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 <noreply@anthropic.com>
This commit is contained in:
Marco
2026-07-25 17:34:20 +00:00
parent fd98f68ba6
commit 0ac2e45077
5 changed files with 28 additions and 9 deletions
+2 -2
View File
@@ -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]"
/>
<span className="text-[0.8rem] text-[#444] leading-normal">
+2 -2
View File
@@ -34,7 +34,7 @@ export function Newsletter({
title = <>Starte mit einer Woche voller Klarheit<span className="text-brand">.</span></>,
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"
/>
<span className="text-label text-text-primary font-normal leading-normal">
+2 -2
View File
@@ -35,7 +35,7 @@ const features = [
export function NewsletterModal({ open, onClose }: { open: boolean; onClose: () => void }) {
const dialogRef = useRef<HTMLDivElement>(null);
const closeButtonRef = useRef<HTMLButtonElement>(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"
/>
<span className="text-label text-text-primary">
+20 -1
View File
@@ -27,15 +27,34 @@ export function useNewsletterSignup(source: NewsletterOptInSource) {
const [error, setError] = useState("");
const emailRef = useRef<HTMLInputElement>(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<HTMLFormElement>) {
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 };
}
@@ -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"
/>
<span className="text-label text-text-primary font-normal leading-normal">