diff --git a/components/TurnstileWidget.tsx b/components/TurnstileWidget.tsx index c2cd12f..3369571 100644 --- a/components/TurnstileWidget.tsx +++ b/components/TurnstileWidget.tsx @@ -1,28 +1,7 @@ "use client"; -import Script from "next/script"; -import { useCallback, useEffect, useRef, useState } from "react"; - -type TurnstileWidgetId = string; -type TurnstileApi = { - render: ( - container: HTMLElement, - options: { - sitekey: string; - action: string; - callback: (token: string) => void; - "expired-callback": () => void; - "error-callback": () => void; - }, - ) => TurnstileWidgetId; - reset: (widgetId: TurnstileWidgetId) => void; -}; - -declare global { - interface Window { - turnstile?: TurnstileApi; - } -} +import { useEffect, useRef, useState } from "react"; +import { loadTurnstile, type TurnstileWidgetId } from "@/lib/turnstile/client"; type TurnstileWidgetProps = { siteKey: string; @@ -50,45 +29,50 @@ export function TurnstileWidget({ siteKey, action, resetKey, onTokenChange }: Tu onTokenChangeRef.current(null); }, [resetKey]); - const render = useCallback(() => { + useEffect(() => { if (!siteKey || !containerRef.current || widgetIdRef.current !== null) return; - if (!window.turnstile) { - setLoadError(true); - return; - } - try { - widgetIdRef.current = window.turnstile.render(containerRef.current, { - sitekey: siteKey, - action, - callback: (token) => { - setVerificationStatus("ready"); - onTokenChangeRef.current(token); - }, - "expired-callback": () => { - setVerificationStatus("expired"); - onTokenChangeRef.current(null); - }, - "error-callback": () => { - onTokenChangeRef.current(null); + let cancelled = false; + loadTurnstile() + .then((turnstile) => { + if (cancelled || !containerRef.current || widgetIdRef.current !== null) return; + + try { + widgetIdRef.current = turnstile.render(containerRef.current, { + sitekey: siteKey, + action, + callback: (token) => { + setVerificationStatus("ready"); + onTokenChangeRef.current(token); + }, + "expired-callback": () => { + setVerificationStatus("expired"); + onTokenChangeRef.current(null); + }, + "error-callback": () => { + onTokenChangeRef.current(null); + setLoadError(true); + }, + }); + } catch { setLoadError(true); - }, + onTokenChangeRef.current(null); + } + }) + .catch(() => { + if (cancelled) return; + setLoadError(true); + onTokenChangeRef.current(null); }); - } catch { - setLoadError(true); - onTokenChangeRef.current(null); - } + + return () => { + cancelled = true; + }; }, [action, siteKey]); return (
-