feat: add booking management, Open Day, unified signup modal
- MC registrations: notification toggles (confirm/remind) with urgency - Group bookings: save to DB from BookingModal, admin CRUD at /admin/bookings - Open Day: full event system with schedule grid (halls × time), per-class booking, discount pricing (30 BYN / 20 BYN from 3+), auto-cancel threshold - Unified SignupModal replaces 3 separate forms — consistent fields (name, phone, instagram, telegram), Instagram DM fallback on network error - Centralized /admin/bookings page with 3 tabs (classes, MC, Open Day), collapsible sections, notification toggles, filter chips - Unread booking badge on sidebar + dashboard widget with per-type breakdown - Pricing: contact hint (Instagram/Telegram/phone) on price & rental tabs, admin toggle to show/hide - DB migrations 5-7: group_bookings table, open_day tables, unified fields Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
43
src/app/api/admin/open-day/bookings/route.ts
Normal file
43
src/app/api/admin/open-day/bookings/route.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import {
|
||||
getOpenDayBookings,
|
||||
toggleOpenDayNotification,
|
||||
deleteOpenDayBooking,
|
||||
} from "@/lib/db";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const eventIdStr = request.nextUrl.searchParams.get("eventId");
|
||||
if (!eventIdStr) return NextResponse.json({ error: "eventId is required" }, { status: 400 });
|
||||
const eventId = parseInt(eventIdStr, 10);
|
||||
if (isNaN(eventId)) return NextResponse.json({ error: "Invalid eventId" }, { status: 400 });
|
||||
return NextResponse.json(getOpenDayBookings(eventId));
|
||||
}
|
||||
|
||||
export async function PUT(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
if (body.action === "toggle-notify") {
|
||||
const { id, field, value } = body;
|
||||
if (!id || !field || typeof value !== "boolean") {
|
||||
return NextResponse.json({ error: "id, field, value required" }, { status: 400 });
|
||||
}
|
||||
if (field !== "notified_confirm" && field !== "notified_reminder") {
|
||||
return NextResponse.json({ error: "Invalid field" }, { status: 400 });
|
||||
}
|
||||
toggleOpenDayNotification(id, field, value);
|
||||
return NextResponse.json({ ok: true });
|
||||
}
|
||||
return NextResponse.json({ error: "Unknown action" }, { status: 400 });
|
||||
} catch {
|
||||
return NextResponse.json({ error: "Internal error" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(request: NextRequest) {
|
||||
const idStr = request.nextUrl.searchParams.get("id");
|
||||
if (!idStr) return NextResponse.json({ error: "id is required" }, { status: 400 });
|
||||
const id = parseInt(idStr, 10);
|
||||
if (isNaN(id)) return NextResponse.json({ error: "Invalid id" }, { status: 400 });
|
||||
deleteOpenDayBooking(id);
|
||||
return NextResponse.json({ ok: true });
|
||||
}
|
||||
Reference in New Issue
Block a user