"use client"; import { useState, type FormEvent } from "react"; import { motion } from "motion/react"; import { HoneycombPattern } from "@/components/honeycomb"; import { Container, SectionHeading, Button } from "@/components/ui"; import { ScrollReveal } from "@/components/scroll-reveal"; import { TurnstileWidget } from "@/components/turnstile-widget"; import { useI18n } from "@/i18n/i18n-provider"; type Status = "idle" | "loading" | "success" | "error"; /** * Der Turnstile-Sitekey kommt als Prop vom Server und NICHT aus * process.env in dieser Datei. * * Grund: NEXT_PUBLIC_-Variablen werden in Client Components zur BUILD-Zeit * ins Bundle eingebacken. Der Wert wird hier aber erst zur Laufzeit gesetzt * (k8s/01-configmap.yaml). Ein Zugriff auf process.env an dieser Stelle * ergibt deshalb dauerhaft undefined — das Widget erschiene nie, waehrend die * Serverseite bei gesetztem TURNSTILE_SECRET_KEY sehr wohl einen Token * verlangt. Das Formular waere damit unabsendbar, ohne dass irgendwo ein * Fehler auftaucht. * * Alle uebrigen Formulare (Login, Registrierung, Passwort-Reset, Zwei-Faktor, * Checkout, Verfuegbarkeits-Benachrichtigung) lesen den Wert bereits im * Server Component und reichen ihn als Prop weiter. Diese Datei folgt jetzt * demselben Muster. */ export function NewsletterSignup({ turnstileSiteKey }: { turnstileSiteKey?: string }) { const { t } = useI18n(); const [email, setEmail] = useState(""); const [status, setStatus] = useState("idle"); const [turnstileToken, setTurnstileToken] = useState(""); async function handleSubmit(event: FormEvent) { event.preventDefault(); setStatus("loading"); try { const response = await fetch("/api/newsletter", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, turnstileToken }), }); if (!response.ok) throw new Error("request failed"); setStatus("success"); setEmail(""); } catch { setStatus("error"); } } return (
{/* Eigene Flaeche mit Wabenraster: die Anmeldung ist ein Angebot, kein Nachsatz unter der Seite. */}

{t.home.newsletter.description}

{status === "success" ? ( // Bestaetigung als kleine Zeremonie: das Haekchen zeichnet sich // in der Wabe, dann erscheint der Text.
{t.home.newsletter.successMessage}
) : (
{/* Eingabefeld und Knopf bilden die Zeile, das CAPTCHA steht darunter. Frueher lagen alle drei in derselben Flex-Zeile ohne flex-wrap: sobald das Widget tatsaechlich rendert, belegte es rund 300 px der 512 px breiten Zeile und drueckte das Eingabefeld auf 34 px zusammen. Solange kein Sitekey gesetzt war, fiel das nicht auf, weil das Widget gar nicht erst erschien. */}
setEmail(e.target.value)} className="min-w-0 flex-1 border border-ink/20 bg-background px-4 py-3 text-sm focus:outline-none focus:border-forest" />
{turnstileSiteKey ? (
) : null}
)} {status === "error" ? (

{t.home.newsletter.errorMessage}

) : null}

{t.home.newsletter.consentBeforeLink} {t.home.newsletter.privacyLinkLabel} {t.home.newsletter.consentAfterLink}

); }