Files
pn-new-crm/src/lib/validators/interests.ts

117 lines
5.3 KiB
TypeScript
Raw Normal View History

import { z } from 'zod';
import { baseListQuerySchema } from '@/lib/api/route-helpers';
import { PIPELINE_STAGES, LEAD_CATEGORIES } from '@/lib/constants';
// ─── Create ──────────────────────────────────────────────────────────────────
export const createInterestSchema = z.object({
clientId: z.string().min(1),
berthId: z.string().optional(),
pipelineStage: z.enum(PIPELINE_STAGES).default('open'),
leadCategory: z.enum(LEAD_CATEGORIES).optional(),
source: z.string().optional(),
notes: z.string().optional(),
tagIds: z.array(z.string()).optional().default([]),
reminderEnabled: z.boolean().optional().default(false),
reminderDays: z.number().int().min(1).optional(),
});
// ─── Update ──────────────────────────────────────────────────────────────────
export const updateInterestSchema = createInterestSchema
.omit({ clientId: true, tagIds: true })
.partial();
// ─── Change Stage ─────────────────────────────────────────────────────────────
export const changeStageSchema = z.object({
pipelineStage: z.enum(PIPELINE_STAGES),
reason: z.string().optional(),
});
// ─── List ─────────────────────────────────────────────────────────────────────
export const listInterestsSchema = baseListQuerySchema.extend({
clientId: z.string().optional(),
berthId: z.string().optional(),
pipelineStage: z
.string()
.transform((v) => v.split(',').filter(Boolean))
.optional(),
leadCategory: z.enum(LEAD_CATEGORIES).optional(),
eoiStatus: z.string().optional(),
tagIds: z
.string()
.transform((v) => v.split(',').filter(Boolean))
.optional(),
});
// ─── Waiting List ─────────────────────────────────────────────────────────────
export const waitingListAddSchema = z.object({
clientId: z.string().min(1),
priority: z.enum(['normal', 'high']).default('normal'),
notifyPref: z.enum(['email', 'in_app', 'both']).default('email'),
notes: z.string().optional(),
});
// ─── Generate Recommendations ─────────────────────────────────────────────────
export const generateRecommendationsSchema = z.object({
interestId: z.string().min(1),
});
// ─── Public Interest ──────────────────────────────────────────────────────────
const addressSchema = z.object({
street: z.string().max(500).optional(),
city: z.string().max(200).optional(),
stateProvince: z.string().max(200).optional(),
postalCode: z.string().max(50).optional(),
country: z.string().max(100).optional(),
});
export const publicInterestSchema = z
.object({
// New: first/last split
firstName: z.string().min(1).max(100).optional(),
lastName: z.string().min(1).max(100).optional(),
// Backward compat
fullName: z.string().min(1).max(200).optional(),
email: z.string().email(),
phone: z.string().min(1),
preferredContactMethod: z.enum(['email', 'phone', 'sms']).optional(),
mooringNumber: z.string().max(50).optional(),
companyName: z.string().optional(),
yachtName: z.string().optional(),
yachtLengthFt: z.coerce.number().positive().optional(),
yachtWidthFt: z.coerce.number().positive().optional(),
yachtDraftFt: z.coerce.number().positive().optional(),
preferredBerthSize: z.string().optional(),
source: z.literal('website').default('website'),
notes: z.string().max(2000).optional(),
address: addressSchema.optional(),
})
.refine((data) => data.fullName || (data.firstName && data.lastName), {
message: 'Either fullName or both firstName and lastName are required',
path: ['fullName'],
});
// ─── Reorder Waiting List ─────────────────────────────────────────────────────
export const reorderWaitingListSchema = z.object({
entryId: z.string().min(1),
newPosition: z.coerce.number().int().min(1),
});
// ─── Types ────────────────────────────────────────────────────────────────────
export type CreateInterestInput = z.infer<typeof createInterestSchema>;
export type UpdateInterestInput = z.infer<typeof updateInterestSchema>;
export type ChangeStageInput = z.infer<typeof changeStageSchema>;
export type ListInterestsInput = z.infer<typeof listInterestsSchema>;
export type WaitingListAddInput = z.infer<typeof waitingListAddSchema>;
export type PublicInterestInput = z.infer<typeof publicInterestSchema>;
export type ReorderWaitingListInput = z.infer<typeof reorderWaitingListSchema>;