changemaker.lite/api/src/modules/map/canvass/canvass.schemas.ts

113 lines
4.3 KiB
TypeScript

import { z } from 'zod';
import { VisitOutcome, SupportLevel } from '@prisma/client';
export const recordVisitSchema = z.object({
addressId: z.string().min(1), // Changed from locationId
outcome: z.nativeEnum(VisitOutcome),
supportLevel: z.nativeEnum(SupportLevel).optional(),
signRequested: z.boolean().optional().default(false),
signSize: z.string().optional(),
notes: z.string().optional(),
durationSeconds: z.number().int().optional(),
sessionId: z.string().optional(),
shiftId: z.string().optional(),
updateLocation: z.boolean().optional().default(true),
});
export const bulkRecordVisitSchema = z.object({
locationId: z.string().min(1), // Building ID
outcome: z.enum(['NOT_HOME', 'REFUSED', 'MOVED']), // Only non-contact outcomes
notes: z.string().optional(),
sessionId: z.string().optional(),
shiftId: z.string().optional(),
});
export const startSessionSchema = z.object({
cutId: z.string().min(1),
shiftId: z.string().optional(),
startLatitude: z.number().optional(),
startLongitude: z.number().optional(),
});
export const endSessionSchema = z.object({
// no body required — session id from URL
});
export const walkingRouteSchema = z.object({
excludeVisited: z.coerce.boolean().optional().default(false),
startLatitude: z.coerce.number().optional(),
startLongitude: z.coerce.number().optional(),
});
export const listMyVisitsSchema = z.object({
page: z.coerce.number().int().positive().default(1),
limit: z.coerce.number().int().positive().max(100).default(20),
});
export const adminActivitySchema = z.object({
page: z.coerce.number().int().positive().default(1),
limit: z.coerce.number().int().positive().max(100).default(20),
cutId: z.string().optional(),
userId: z.string().optional(),
outcome: z.nativeEnum(VisitOutcome).optional(),
});
export const adminVisitsSchema = z.object({
page: z.coerce.number().int().positive().default(1),
limit: z.coerce.number().int().positive().max(100).default(50),
cutId: z.string().optional(),
userId: z.string().optional(),
shiftId: z.string().optional(),
outcome: z.nativeEnum(VisitOutcome).optional(),
sortBy: z.enum(['visitedAt', 'outcome']).optional().default('visitedAt'),
sortOrder: z.enum(['asc', 'desc']).optional().default('desc'),
});
export const volunteerUpdateLocationSchema = z.object({
supportLevel: z.nativeEnum(SupportLevel).nullable().optional(),
sign: z.boolean().optional(),
signSize: z.string().nullable().optional(),
notes: z.string().nullable().optional(),
// Admin-only fields (stripped by service for non-admins)
firstName: z.string().nullable().optional(),
lastName: z.string().nullable().optional(),
address: z.string().nullable().optional(),
unitNumber: z.string().nullable().optional(),
email: z.string().email().nullable().optional().or(z.literal('')),
phone: z.string().nullable().optional(),
});
export const volunteerCreateLocationSchema = z.object({
address: z.string().min(1, 'Address is required'),
latitude: z.number().min(-90).max(90),
longitude: z.number().min(-180).max(180),
unitNumber: z.string().optional(),
// USER+ fields (stripped by route for TEMPs)
supportLevel: z.nativeEnum(SupportLevel).optional(),
sign: z.boolean().optional().default(false),
signSize: z.string().optional(),
notes: z.string().optional(),
// Admin-only fields
firstName: z.string().optional(),
lastName: z.string().optional(),
email: z.string().email().optional().or(z.literal('')),
phone: z.string().optional(),
});
export type RecordVisitInput = z.infer<typeof recordVisitSchema>;
export type BulkRecordVisitInput = z.infer<typeof bulkRecordVisitSchema>;
export type StartSessionInput = z.infer<typeof startSessionSchema>;
export type WalkingRouteInput = z.infer<typeof walkingRouteSchema>;
export type ListMyVisitsInput = z.infer<typeof listMyVisitsSchema>;
export type AdminActivityInput = z.infer<typeof adminActivitySchema>;
export type AdminVisitsInput = z.infer<typeof adminVisitsSchema>;
export const outcomeTrendsQuerySchema = z.object({
granularity: z.enum(['day', 'week']).default('day'),
dateFrom: z.string().optional(),
dateTo: z.string().optional(),
});
export type VolunteerUpdateLocationInput = z.infer<typeof volunteerUpdateLocationSchema>;
export type VolunteerCreateLocationInput = z.infer<typeof volunteerCreateLocationSchema>;
export type OutcomeTrendsQueryInput = z.infer<typeof outcomeTrendsQuerySchema>;