import { z } from 'zod'; import { baseListQuerySchema } from '@/lib/api/list-query'; export const TENANCY_STATUSES = ['pending', 'active', 'ended', 'cancelled'] as const; export const TENURE_TYPES = ['permanent', 'fixed_term', 'seasonal'] as const; export const createPendingSchema = z.object({ berthId: z.string().min(1), clientId: z.string().min(1), yachtId: z.string().min(1), interestId: z.string().optional(), startDate: z.coerce.date(), tenureType: z.enum(TENURE_TYPES).optional().default('permanent'), notes: z.string().optional(), }); export const activateSchema = z.object({ contractFileId: z.string().optional(), effectiveDate: z.coerce.date().optional(), }); export const endTenancySchema = z.object({ endDate: z.coerce.date(), notes: z.string().optional(), }); export const cancelSchema = z.object({ reason: z.string().optional(), }); /** PATCH body for the "edit metadata" idiom — touches notes / dates / * tenure type without crossing a status boundary. Status transitions * flow through activate / endTenancy / cancel; this is non-transition * metadata only. */ export const updateTenancySchema = z .object({ startDate: z.coerce.date().optional(), endDate: z.coerce.date().nullable().optional(), tenureType: z.enum(TENURE_TYPES).optional(), notes: z.string().nullable().optional(), }) .refine((d) => Object.keys(d).length > 0, { message: 'At least one field must be provided' }); export type UpdateTenancyInput = z.infer; /** Renewal input. For permanent-class tenancies the existing row is * mutated in place; for fixed_term / seasonal the existing row is * ended at `previousEndDate` and a fresh row is minted with * previousTenancyId pointing back. */ export const renewTenancySchema = z.object({ /** New start date for the renewal window (or the mutated row when permanent). */ newStartDate: z.coerce.date(), /** New end date — required for fixed_term / seasonal; optional when permanent. */ newEndDate: z.coerce.date().optional(), /** Optional notes appended to the successor / mutated row. */ notes: z.string().optional(), }); export type RenewTenancyInput = z.infer; /** Transfer input — hand a berth's active tenancy to a new client/yacht * pair. The current row is ended, a fresh active row is minted with * transferredFromTenancyId pointing at the predecessor. */ export const transferTenancySchema = z.object({ newClientId: z.string().min(1), newYachtId: z.string().min(1), transferDate: z.coerce.date(), notes: z.string().optional(), }); export type TransferTenancyInput = z.infer; export const listTenanciesSchema = baseListQuerySchema.extend({ status: z.enum(TENANCY_STATUSES).optional(), berthId: z.string().optional(), clientId: z.string().optional(), yachtId: z.string().optional(), }); export type CreatePendingInput = z.infer; export type ActivateInput = z.infer; export type EndTenancyInput = z.infer; export type CancelInput = z.infer; export type ListTenanciesInput = z.infer;