import { z } from "zod"; // "YYYY-MM-DD" -- exactly what an gives back, so the // client never needs to reformat before sending it. Lexicographic string // comparison is a valid chronological comparison for this shape. const DateStringSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Invalid date"); export const SummaryDateRangeSchema = z.enum([ "today", "thisWeek", "thisMonth", "lastMonth", "custom", ]); export const SummaryOrganizeBySchema = z.enum(["byDate", "byCategory"]); export const SummaryRequestSchema = z .object({ dateRange: SummaryDateRangeSchema, // Only read when dateRange is "custom" -- enforced conditionally below. customStart: DateStringSchema.optional(), customEnd: DateStringSchema.optional(), organizeBy: SummaryOrganizeBySchema, }) .superRefine((value, ctx) => { if (value.dateRange !== "custom") return; if (!value.customStart) { ctx.addIssue({ code: "custom", path: ["customStart"], message: "A start date is required." }); } if (!value.customEnd) { ctx.addIssue({ code: "custom", path: ["customEnd"], message: "An end date is required." }); } if (value.customStart && value.customEnd && value.customStart > value.customEnd) { ctx.addIssue({ code: "custom", path: ["customStart"], message: "The start date must be on or before the end date.", }); } }); export type SummaryRequest = z.infer;