// New patient — 3-step wizard. const WZ_VT = window.VT || {}; const WZ_DANGER = WZ_VT.danger || '#b91c1c'; // ───────────────────────────────────────────────────────────── // Validation — au blur uniquement. // Corriger quelqu'un pendant qu'il tape est hostile : on attend qu'il ait // fini le champ. L'erreur s'efface dès la première frappe suivante. // Les champs facultatifs ne sont contrôlés que s'ils sont remplis. // ───────────────────────────────────────────────────────────── function wzValidate(field, raw) { const v = String(raw || '').trim(); if (field === 'ddn') { if (!v) return 'Date de naissance requise.'; const m = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(v); if (!m) return 'Format attendu : JJ/MM/AAAA.'; const [, dd, mm, yyyy] = m.map(Number); const d = new Date(yyyy, mm - 1, dd); // getMonth() rattrape les 31/02 : si le mois a glissé, la date n'existe pas. if (d.getFullYear() !== yyyy || d.getMonth() !== mm - 1 || d.getDate() !== dd) { return "Cette date n'existe pas."; } if (yyyy < 1900) return 'Année trop ancienne.'; if (d > new Date()) return 'Date dans le futur.'; return null; } if (field === 'email') { if (!v) return null; if (!/^[^\s@]+@[^\s@]+\.[a-zA-Z]{2,}$/.test(v)) return 'Adresse e-mail invalide.'; return null; } if (field === 'secu') { if (!v) return null; const digits = v.replace(/\s/g, ''); if (!/^\d{15}$/.test(digits)) return '15 chiffres attendus.'; if (!/^[12]/.test(digits)) return 'Doit commencer par 1 ou 2.'; return null; } if (field === 'phone') { if (!v) return null; const digits = v.replace(/[\s.\-]/g, ''); if (!/^(0\d{9}|\+33\d{9})$/.test(digits)) return 'Numéro à 10 chiffres attendu.'; return null; } return null; } function StepBar({ step }) { return (