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:
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user