Files
blackheart-website/src/app/api/admin/mc-registrations/route.ts
diana.dolgolyova 66dce3f8f5 fix: HIGH priority — scroll debounce, timing-safe auth, a11y, error logging, cleanup dead modals
- Header: throttle scroll handler via requestAnimationFrame (was firing 60+/sec)
- Auth: use crypto.timingSafeEqual for password and token signature comparison
- A11y: add role="dialog", aria-modal, aria-label to all modals (SignupModal, NewsModal, TeamProfile lightbox)
- A11y: add aria-label to close buttons, menu toggle (with aria-expanded), floating CTA
- A11y: add aria-label to MC Instagram buttons
- Error logging: add console.error with route names to all API catch blocks (admin + public)
- Fix open-day-register error leak (was returning raw DB error to client)
- Fix MasterClasses key={index} → key={item.title}
- Delete 3 unused modal components (BookingModal, MasterClassSignupModal, OpenDaySignupModal) — replaced by unified SignupModal

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 14:01:21 +03:00

70 lines
2.7 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { getMcRegistrations, getAllMcRegistrations, addMcRegistration, updateMcRegistration, toggleMcNotification, deleteMcRegistration } from "@/lib/db";
export async function GET(request: NextRequest) {
const title = request.nextUrl.searchParams.get("title");
if (title) {
return NextResponse.json(getMcRegistrations(title));
}
// No title = return all registrations
return NextResponse.json(getAllMcRegistrations());
}
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { masterClassTitle, name, instagram, telegram } = body;
if (!masterClassTitle || !name || !instagram) {
return NextResponse.json({ error: "masterClassTitle, name, instagram are required" }, { status: 400 });
}
const id = addMcRegistration(masterClassTitle.trim(), name.trim(), instagram.trim(), telegram?.trim() || undefined);
return NextResponse.json({ ok: true, id });
} catch (err) {
console.error("[admin/mc-registrations] error:", err);
return NextResponse.json({ error: "Internal error" }, { status: 500 });
}
}
export async function PUT(request: NextRequest) {
try {
const body = await request.json();
// Toggle notification status
if (body.action === "toggle-notify") {
const { id, field, value } = body;
if (!id || !field || typeof value !== "boolean") {
return NextResponse.json({ error: "id, field, value are required" }, { status: 400 });
}
if (field !== "notified_confirm" && field !== "notified_reminder") {
return NextResponse.json({ error: "Invalid field" }, { status: 400 });
}
toggleMcNotification(id, field, value);
return NextResponse.json({ ok: true });
}
// Regular update
const { id, name, instagram, telegram } = body;
if (!id || !name || !instagram) {
return NextResponse.json({ error: "id, name, instagram are required" }, { status: 400 });
}
updateMcRegistration(id, name.trim(), instagram.trim(), telegram?.trim() || undefined);
return NextResponse.json({ ok: true });
} catch (err) {
console.error("[admin/mc-registrations] error:", err);
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 parameter is required" }, { status: 400 });
}
const id = parseInt(idStr, 10);
if (isNaN(id)) {
return NextResponse.json({ error: "Invalid id" }, { status: 400 });
}
deleteMcRegistration(id);
return NextResponse.json({ ok: true });
}