From 5273f88272e88252a75d4b3727770dd48dc20d38 Mon Sep 17 00:00:00 2001 From: BOHA Date: Fri, 5 Jun 2026 11:47:34 +0200 Subject: [PATCH] feat(plan): zod schemas for plan endpoints --- src/schemas/plan.schema.ts | 97 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/schemas/plan.schema.ts diff --git a/src/schemas/plan.schema.ts b/src/schemas/plan.schema.ts new file mode 100644 index 0000000..f2e4fdd --- /dev/null +++ b/src/schemas/plan.schema.ts @@ -0,0 +1,97 @@ +import { z } from "zod"; + +const isoDate = z + .string() + .regex(/^\d{4}-\d{2}-\d{2}$/, "Datum musí být ve formátu YYYY-MM-DD"); + +const intFromForm = z + .union([z.number(), z.string()]) + .transform((v) => Number(v)) + .refine((n) => Number.isInteger(n) && n > 0, "Neplatné ID"); + +const planCategoryEnum = z.enum([ + "work", + "preparation", + "travel", + "leave", + "sick", + "training", + "other", +]); + +export const CreatePlanEntrySchema = z + .object({ + user_id: intFromForm, + date_from: isoDate, + date_to: isoDate, + project_id: z + .union([z.number(), z.string()]) + .transform((v) => Number(v)) + .nullish(), + category: planCategoryEnum.default("work"), + note: z + .string() + .min(1, "Text poznámky je povinný") + .max(500, "Maximálně 500 znaků"), + }) + .refine((v) => v.date_to >= v.date_from, { + message: "Datum do musí být stejné nebo po datumu od", + path: ["date_to"], + }); + +export const UpdatePlanEntrySchema = z + .object({ + date_from: isoDate.optional(), + date_to: isoDate.optional(), + project_id: z + .union([z.number(), z.string(), z.null()]) + .transform((v) => (v === null ? null : Number(v))) + .nullish(), + category: planCategoryEnum.optional(), + note: z.string().min(1).max(500).optional(), + }) + .refine( + (v) => + v.date_from === undefined || + v.date_to === undefined || + v.date_to >= v.date_from, + { + message: "Datum do musí být stejné nebo po datumu od", + path: ["date_to"], + }, + ); + +export const CreatePlanOverrideSchema = z.object({ + user_id: intFromForm, + shift_date: isoDate, + project_id: z + .union([z.number(), z.string()]) + .transform((v) => Number(v)) + .nullish(), + category: planCategoryEnum, + note: z + .string() + .min(1, "Text poznámky je povinný") + .max(500, "Maximálně 500 znaků"), +}); + +export const UpdatePlanOverrideSchema = z.object({ + project_id: z + .union([z.number(), z.string(), z.null()]) + .transform((v) => (v === null ? null : Number(v))) + .nullish(), + category: planCategoryEnum.optional(), + note: z.string().min(1).max(500).optional(), +}); + +export const PlanRangeQuerySchema = z.object({ + user_id: intFromForm.optional(), + date_from: isoDate, + date_to: isoDate, +}); + +export const PlanGridQuerySchema = z.object({ + date_from: isoDate, + date_to: isoDate, + view: z.enum(["week", "month"]).default("week"), +});