Files
Wabenhain/src/components/newsletter-signup.tsx
T
Nick Szaunig c7927f2883 feat: Wabenhain Honig-Shop Anwendung
Vollstaendige Next.js/Prisma-E-Commerce-Anwendung fuer eine Imkerei:
Shop, Warenkorb, Stripe-Checkout, Kundenkonto mit 2FA, Admin-Bereich
(Produkte, Ernten, Chargen, Bestellungen, Gutscheine, admin-editierbare
Website-Inhalte), i18n (DE/EN), Rate-Limiting/CSP/Audit-Log-Haertung,
PostgreSQL- und MySQL-Unterstuetzung ueber austauschbare Prisma-
Treiber-Adapter, Unit-/Komponenten-/E2E-Tests.
2026-08-17 14:30:28 +02:00

89 lines
3.1 KiB
TypeScript

"use client";
import { useState, type FormEvent } from "react";
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";
const TURNSTILE_SITE_KEY = process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY;
export function NewsletterSignup() {
const { t } = useI18n();
const [email, setEmail] = useState("");
const [status, setStatus] = useState<Status>("idle");
const [turnstileToken, setTurnstileToken] = useState("");
async function handleSubmit(event: FormEvent<HTMLFormElement>) {
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 (
<section className="py-24">
<Container className="max-w-2xl text-center">
<ScrollReveal>
<SectionHeading
eyebrow={t.home.newsletter.eyebrow}
title={t.home.newsletter.title}
align="center"
className="mx-auto"
/>
<p className="mt-4 text-ink/70">{t.home.newsletter.description}</p>
{status === "success" ? (
<p className="mt-8 text-forest">{t.home.newsletter.successMessage}</p>
) : (
<form
onSubmit={handleSubmit}
className="mt-8 flex flex-col sm:flex-row gap-3 max-w-lg mx-auto"
>
<input
type="email"
required
placeholder={t.home.newsletter.emailPlaceholder}
value={email}
onChange={(e) => 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"
/>
<Button type="submit" disabled={status === "loading"} className="flex-shrink-0 whitespace-nowrap">
{status === "loading" ? t.home.newsletter.subscribing : t.home.newsletter.subscribe}
</Button>
{TURNSTILE_SITE_KEY ? (
<div className="w-full flex justify-center">
<TurnstileWidget siteKey={TURNSTILE_SITE_KEY} onVerify={setTurnstileToken} />
</div>
) : null}
</form>
)}
{status === "error" ? (
<p className="mt-4 text-sm text-red-700">{t.home.newsletter.errorMessage}</p>
) : null}
<p className="mt-6 text-xs text-ink/65">
{t.home.newsletter.consentBeforeLink}
<a href="/datenschutz" className="underline">
{t.home.newsletter.privacyLinkLabel}
</a>
{t.home.newsletter.consentAfterLink}
</p>
</ScrollReveal>
</Container>
</section>
);
}