Gestisce errori email del form contatti senza 500 opaco. (#18)

Invia via fetch/JSON, cattura fallimenti Cloudflare Email (con retry senza Reply-To) e reindirizza a #contatti.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Javaxman
2026-07-29 15:24:28 +02:00
committed by GitHub
parent 2c3df8371d
commit 4b70c940db
3 changed files with 201 additions and 83 deletions

View File

@ -1,4 +1,4 @@
/** Modulo contatti in pagina (#contatti): mailto o POST Formspree. */
/** Modulo contatti in pagina (#contatti): mailto o POST /api/contact. */
interface ContactFormCfg {
actionUrl: string;
mailto: string;
@ -52,11 +52,18 @@ function readCfg(): ContactFormCfg {
return JSON.parse(raw) as ContactFormCfg;
}
function showError(message: string): void {
const err = document.getElementById('nx-contact-form-error');
if (!err) return;
err.textContent = message;
err.classList.remove('hidden');
}
function bind(): void {
const form = document.getElementById('nx-contact-form') as HTMLFormElement | null;
if (!form) return;
form.addEventListener('submit', (e) => {
form.addEventListener('submit', async (e) => {
const cfg = readCfg();
const err = document.getElementById('nx-contact-form-error');
if (err) err.classList.add('hidden');
@ -69,17 +76,44 @@ function bind(): void {
)?.value;
if (!token) {
e.preventDefault();
if (err) {
err.textContent = cfg.turnstileError;
err.classList.remove('hidden');
}
showError(cfg.turnstileError);
return;
}
}
if (cfg.actionUrl) {
e.preventDefault();
const submitBtn = form.querySelector<HTMLButtonElement>('button[type="submit"]');
if (submitBtn) submitBtn.disabled = true;
try {
const res = await fetch(cfg.actionUrl, {
method: 'POST',
headers: { Accept: 'application/json' },
body: new FormData(form),
});
const data = (await res.json().catch(() => null)) as
| { ok?: boolean; error?: string; redirect?: string }
| null;
if (!res.ok) {
showError(
(data && typeof data.error === 'string' && data.error) ||
'Invio non riuscito. Riprova tra poco.',
);
return;
}
const target =
(data && typeof data.redirect === 'string' && data.redirect) ||
cfg.successRedirect ||
`${window.location.pathname}${window.location.search}#contatti`;
window.location.assign(target);
} catch {
showError('Errore di rete. Controlla la connessione e riprova.');
} finally {
if (submitBtn) submitBtn.disabled = false;
}
return;
}
e.preventDefault();
const fd = new FormData(form);
const name = String(fd.get(cfg.fieldName) ?? '').trim();
@ -101,10 +135,7 @@ function bind(): void {
window.location.href = `mailto:${cfg.mailto}?subject=${subject}&body=${body}`;
return;
}
if (err) {
err.textContent = cfg.configError;
err.classList.remove('hidden');
}
showError(cfg.configError);
});
}