import { z } from "zod"; import { NextResponse } from "next/server"; export const TASK_STATUSES = ["PENDING", "DONE", "IN_PROGRESS", "CANCELLED"] as const; export const REPORT_STATUSES = ["IN_PROGRESS", "COMPLETED", "SUBMITTED"] as const; const httpLink = z .string() .trim() .max(2000) .refine((v) => v === "" || /^https?:\/\//i.test(v), { message: "Link must start with http:// or https://", }); export const createReportSchema = z.object({ managerName: z.string().trim().min(1).max(200), date: z .string() .regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be YYYY-MM-DD") .optional(), }); export const updateReportSchema = z.object({ managerName: z.string().trim().min(1).max(200).optional(), status: z.enum(REPORT_STATUSES).optional(), }); export const createTaskSchema = z.object({ reportId: z.string().min(1), type: z.enum(["PLANNED", "COMPLETED"]), description: z.string().max(2000).default(""), timeEstimate: z.string().max(100).nullish(), notes: z.string().max(2000).nullish(), link: httpLink.nullish(), status: z.enum(TASK_STATUSES).nullish(), }); export const updateTaskSchema = z.object({ id: z.string().min(1), type: z.enum(["PLANNED", "COMPLETED"]).optional(), description: z.string().max(2000).optional(), timeEstimate: z.string().max(100).nullish(), notes: z.string().max(2000).nullish(), link: httpLink.nullish(), status: z.enum(TASK_STATUSES).nullish(), }); export const updateSettingSchema = z.object({ key: z.enum(["GOOGLE_DRIVE_FOLDER_ID"]), value: z.string().trim().max(500), }); export const updateUserRoleSchema = z.object({ userId: z.string().min(1), role: z.enum(["EMPLOYEE", "ADMIN"]), }); /** * Parse and validate a request body. Returns the parsed data, or a * NextResponse 400 that the route should return immediately. */ export async function parseBody( req: Request, schema: T ): Promise<{ data: z.infer; error: null } | { data: null; error: NextResponse }> { let json: unknown; try { json = await req.json(); } catch { return { data: null, error: NextResponse.json({ error: "Invalid JSON body" }, { status: 400 }), }; } const result = schema.safeParse(json); if (!result.success) { return { data: null, error: NextResponse.json( { error: "Validation failed", details: result.error.flatten().fieldErrors }, { status: 400 } ), }; } return { data: result.data, error: null }; }