'use client'; import { useEffect, useId, useRef } from 'react'; declare global { interface Window { turnstile?: { render: ( container: string | HTMLElement, options: { sitekey: string; callback: (token: string) => void; 'expired-callback'?: () => void; 'error-callback'?: () => void; theme?: 'auto' | 'light' | 'dark'; }, ) => string; remove: (widgetId: string) => void; reset: (widgetId?: string) => void; }; } } const TURNSTILE_SCRIPT_ID = 'cloudflare-turnstile-script'; const TURNSTILE_SCRIPT_SRC = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit'; interface TurnstileWidgetProps { siteKey: string; onVerify: (token: string) => void; onExpire?: () => void; onError?: () => void; } export function TurnstileWidget({ siteKey, onVerify, onExpire, onError, }: TurnstileWidgetProps) { const containerRef = useRef(null); const widgetIdRef = useRef(null); const elementId = useId().replace(/:/g, '-'); useEffect(() => { let cancelled = false; const mountWidget = () => { if (cancelled || !containerRef.current || !window.turnstile) { return; } if (widgetIdRef.current) { window.turnstile.remove(widgetIdRef.current); widgetIdRef.current = null; } widgetIdRef.current = window.turnstile.render(containerRef.current, { sitekey: siteKey, callback: onVerify, 'expired-callback': onExpire, 'error-callback': onError, theme: 'auto', }); }; const existingScript = document.getElementById(TURNSTILE_SCRIPT_ID) as HTMLScriptElement | null; if (window.turnstile) { mountWidget(); } else if (existingScript) { existingScript.addEventListener('load', mountWidget); } else { const script = document.createElement('script'); script.id = TURNSTILE_SCRIPT_ID; script.src = TURNSTILE_SCRIPT_SRC; script.async = true; script.defer = true; script.addEventListener('load', mountWidget); document.head.appendChild(script); } return () => { cancelled = true; const script = document.getElementById(TURNSTILE_SCRIPT_ID) as HTMLScriptElement | null; if (script) { script.removeEventListener('load', mountWidget); } if (widgetIdRef.current && window.turnstile) { window.turnstile.remove(widgetIdRef.current); widgetIdRef.current = null; } }; }, [onError, onExpire, onVerify, siteKey]); return
; }