feat: booking confirm modal with cascading Hall → Trainer → Group, linear workflow

- Add confirmed_date, confirmed_group, confirmed_comment to group_bookings (migration #10)
- Linear booking flow: Новая → Связались → Подтвердить (modal) / Отказ
- Confirm modal with cascading selects: Hall → Trainer → Group → Date → Comment
- Groups merged by groupId — shows all days/times (e.g. "СР 20:00, ПТ 16:15")
- Auto-prefill hall/trainer/group from booking's groupInfo via fuzzy scoring
- Proper SHORT_DAYS constant for weekday abbreviations
- Filter chips with status counts, declined sorted to bottom
- "Вернуть" on confirmed/declined returns to "Связались" (not "Новая")

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-20 01:03:20 +03:00
parent 8d1e3fb596
commit 1bfd502930
3 changed files with 282 additions and 26 deletions

View File

@@ -211,6 +211,12 @@ const migrations: Migration[] = [
if (!cols.some((c) => c.name === "confirmed_date")) {
db.exec("ALTER TABLE group_bookings ADD COLUMN confirmed_date TEXT");
}
if (!cols.some((c) => c.name === "confirmed_group")) {
db.exec("ALTER TABLE group_bookings ADD COLUMN confirmed_group TEXT");
}
if (!cols.some((c) => c.name === "confirmed_comment")) {
db.exec("ALTER TABLE group_bookings ADD COLUMN confirmed_comment TEXT");
}
},
},
];
@@ -596,6 +602,8 @@ interface GroupBookingRow {
reminder_status: string | null;
status: string;
confirmed_date: string | null;
confirmed_group: string | null;
confirmed_comment: string | null;
created_at: string;
}
@@ -613,6 +621,8 @@ export interface GroupBooking {
reminderStatus?: string;
status: BookingStatus;
confirmedDate?: string;
confirmedGroup?: string;
confirmedComment?: string;
createdAt: string;
}
@@ -649,16 +659,26 @@ export function getGroupBookings(): GroupBooking[] {
reminderStatus: r.reminder_status ?? undefined,
status: (r.status || "new") as BookingStatus,
confirmedDate: r.confirmed_date ?? undefined,
confirmedGroup: r.confirmed_group ?? undefined,
confirmedComment: r.confirmed_comment ?? undefined,
createdAt: r.created_at,
}));
}
export function setGroupBookingStatus(id: number, status: BookingStatus, confirmedDate?: string): void {
export function setGroupBookingStatus(
id: number,
status: BookingStatus,
confirmation?: { date: string; group: string; comment?: string }
): void {
const db = getDb();
if (status === "confirmed" && confirmedDate) {
db.prepare("UPDATE group_bookings SET status = ?, confirmed_date = ? WHERE id = ?").run(status, confirmedDate, id);
if (status === "confirmed" && confirmation) {
db.prepare(
"UPDATE group_bookings SET status = ?, confirmed_date = ?, confirmed_group = ?, confirmed_comment = ? WHERE id = ?"
).run(status, confirmation.date, confirmation.group, confirmation.comment || null, id);
} else {
db.prepare("UPDATE group_bookings SET status = ?, confirmed_date = NULL WHERE id = ?").run(status, id);
db.prepare(
"UPDATE group_bookings SET status = ?, confirmed_date = NULL, confirmed_group = NULL, confirmed_comment = NULL WHERE id = ?"
).run(status, id);
}
}