Files
einfach-produktiv/app/lib/useNewsletterSignup.ts
T
Marco 0ac2e45077 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>
2026-07-25 17:34:20 +00:00

94 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useRef, useState, type FormEvent } from "react";
import { validateEmailFormat } from "./email";
import type { NewsletterOptInSource } from "./brevo";
// Shared state/submit logic behind every newsletter-signup form
// (Newsletter.tsx, NewsletterModal.tsx, WeeklyImpulsesHero.tsx's inline
// hero form, /challenge's EmailCapture) — four places with the same
// email+consent+submit shape but different markup/visual style, so only
// the logic is shared here rather than a one-size-fits-all component.
// Per the user's own explicit wording request, see the newsletter-DOI
// memory — kept here once rather than duplicated across all 4 forms.
const SUCCESS_MESSAGE = "Fast geschafft! Schau kurz in dein Postfach da wartet schon eine Mail von uns.";
// Deliberately routed through the *error* state, not a success variant —
// per explicit feedback: swapping the whole form out for a bare message
// (the real-success treatment) felt wrong for "you're already signed up,
// nothing to do" — the form should stay visible, with a small note below
// it, exactly like every other inline validation error already does.
const ALREADY_SUBSCRIBED_MESSAGE = "Diese E-Mail-Adresse ist schon für unseren Newsletter angemeldet.";
export function useNewsletterSignup(source: NewsletterOptInSource) {
const [email, setEmail] = useState("");
const [emailError, setEmailError] = useState("");
const [consent, setConsent] = useState(false);
const [status, setStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
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);
setEmailError(formatError);
if (formatError) {
emailRef.current?.focus();
return;
}
setStatus("submitting");
setError("");
try {
const res = await fetch("/api/newsletter/subscribe", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, consent, source }),
});
const data = await res.json();
if (!data.ok) {
setError(data.reason || "Anmeldung ist fehlgeschlagen. Bitte versuche es später erneut.");
setStatus("error");
return;
}
if (data.alreadySubscribed) {
setError(ALREADY_SUBSCRIBED_MESSAGE);
setStatus("error");
return;
}
setStatus("success");
} catch {
setError("Anmeldung ist fehlgeschlagen. Bitte versuche es später erneut.");
setStatus("error");
}
}
return { email, emailError, consent, handleConsentChange, status, error, successMessage: SUCCESS_MESSAGE, emailRef, handleEmailChange, handleEmailBlur, handleSubmit };
}