From 0ac2e45077cf5a40d60c2272757f2069ff1a0770 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 25 Jul 2026 17:34:20 +0000 Subject: [PATCH] Clear "already subscribed" newsletter error on next interaction Matches standard form-validation behavior: any further edit to the email or consent checkbox after the already-subscribed message appears now dismisses it, instead of leaving it stuck until submit. Co-Authored-By: Claude Sonnet 5 --- app/challenge/components/EmailCapture.tsx | 4 ++-- app/components/Newsletter.tsx | 4 ++-- app/components/NewsletterModal.tsx | 4 ++-- app/lib/useNewsletterSignup.ts | 21 ++++++++++++++++++- .../components/WeeklyImpulsesHero.tsx | 4 ++-- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/app/challenge/components/EmailCapture.tsx b/app/challenge/components/EmailCapture.tsx index 30a4860..1fe5718 100644 --- a/app/challenge/components/EmailCapture.tsx +++ b/app/challenge/components/EmailCapture.tsx @@ -13,7 +13,7 @@ function LockIcon() { } export function EmailCapture({ buttonLabel = "Challenge starten" }: { buttonLabel?: string }) { - const { email, emailError, consent, setConsent, status, error, successMessage, emailRef, handleEmailChange, handleEmailBlur, handleSubmit } = + const { email, emailError, consent, handleConsentChange, status, error, successMessage, emailRef, handleEmailChange, handleEmailBlur, handleSubmit } = useNewsletterSignup("challenge"); if (status === "success") { @@ -60,7 +60,7 @@ export function EmailCapture({ buttonLabel = "Challenge starten" }: { buttonLabe type="checkbox" required checked={consent} - onChange={(e) => setConsent(e.target.checked)} + onChange={(e) => handleConsentChange(e.target.checked)} className="size-4 shrink-0 mt-0.5 rounded-xs border border-[#d9d9d9] accent-[#f6a701]" /> diff --git a/app/components/Newsletter.tsx b/app/components/Newsletter.tsx index 8b3b3d6..cd21383 100644 --- a/app/components/Newsletter.tsx +++ b/app/components/Newsletter.tsx @@ -34,7 +34,7 @@ export function Newsletter({ title = <>Starte mit einer Woche voller Klarheit., description = "Melde dich zum Newsletter an und erhalte die 7-Tage-Challenge, mit der du durch mehr Struktur weniger Stress spürst.", }: NewsletterProps = {}) { - const { email, emailError, consent, setConsent, status, error, successMessage, emailRef, handleEmailChange, handleEmailBlur, handleSubmit } = + const { email, emailError, consent, handleConsentChange, status, error, successMessage, emailRef, handleEmailChange, handleEmailBlur, handleSubmit } = useNewsletterSignup("newsletter-page"); return ( @@ -138,7 +138,7 @@ export function Newsletter({ type="checkbox" required checked={consent} - onChange={(e) => setConsent(e.target.checked)} + onChange={(e) => handleConsentChange(e.target.checked)} className="size-4 shrink-0 mt-0.5 rounded-xs border border-border accent-brand" /> diff --git a/app/components/NewsletterModal.tsx b/app/components/NewsletterModal.tsx index 17b2c06..f6fb054 100644 --- a/app/components/NewsletterModal.tsx +++ b/app/components/NewsletterModal.tsx @@ -35,7 +35,7 @@ const features = [ export function NewsletterModal({ open, onClose }: { open: boolean; onClose: () => void }) { const dialogRef = useRef(null); const closeButtonRef = useRef(null); - const { email, emailError, consent, setConsent, status, error, successMessage, emailRef, handleEmailChange, handleEmailBlur, handleSubmit } = + const { email, emailError, consent, handleConsentChange, status, error, successMessage, emailRef, handleEmailChange, handleEmailBlur, handleSubmit } = useNewsletterSignup("newsletter-modal"); // Background scroll lock while open — intercepts and cancels the wheel/ @@ -223,7 +223,7 @@ export function NewsletterModal({ open, onClose }: { open: boolean; onClose: () type="checkbox" required checked={consent} - onChange={(e) => setConsent(e.target.checked)} + onChange={(e) => handleConsentChange(e.target.checked)} className="size-4 shrink-0 rounded-xs border border-border accent-brand" /> diff --git a/app/lib/useNewsletterSignup.ts b/app/lib/useNewsletterSignup.ts index 0560970..95dad4d 100644 --- a/app/lib/useNewsletterSignup.ts +++ b/app/lib/useNewsletterSignup.ts @@ -27,15 +27,34 @@ export function useNewsletterSignup(source: NewsletterOptInSource) { const [error, setError] = useState(""); const emailRef = useRef(null); + // Clears a previous submit-time error (real failure or "already + // subscribed") the moment the customer interacts with the form again — + // same "stale validation message shouldn't linger" behavior + // emailError already had for itself, extended to the submit-result + // error too, since it's otherwise easy to misread as still describing + // the current (possibly already-corrected) input. + function clearSubmitError() { + if (status === "error") { + setStatus("idle"); + setError(""); + } + } + function handleEmailChange(value: string) { setEmail(value); if (emailError) setEmailError(""); + clearSubmitError(); } function handleEmailBlur(value: string) { setEmailError(validateEmailFormat(value)); } + function handleConsentChange(checked: boolean) { + setConsent(checked); + clearSubmitError(); + } + async function handleSubmit(e: FormEvent) { e.preventDefault(); const formatError = validateEmailFormat(email); @@ -70,5 +89,5 @@ export function useNewsletterSignup(source: NewsletterOptInSource) { } } - return { email, emailError, consent, setConsent, status, error, successMessage: SUCCESS_MESSAGE, emailRef, handleEmailChange, handleEmailBlur, handleSubmit }; + return { email, emailError, consent, handleConsentChange, status, error, successMessage: SUCCESS_MESSAGE, emailRef, handleEmailChange, handleEmailBlur, handleSubmit }; } diff --git a/app/newsletter/components/WeeklyImpulsesHero.tsx b/app/newsletter/components/WeeklyImpulsesHero.tsx index 48a7b90..3d61cd8 100644 --- a/app/newsletter/components/WeeklyImpulsesHero.tsx +++ b/app/newsletter/components/WeeklyImpulsesHero.tsx @@ -35,7 +35,7 @@ const checklist = [ ]; export function WeeklyImpulsesHero() { - const { email, emailError, consent, setConsent, status, error, successMessage, emailRef, handleEmailChange, handleEmailBlur, handleSubmit } = + const { email, emailError, consent, handleConsentChange, status, error, successMessage, emailRef, handleEmailChange, handleEmailBlur, handleSubmit } = useNewsletterSignup("newsletter-hero"); return ( @@ -155,7 +155,7 @@ export function WeeklyImpulsesHero() { type="checkbox" required checked={consent} - onChange={(e) => setConsent(e.target.checked)} + onChange={(e) => handleConsentChange(e.target.checked)} className="size-4 shrink-0 mt-0.5 rounded-xs border border-border accent-brand" />