import { TRPCError } from "@trpc/server"; import { z } from "zod"; import { findUniqueOrThrow } from "../db/helpers.js"; import { adminProcedure } from "../trpc.js"; import { asHolidayCalendarDb, type HolidayReadContext } from "./holiday-calendar-shared.js"; import { holidayCalendarDetailInclude, holidayCalendarListInclude, } from "./holiday-calendar-support.js"; const HolidayCalendarCatalogInputSchema = z.object({ includeInactive: z.boolean().optional(), countryCode: z.string().trim().min(1).optional(), scopeType: z.enum(["COUNTRY", "STATE", "CITY"]).optional(), stateCode: z.string().trim().min(1).optional(), metroCity: z.string().trim().min(1).optional(), }).optional(); function formatIsoDate(value: Date): string { return value.toISOString().slice(0, 10); } function formatHolidayCalendarEntryDetail(entry: { id: string; date: Date; name: string; isRecurringAnnual?: boolean | null; source?: string | null; }) { return { id: entry.id, date: formatIsoDate(entry.date), name: entry.name, isRecurringAnnual: entry.isRecurringAnnual ?? false, source: entry.source ?? null, }; } function formatHolidayCalendarDetail(calendar: { id: string; name: string; scopeType: string; stateCode?: string | null; isActive?: boolean | null; priority?: number | null; country?: { id: string; code: string; name: string } | null; metroCity?: { id: string; name: string } | null; _count?: { entries?: number | null } | null; entries?: Array<{ id: string; date: Date; name: string; isRecurringAnnual?: boolean | null; source?: string | null; }> | null; }) { const entries = calendar.entries?.map(formatHolidayCalendarEntryDetail) ?? []; return { id: calendar.id, name: calendar.name, scopeType: calendar.scopeType, stateCode: calendar.stateCode ?? null, isActive: calendar.isActive ?? true, priority: calendar.priority ?? 0, country: calendar.country ? { id: calendar.country.id, code: calendar.country.code, name: calendar.country.name, } : null, metroCity: calendar.metroCity ? { id: calendar.metroCity.id, name: calendar.metroCity.name, } : null, entryCount: calendar._count?.entries ?? entries.length, entries, }; } async function readCalendarsSnapshot( ctx: HolidayReadContext, input?: z.infer, ) { const db = asHolidayCalendarDb(ctx.db); const where = { ...(input?.includeInactive ? {} : { isActive: true }), ...(input?.countryCode ? { country: { code: { equals: input.countryCode.trim().toUpperCase(), mode: "insensitive" as const } }, } : {}), ...(input?.scopeType ? { scopeType: input.scopeType } : {}), ...(input?.stateCode ? { stateCode: input.stateCode.trim().toUpperCase() } : {}), ...(input?.metroCity ? { metroCity: { name: { contains: input.metroCity.trim(), mode: "insensitive" as const } }, } : {}), }; return db.holidayCalendar.findMany({ where, include: holidayCalendarListInclude, orderBy: [ { country: { name: "asc" } }, { scopeType: "asc" }, { priority: "desc" }, { name: "asc" }, ], }); } async function readCalendarByIdentifierSnapshot(ctx: HolidayReadContext, identifier: string) { const db = asHolidayCalendarDb(ctx.db); const trimmedIdentifier = identifier.trim(); let calendar = await db.holidayCalendar.findUnique({ where: { id: trimmedIdentifier }, include: holidayCalendarDetailInclude, }); if (!calendar) { calendar = await db.holidayCalendar.findFirst({ where: { name: { equals: trimmedIdentifier, mode: "insensitive" } }, include: holidayCalendarDetailInclude, }); } if (!calendar) { calendar = await db.holidayCalendar.findFirst({ where: { name: { contains: trimmedIdentifier, mode: "insensitive" } }, include: holidayCalendarDetailInclude, }); } if (!calendar) { throw new TRPCError({ code: "NOT_FOUND", message: `Holiday calendar not found: ${trimmedIdentifier}` }); } return calendar; } export const holidayCalendarCatalogReadProcedures = { listCalendars: adminProcedure .input(HolidayCalendarCatalogInputSchema) .query(async ({ ctx, input }) => readCalendarsSnapshot(ctx, input)), listCalendarsDetail: adminProcedure .input(HolidayCalendarCatalogInputSchema) .query(async ({ ctx, input }) => { const calendars = await readCalendarsSnapshot(ctx, input); return { count: calendars.length, calendars: calendars.map(formatHolidayCalendarDetail), }; }), getCalendarByIdentifier: adminProcedure .input(z.object({ identifier: z.string().trim().min(1) })) .query(async ({ ctx, input }) => readCalendarByIdentifierSnapshot(ctx, input.identifier)), getCalendarByIdentifierDetail: adminProcedure .input(z.object({ identifier: z.string().trim().min(1) })) .query(async ({ ctx, input }) => { const calendar = await readCalendarByIdentifierSnapshot(ctx, input.identifier); return formatHolidayCalendarDetail(calendar); }), getCalendarById: adminProcedure .input(z.object({ id: z.string() })) .query(async ({ ctx, input }) => { const db = asHolidayCalendarDb(ctx.db); return findUniqueOrThrow( db.holidayCalendar.findUnique({ where: { id: input.id }, include: holidayCalendarDetailInclude, }), "Holiday calendar", ); }), };