// ─── 폼 필수 입력 검증 ────────────────────────────────────────────────────────
// 필수 항목이 채워지지 않으면 접수되지 않도록 공통 검증을 제공한다.
// validateForm(form, rules) → { ok, errors: {key: 메시지} }
// rules: [{ k, label, type }] type: 'text' | 'email' | 'phone' | 'agree'
// 라벨에는 를 붙여 필수 표시(*)를 노출한다.
const FV = (() => {
const msgs = {
ko: { required:'필수 입력 항목입니다.', email:'올바른 이메일 형식이 아닙니다.', phone:'올바른 연락처를 입력해 주세요.', agree:'개인정보 수집·이용에 동의해 주세요.' },
en: { required:'This field is required.', email:'Enter a valid email address.', phone:'Enter a valid phone number.', agree:'Please agree to the privacy notice.' },
ja: { required:'必須項目です。', email:'メールアドレスの形式が正しくありません。', phone:'正しい連絡先を入力してください。', agree:'個人情報の取扱いに同意してください。' },
};
const M = (lang, k) => (msgs[lang] || msgs.ko)[k];
const isEmail = v => /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(String(v||'').trim());
// 국내 번호 기준: 숫자 9~11자리 (하이픈·공백·괄호 허용)
const isPhone = v => { const d = String(v||'').replace(/[^0-9]/g,''); return d.length >= 9 && d.length <= 11; };
const validateForm = (form, rules, lang='ko') => {
const errors = {};
rules.forEach(r => {
const v = form[r.k];
if (r.type === 'agree') { if (!v) errors[r.k] = M(lang,'agree'); return; }
if (r.type === 'multi') { if (!Array.isArray(v) || !v.length) errors[r.k] = M(lang,'required'); return; }
const s = String(v ?? '').trim();
if (!s) { errors[r.k] = M(lang,'required'); return; }
if (r.type === 'email' && !isEmail(s)) errors[r.k] = M(lang,'email');
if (r.type === 'phone' && !isPhone(s)) errors[r.k] = M(lang,'phone');
});
return { ok: Object.keys(errors).length === 0, errors };
};
return { validateForm, isEmail, isPhone, M };
})();
// 필수 표시 — 라벨 뒤에 붙인다
const Req = () => *;
// 입력칸 아래 오류 메시지
const FieldErr = ({ msg }) => msg ? {msg} : null;
Object.assign(window, { validateForm: FV.validateForm, isEmailValid: FV.isEmail, isPhoneValid: FV.isPhone, Req, FieldErr });