proposal-system/web/src/domain/customers/schemas.ts

49 lines
1.8 KiB
TypeScript
Raw Normal View History

// Customers domain — contract schema re-exports + customer form schema.
import { z } from 'zod';
import { createCustomerRequestSchema } from '@proposal-system/api-contracts/schemas';
import type { CreateCustomerRequest, UpdateCustomerRequest } from './types';
export {
customerSchema,
createCustomerRequestSchema,
updateCustomerRequestSchema,
} from '@proposal-system/api-contracts/schemas';
/** Simple email format check (client-side only) — mirrors CustomerManagementPage. */
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
/**
* Customer create/edit form. Derived from createCustomerRequestSchema — the
* form edits a single primary address string (the wire type takes
* addresses: string[]); toCustomerRequest() maps to the request shape.
*/
export const customerFormSchema = createCustomerRequestSchema
.pick({ name: true })
.extend({
name: z.string().trim().min(1, 'Name is required'),
address: z.string().trim().min(1, 'Address is required'),
contactEmail: z
.string()
.refine((v) => v.trim() === '' || EMAIL_RE.test(v.trim()), {
message: 'Enter a valid email address',
}),
});
export type CustomerFormValues = z.infer<typeof customerFormSchema>;
/**
* Map validated form values to the create/update request. The form edits the
* primary address; any additional existing addresses are preserved
* (mirrors the current CustomerManagementPage submit mapping).
*/
export function toCustomerRequest(
values: CustomerFormValues,
existingAddresses: string[] = []
): CreateCustomerRequest & UpdateCustomerRequest {
return {
name: values.name.trim(),
addresses: [values.address.trim(), ...existingAddresses.slice(1)],
...(values.contactEmail.trim() ? { contactEmail: values.contactEmail.trim() } : {}),
};
}