import { z } from 'zod'; import { addressSchema } from '@/schemas/address'; import { backendOrganizationSchema } from '@/schemas/backend/organization'; import { businessFocusOptionsSchema } from '@/schemas/businessFocus'; import { resourceCategorySchema } from '@/schemas/category'; import { coordinateSchema, nameSchema, optionalUrlSchema, yearSchema } from '@/schemas/common'; import { getContactSchema } from '@/schemas/contact'; import { organizationSubtypeSchema } from '@/schemas/organizationSubtype'; type TFunction = (key: string, replacements?: { [key: string]: string | number }) => string; /** * User-friendly need schema for the form * Maps to ResourceFlow with direction='input' in the backend * Uses Zod v4's improved string validation */ export const getFormNeedSchema = (t: TFunction) => z.object({ resource_name: z .string() .trim() .min(1, { message: t('validation.resource.name_min') }), category: resourceCategorySchema.optional(), quantity: z .string() .max(50, { message: t('validation.resource.quantity_max') }) .optional() .describe('Quantity description'), description: z .string() .max(200, { message: t('validation.resource.description_max') }) .optional() .describe('Additional description'), }); /** * User-friendly offer schema for the form * Maps to ResourceFlow with direction='output' in the backend * Uses Zod v4's improved string validation */ export const getFormOfferSchema = (t: TFunction) => z.object({ resource_name: z .string() .trim() .min(1, { message: t('validation.resource.name_min') }), category: resourceCategorySchema.optional(), quantity: z .string() .max(50, { message: t('validation.resource.quantity_max') }) .optional() .describe('Quantity description'), description: z .string() .max(200, { message: t('validation.resource.description_max') }) .optional() .describe('Additional description'), }); /** * Organization form schema - user-friendly interface * Uses "needs" and "offers" (business-friendly terms) * These will be converted to ResourceFlows (backend technical terms) when submitting * * Uses Zod v4's composition features and common schemas for DRY code */ export const getOrganizationFormSchema = (t: TFunction) => z.object({ name: nameSchema.min(2, { message: t('validation.string.min2') }), sector: z .string() .min(1, { message: t('validation.string.min1') }) .describe('Business sector'), description: z .string() .min(10, { message: t('validation.string.min10') }) .describe('Organization description'), subtype: organizationSubtypeSchema.optional(), legal_form: z.enum(['LLC', 'corporation', 'sole_proprietorship']).describe('Legal form'), company_registration_number: z .string() .regex(/^(\d{10}|\d{13})?$/, { message: t('validation.string.regex') }) .optional() .describe('Company registration number (10 or 13 digits)'), website: z .string() .url({ message: t('validation.string.url') }) .or(z.literal('')) .optional(), primary_contact: getContactSchema(t), company_size: z.coerce .number() .int() .min(1, { message: t('validation.number.min1') }) .describe('Company size (number of employees)'), founding_year: yearSchema .min(1800, { message: t('validation.number.min1800') }) .max(new Date().getFullYear(), { message: t('validation.number.max') }), business_focus: z .array(businessFocusOptionsSchema) .min(1, { message: t('validation.array.min1') }) .describe('Business focus areas'), industries: z.array(z.string()).optional().describe('Industries'), tags: z.array(z.string()).optional().describe('Tags'), // User-friendly: "needs" and "offers" // Backend: These will be converted to ResourceFlows with direction='input' and direction='output' needs: z.array(getFormNeedSchema(t)).optional().describe('Resource needs'), offers: z.array(getFormOfferSchema(t)).optional().describe('Resource offers'), logoUrl: optionalUrlSchema, galleryImages: z.array(optionalUrlSchema).optional().default([]).describe('Array of gallery image URLs'), address: addressSchema.optional(), location: coordinateSchema.describe('Geographic location'), }); // For backwards compatibility and non-form usage export const organizationFormSchema = getOrganizationFormSchema((key: string) => key); /** * Organization schema for validation * Alias to backendOrganizationSchema for backwards compatibility * @deprecated Use backendOrganizationSchema from '@/schemas/backend/organization' for new code */ export const organizationSchema = backendOrganizationSchema;