Files
einfach-produktiv/app/lib/useNewsletterSignup.ts
T
Marco fd98f68ba6 Route already-subscribed through the error state, not success
Per explicit feedback: swapping the whole form out for a bare success
message felt wrong for "you're already signed up, nothing to do" — the
form stays visible with a small red note below it instead, same as
every other inline validation error. No per-form UI changes needed,
they already render the error state.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 17:27:50 +00:00

75 lines
3.0 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);
function handleEmailChange(value: string) {
setEmail(value);
if (emailError) setEmailError("");
}
function handleEmailBlur(value: string) {
setEmailError(validateEmailFormat(value));
}
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, setConsent, status, error, successMessage: SUCCESS_MESSAGE, emailRef, handleEmailChange, handleEmailBlur, handleSubmit };
}