import { z } from 'zod'; import { baseListQuerySchema } from '@/lib/api/route-helpers'; import { optionalCountryIsoSchema, optionalIanaTimezoneSchema, optionalPhoneE164Schema, optionalSubdivisionIsoSchema, } from '@/lib/validators/i18n'; // ─── Residential client ────────────────────────────────────────────────────── export const createResidentialClientSchema = z.object({ fullName: z.string().min(1).max(200), email: z .string() .email() .optional() .or(z.literal('').transform(() => undefined)), phone: z.string().optional(), /** E.164-normalized phone alongside the legacy free-text `phone`. */ phoneE164: optionalPhoneE164Schema.optional(), /** ISO-3166-1 alpha-2 the phone was parsed against. */ phoneCountry: optionalCountryIsoSchema.optional(), /** ISO-3166-1 alpha-2 nationality. */ nationalityIso: optionalCountryIsoSchema.optional(), /** IANA timezone. */ timezone: optionalIanaTimezoneSchema.optional(), placeOfResidence: z.string().optional(), /** ISO-3166-1 alpha-2 country of residence. */ placeOfResidenceCountryIso: optionalCountryIsoSchema.optional(), /** ISO 3166-2 subdivision code for place of residence. */ subdivisionIso: optionalSubdivisionIsoSchema.optional(), preferredContactMethod: z.enum(['email', 'phone']).optional(), status: z.enum(['prospect', 'active', 'inactive']).optional().default('prospect'), source: z.enum(['website', 'manual', 'referral', 'broker']).optional(), notes: z.string().optional(), }); export const updateResidentialClientSchema = createResidentialClientSchema.partial(); export const listResidentialClientsSchema = baseListQuerySchema.extend({ status: z.enum(['prospect', 'active', 'inactive']).optional(), source: z.enum(['website', 'manual', 'referral', 'broker']).optional(), }); // ─── Residential interest ──────────────────────────────────────────────────── export const PIPELINE_STAGES = [ 'new', 'contacted', 'viewing_scheduled', 'offer_made', 'offer_accepted', 'closed_won', 'closed_lost', ] as const; export const createResidentialInterestSchema = z.object({ residentialClientId: z.string().min(1), pipelineStage: z.enum(PIPELINE_STAGES).optional().default('new'), source: z.enum(['website', 'manual', 'referral', 'broker']).optional(), notes: z.string().optional(), preferences: z.string().optional(), assignedTo: z.string().optional(), }); export const updateResidentialInterestSchema = createResidentialInterestSchema .omit({ residentialClientId: true }) .partial(); export const listResidentialInterestsSchema = baseListQuerySchema.extend({ pipelineStage: z.enum(PIPELINE_STAGES).optional(), assignedTo: z.string().optional(), residentialClientId: z.string().optional(), }); // ─── Public website inquiry ────────────────────────────────────────────────── /** * Shape posted by the public website's residential interest form. Coerces * to internal create-shapes inside the public route. * * The legacy `phone` field stays free-text - older website builds may post * raw international strings ('+44 7700 900123'). The route handler parses * it server-side into `phoneE164` + `phoneCountry`. Newer website builds * can post normalized values directly. */ export const publicResidentialInquirySchema = z.object({ firstName: z.string().min(1), lastName: z.string().min(1), email: z.string().email(), phone: z.string().min(1), /** Pre-normalized E.164 form, optional for backwards compat. */ phoneE164: optionalPhoneE164Schema.optional(), /** ISO-3166-1 alpha-2 the phone was parsed against. */ phoneCountry: optionalCountryIsoSchema.optional(), /** ISO-3166-1 alpha-2 nationality. */ nationalityIso: optionalCountryIsoSchema.optional(), /** IANA timezone. */ timezone: optionalIanaTimezoneSchema.optional(), placeOfResidence: z.string().optional(), /** ISO-3166-1 alpha-2 country of residence. */ placeOfResidenceCountryIso: optionalCountryIsoSchema.optional(), /** ISO 3166-2 subdivision code for place of residence. */ subdivisionIso: optionalSubdivisionIsoSchema.optional(), preferredContactMethod: z.enum(['email', 'phone']).optional(), notes: z.string().optional(), preferences: z.string().optional(), }); // ─── Types ──────────────────────────────────────────────────────────────────── export type CreateResidentialClientInput = z.infer; export type UpdateResidentialClientInput = z.infer; export type ListResidentialClientsInput = z.infer; export type CreateResidentialInterestInput = z.infer; export type UpdateResidentialInterestInput = z.infer; export type ListResidentialInterestsInput = z.infer; export type PublicResidentialInquiryInput = z.infer;