fix: MEDIUM priority — shared validation, content caching, Schedule useReducer, stable keys
- Extract shared sanitization to src/lib/validation.ts, apply to all 3 registration routes (#2) - Replace key={index} with stable keys in About and News (#4) - Add 5-min in-memory content cache in content.ts, invalidate on admin section save (#6) - Refactor Schedule from 8 useState calls to useReducer — single dispatch, fewer re-renders (#8) - Remove Hero scroll indicator, add auto-scroll to next section on wheel/swipe Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
getOpenDayEvent,
|
||||
} from "@/lib/db";
|
||||
import { checkRateLimit, getClientIp } from "@/lib/rateLimit";
|
||||
import { sanitizeName, sanitizePhone, sanitizeHandle } from "@/lib/validation";
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const ip = getClientIp(request);
|
||||
@@ -20,17 +21,18 @@ export async function POST(request: NextRequest) {
|
||||
const body = await request.json();
|
||||
const { classId, eventId, name, phone, instagram, telegram } = body;
|
||||
|
||||
if (!classId || !eventId || !name || !phone) {
|
||||
return NextResponse.json({ error: "classId, eventId, name, phone are required" }, { status: 400 });
|
||||
if (!classId || !eventId) {
|
||||
return NextResponse.json({ error: "classId and eventId are required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const cleanName = (name as string).trim().slice(0, 100);
|
||||
const cleanPhone = (phone as string).replace(/\D/g, "").slice(0, 15);
|
||||
const cleanIg = instagram ? (instagram as string).trim().slice(0, 100) : undefined;
|
||||
const cleanTg = telegram ? (telegram as string).trim().slice(0, 100) : undefined;
|
||||
const cleanName = sanitizeName(name);
|
||||
if (!cleanName) {
|
||||
return NextResponse.json({ error: "Имя обязательно" }, { status: 400 });
|
||||
}
|
||||
|
||||
const cleanPhone = sanitizePhone(phone);
|
||||
if (!cleanPhone) {
|
||||
return NextResponse.json({ error: "Invalid phone" }, { status: 400 });
|
||||
return NextResponse.json({ error: "Телефон обязателен" }, { status: 400 });
|
||||
}
|
||||
|
||||
// Check not already booked
|
||||
@@ -41,8 +43,8 @@ export async function POST(request: NextRequest) {
|
||||
const id = addOpenDayBooking(classId, eventId, {
|
||||
name: cleanName,
|
||||
phone: cleanPhone,
|
||||
instagram: cleanIg,
|
||||
telegram: cleanTg,
|
||||
instagram: sanitizeHandle(instagram),
|
||||
telegram: sanitizeHandle(telegram),
|
||||
});
|
||||
|
||||
// Return total bookings for this person (for discount calculation)
|
||||
|
||||
Reference in New Issue
Block a user