Files
Wabenhain/src/components/turnstile-widget.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

61 lines
1.8 KiB
TypeScript

"use client";
import { useEffect, useRef, useState } from "react";
import Script from "next/script";
declare global {
interface Window {
turnstile?: {
render: (container: HTMLElement, options: Record<string, unknown>) => string;
};
}
}
interface TurnstileWidgetProps {
siteKey: string;
onVerify: (token: string) => void;
}
/**
* Cloudflare-Turnstile-CAPTCHA-Widget. Wird nur eingebunden, wenn eine
* NEXT_PUBLIC_TURNSTILE_SITE_KEY konfiguriert ist (siehe README) — ohne
* Konfiguration rendern die umgebenden Formulare gar nicht erst diese
* Komponente und bleiben unveraendert nutzbar.
*/
export function TurnstileWidget({ siteKey, onVerify }: TurnstileWidgetProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [scriptLoaded, setScriptLoaded] = useState(false);
useEffect(() => {
if (!scriptLoaded || !containerRef.current || !window.turnstile) return;
window.turnstile.render(containerRef.current, {
sitekey: siteKey,
callback: onVerify,
"expired-callback": () => onVerify(""),
"error-callback": () => onVerify(""),
});
}, [scriptLoaded, siteKey, onVerify]);
return (
<>
<Script
src="https://challenges.cloudflare.com/turnstile/v0/api.js"
strategy="afterInteractive"
onLoad={() => setScriptLoaded(true)}
/>
<div ref={containerRef} />
</>
);
}
/** Turnstile-Widget fuer klassische (nicht per fetch/JSON gesendete) Formulare: legt das Token als Hidden-Field ab. */
export function TurnstileField({ siteKey, name = "turnstileToken" }: { siteKey: string; name?: string }) {
const [token, setToken] = useState("");
return (
<>
<TurnstileWidget siteKey={siteKey} onVerify={setToken} />
<input type="hidden" name={name} value={token} />
</>
);
}