Fix consent token not set before submission

- home.tsx: extract postConsent() helper; make onSubmit async and await it
  before doActualSubmit (returning users); await it in handleConsentConfirm
  before doActualSubmit (new users, was fire-and-forget)
- consultation.tsx: same fix on returning-user path in onSubmit

Without this, returning users (consent_v1 in localStorage) never called
/api/consent so the _ct cookie was never set, causing all submissions to
return 403 consent_required.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 16:15:43 +02:00
parent e31c268d54
commit 18bb0efc30
2 changed files with 19 additions and 10 deletions
@@ -181,6 +181,12 @@ export default function ConsultationPage() {
setShowConsentDialog(true); setShowConsentDialog(true);
return; return;
} }
try {
const visitorId = getVisitorId();
const h: Record<string, string> = { "Content-Type": "application/json" };
if (visitorId) h["X-Visitor-Id"] = visitorId;
await fetch(`${API_BASE}/api/consent`, { method: "POST", headers: h, body: JSON.stringify({ consent_version: "1.0" }) });
} catch { /* non-bloquant */ }
await doActualSubmit(data); await doActualSubmit(data);
}; };
+13 -10
View File
@@ -165,22 +165,24 @@ export default function Home() {
}); });
}; };
// Confirme le consentement, l'enregistre en DB, puis exécute la soumission en attente const postConsent = async () => {
const handleConsentConfirm = () => {
localStorage.setItem("consent_v1", new Date().toISOString());
setConsentGiven(true);
setShowConsentDialog(false);
const visitorId = getVisitorId(); const visitorId = getVisitorId();
fetch(`${API_BASE}/api/consent`, { await fetch(`${API_BASE}/api/consent`, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
...(visitorId ? { "X-Visitor-Id": visitorId } : {}), ...(visitorId ? { "X-Visitor-Id": visitorId } : {}),
}, },
body: JSON.stringify({ consent_version: "1.0" }), body: JSON.stringify({ consent_version: "1.0" }),
}).catch(() => { }).catch(() => {});
// Dégradation silencieuse — localStorage suffit comme preuve côté client };
});
// Confirme le consentement, l'enregistre en DB, puis exécute la soumission en attente
const handleConsentConfirm = async () => {
localStorage.setItem("consent_v1", new Date().toISOString());
setConsentGiven(true);
setShowConsentDialog(false);
await postConsent();
if (pendingSubmitData.current) { if (pendingSubmitData.current) {
doActualSubmit(pendingSubmitData.current); doActualSubmit(pendingSubmitData.current);
pendingSubmitData.current = null; pendingSubmitData.current = null;
@@ -250,7 +252,7 @@ export default function Home() {
defaultValues: { content: "", author: "" }, defaultValues: { content: "", author: "" },
}); });
const onSubmit = (data: SubmitIdeaValues) => { const onSubmit = async (data: SubmitIdeaValues) => {
// Honeypot — si le champ leurre est rempli, c'est un bot // Honeypot — si le champ leurre est rempli, c'est un bot
if (honeypotRef.current?.value) { if (honeypotRef.current?.value) {
setSubmitResult({ success: true, message: "Votre contribution a été ajoutée à la synthèse." }); setSubmitResult({ success: true, message: "Votre contribution a été ajoutée à la synthèse." });
@@ -268,6 +270,7 @@ export default function Home() {
setShowConsentDialog(true); setShowConsentDialog(true);
return; return;
} }
await postConsent();
doActualSubmit(data); doActualSubmit(data);
}; };