feat: add status workflow to MC and Open Day bookings, refactor into separate files

- DB migration v12: add status column to mc_registrations and open_day_bookings
- MC and Open Day tabs now have full status workflow (new → contacted → confirmed/declined)
- Filter tabs with counts, status badges, action buttons matching group bookings
- Extract shared components (_shared.tsx): FilterTabs, StatusBadge, StatusActions, BookingCard, ContactLinks
- Split monolith into _McRegistrationsTab.tsx, _OpenDayBookingsTab.tsx, _shared.tsx

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-23 19:05:44 +03:00
parent 575c684cc5
commit b906216317
7 changed files with 501 additions and 294 deletions

View File

@@ -229,6 +229,19 @@ const migrations: Migration[] = [
}
},
},
{
version: 12,
name: "add_status_to_mc_and_openday",
up: (db) => {
for (const table of ["mc_registrations", "open_day_bookings"]) {
const cols = db.prepare(`PRAGMA table_info(${table})`).all() as { name: string }[];
const colNames = new Set(cols.map((c) => c.name));
if (!colNames.has("status")) {
db.exec(`ALTER TABLE ${table} ADD COLUMN status TEXT NOT NULL DEFAULT 'new'`);
}
}
},
},
];
function runMigrations(db: Database.Database) {
@@ -510,6 +523,7 @@ interface McRegistrationRow {
notified_confirm: number;
notified_reminder: number;
reminder_status: string | null;
status: string;
}
export interface McRegistration {
@@ -523,6 +537,7 @@ export interface McRegistration {
notifiedConfirm: boolean;
notifiedReminder: boolean;
reminderStatus?: string;
status: string;
}
export function addMcRegistration(
@@ -572,9 +587,15 @@ function mapMcRow(r: McRegistrationRow): McRegistration {
notifiedConfirm: !!r.notified_confirm,
notifiedReminder: !!r.notified_reminder,
reminderStatus: r.reminder_status ?? undefined,
status: r.status || "new",
};
}
export function setMcRegistrationStatus(id: number, status: string): void {
const db = getDb();
db.prepare("UPDATE mc_registrations SET status = ? WHERE id = ?").run(status, id);
}
export function updateMcRegistration(
id: number,
name: string,
@@ -928,6 +949,7 @@ interface OpenDayBookingRow {
notified_confirm: number;
notified_reminder: number;
reminder_status: string | null;
status: string;
created_at: string;
class_style?: string;
class_trainer?: string;
@@ -946,6 +968,7 @@ export interface OpenDayBooking {
notifiedConfirm: boolean;
notifiedReminder: boolean;
reminderStatus?: string;
status: string;
createdAt: string;
classStyle?: string;
classTrainer?: string;
@@ -982,6 +1005,11 @@ function mapClassRow(r: OpenDayClassRow): OpenDayClass {
};
}
export function setOpenDayBookingStatus(id: number, status: string): void {
const db = getDb();
db.prepare("UPDATE open_day_bookings SET status = ? WHERE id = ?").run(status, id);
}
function mapBookingRow(r: OpenDayBookingRow): OpenDayBooking {
return {
id: r.id,
@@ -994,6 +1022,7 @@ function mapBookingRow(r: OpenDayBookingRow): OpenDayBooking {
notifiedConfirm: !!r.notified_confirm,
notifiedReminder: !!r.notified_reminder,
reminderStatus: r.reminder_status ?? undefined,
status: r.status || "new",
createdAt: r.created_at,
classStyle: r.class_style ?? undefined,
classTrainer: r.class_trainer ?? undefined,