import { z } from "zod"; import { AllocationType, OrderType, ProjectStatus } from "../types/enums.js"; export const StaffingRequirementSchema = z.object({ id: z.string().uuid().default(() => crypto.randomUUID()), role: z.string().min(1).max(200), requiredSkills: z.array(z.string()), preferredSkills: z.array(z.string()).optional(), hoursPerDay: z.number().min(0).max(24), headcount: z.number().int().min(1), startDate: z.string().optional(), endDate: z.string().optional(), notes: z.string().optional(), chapter: z.string().optional(), }); // Base object schema — used for .partial() in UpdateProjectSchema export const CreateProjectBaseSchema = z.object({ shortCode: z.string().min(1).max(20).regex(/^[A-Z0-9_-]+$/, "Must be uppercase alphanumeric"), name: z.string().min(1).max(500), orderType: z.nativeEnum(OrderType), allocationType: z.nativeEnum(AllocationType), winProbability: z.number().int().min(0).max(100).default(100), budgetCents: z.number().int().min(0), startDate: z.coerce.date(), endDate: z.coerce.date(), staffingReqs: z.array(StaffingRequirementSchema).default([]), dynamicFields: z.record(z.string(), z.unknown()).default({}), blueprintId: z.string().optional(), status: z.nativeEnum(ProjectStatus).default(ProjectStatus.DRAFT), responsiblePerson: z.string().max(200).optional(), color: z.string().regex(/^#[0-9a-fA-F]{6}$/, "Must be a hex color like #3b82f6").optional(), utilizationCategoryId: z.string().optional(), clientId: z.string().optional(), coverImageUrl: z.string().optional(), }); // Full schema with date-range validation export const CreateProjectSchema = CreateProjectBaseSchema.refine( (data) => data.endDate >= data.startDate, { message: "End date must be after start date", path: ["endDate"] }, ); export const UpdateProjectSchema = CreateProjectBaseSchema.partial(); export type CreateProjectInput = z.infer; export type UpdateProjectInput = z.infer;