import { emailValidator, regexValidator, requiredValidator, urlValidator } from './validators' import { FormFieldType } from '../types/formBuilder' import type { PublicFormField } from '../types/formBuilder' export type Validator = (value: unknown) => true | string /** * Build a list of client-side validators for a public form field. * Runs in VTextField `:rules` and the stepper "current step valid" * gate. Mirrors (a subset of) the backend relaxed rule set so the * submitter gets feedback before the submit round-trip. */ export function getValidatorsForField(field: PublicFormField): Validator[] { const rules: Validator[] = [] const v = field.validation_rules ?? {} if (field.is_required) { rules.push(value => { const ok = requiredValidator(value) return ok === true ? true : 'Dit veld is verplicht.' }) } switch (field.field_type) { case FormFieldType.EMAIL: rules.push(value => { const ok = emailValidator(value) return ok === true ? true : 'Vul een geldig e-mailadres in.' }) break case FormFieldType.URL: rules.push(value => { const ok = urlValidator(value) return ok === true ? true : 'Vul een geldige URL in (beginnend met http:// of https://).' }) break case FormFieldType.PHONE: rules.push(value => { if (value === null || value === undefined || value === '') return true const s = String(value).replace(/\s+/g, '') return /^\+?[\d()-]{6,}$/.test(s) || 'Vul een geldig telefoonnummer in.' }) break case FormFieldType.NUMBER: rules.push(value => { if (value === null || value === undefined || value === '') return true const n = Number(value) return Number.isFinite(n) || 'Vul een geldig getal in.' }) if (typeof v.min === 'number') { const min = v.min rules.push(value => { if (value === null || value === undefined || value === '') return true const n = Number(value) return Number.isFinite(n) && n >= min ? true : `Minimaal ${min}.` }) } if (typeof v.max === 'number') { const max = v.max rules.push(value => { if (value === null || value === undefined || value === '') return true const n = Number(value) return Number.isFinite(n) && n <= max ? true : `Maximaal ${max}.` }) } break case FormFieldType.TEXT: case FormFieldType.TEXTAREA: if (typeof v.min === 'number') { const min = v.min rules.push(value => { if (value === null || value === undefined || value === '') return true return String(value).length >= min ? true : `Minimaal ${min} tekens.` }) } if (typeof v.max === 'number') { const max = v.max rules.push(value => { if (value === null || value === undefined || value === '') return true return String(value).length <= max ? true : `Maximaal ${max} tekens.` }) } if (typeof v.pattern === 'string' && v.pattern.length > 0) { const pattern = v.pattern rules.push(value => { if (value === null || value === undefined || value === '') return true const ok = regexValidator(value, pattern) return ok === true ? true : 'Ongeldige invoer.' }) } break case FormFieldType.MULTISELECT: case FormFieldType.CHECKBOX_LIST: if (typeof v.min_selections === 'number') { const min = v.min_selections rules.push(value => { const arr = Array.isArray(value) ? value : [] return arr.length >= min ? true : `Kies er minimaal ${min}.` }) } if (typeof v.max_selections === 'number') { const max = v.max_selections rules.push(value => { const arr = Array.isArray(value) ? value : [] return arr.length <= max ? true : `Kies er maximaal ${max}.` }) } break default: break } return rules } export function runValidators(rules: Validator[], value: unknown): string | true { for (const rule of rules) { const r = rule(value) if (r !== true) return r } return true } export function isFieldValueEmpty(value: unknown): boolean { if (value === null || value === undefined) return true if (typeof value === 'string') return value.trim() === '' if (Array.isArray(value)) return value.length === 0 return false }