feat: add master classes section with registration system

- New master classes section on landing page with upcoming events grid
- Admin CRUD for master classes (image, slots, trainer, style, cost, location)
- User signup modal (name + Instagram required, Telegram optional)
- Admin registration management: view, add, edit, delete with quick-contact links
- Customizable success message for signup confirmation
- Auto-filter past events, Russian date formatting, duration auto-calculation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-15 18:29:06 +03:00
parent 6981376171
commit 84b0bc4d60
14 changed files with 1573 additions and 3 deletions

View File

@@ -26,6 +26,15 @@ function initTables(db: Database.Database) {
updated_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS mc_registrations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
master_class_title TEXT NOT NULL,
name TEXT NOT NULL,
instagram TEXT NOT NULL,
telegram TEXT,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS team_members (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
@@ -228,6 +237,7 @@ const SECTION_KEYS = [
"hero",
"about",
"classes",
"masterClasses",
"faq",
"pricing",
"schedule",
@@ -257,6 +267,7 @@ export function getSiteContent(): SiteContent | null {
hero: sections.hero,
about: sections.about,
classes: sections.classes,
masterClasses: sections.masterClasses ?? { title: "Мастер-классы", items: [] },
faq: sections.faq,
pricing: sections.pricing,
schedule: sections.schedule,
@@ -276,4 +287,74 @@ export function isDatabaseSeeded(): boolean {
return row.count > 0;
}
// --- MC Registrations ---
interface McRegistrationRow {
id: number;
master_class_title: string;
name: string;
instagram: string;
telegram: string | null;
created_at: string;
}
export interface McRegistration {
id: number;
masterClassTitle: string;
name: string;
instagram: string;
telegram?: string;
createdAt: string;
}
export function addMcRegistration(
masterClassTitle: string,
name: string,
instagram: string,
telegram?: string
): number {
const db = getDb();
const result = db
.prepare(
`INSERT INTO mc_registrations (master_class_title, name, instagram, telegram)
VALUES (?, ?, ?, ?)`
)
.run(masterClassTitle, name, instagram, telegram || null);
return result.lastInsertRowid as number;
}
export function getMcRegistrations(masterClassTitle: string): McRegistration[] {
const db = getDb();
const rows = db
.prepare(
"SELECT * FROM mc_registrations WHERE master_class_title = ? ORDER BY created_at DESC"
)
.all(masterClassTitle) as McRegistrationRow[];
return rows.map((r) => ({
id: r.id,
masterClassTitle: r.master_class_title,
name: r.name,
instagram: r.instagram,
telegram: r.telegram ?? undefined,
createdAt: r.created_at,
}));
}
export function updateMcRegistration(
id: number,
name: string,
instagram: string,
telegram?: string
): void {
const db = getDb();
db.prepare(
"UPDATE mc_registrations SET name = ?, instagram = ?, telegram = ? WHERE id = ?"
).run(name, instagram, telegram || null, id);
}
export function deleteMcRegistration(id: number): void {
const db = getDb();
db.prepare("DELETE FROM mc_registrations WHERE id = ?").run(id);
}
export { SECTION_KEYS };