Files
ProductDevelopment/src/components/Turnstile.js
T
Sizzy e22a8dc248 chnages
chnages
2026-07-01 01:10:13 +05:45

65 lines
2.1 KiB
JavaScript

// Reusable Cloudflare Turnstile widget. Loads the CF script on demand,
// renders the widget, and reports the token up via onToken. Exposes a
// reset() through a ref so forms can re-challenge after a failure.
import { useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
const SITE_KEY = process.env.REACT_APP_TURNSTILE_SITE_KEY;
const SCRIPT_SRC = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit';
let scriptPromise = null;
function loadTurnstileScript() {
if (window.turnstile) return Promise.resolve();
if (scriptPromise) return scriptPromise;
scriptPromise = new Promise((resolve, reject) => {
const s = document.createElement('script');
s.src = SCRIPT_SRC;
s.async = true;
s.defer = true;
s.onload = () => resolve();
s.onerror = () => reject(new Error('Failed to load CAPTCHA.'));
document.head.appendChild(s);
});
return scriptPromise;
}
const Turnstile = forwardRef(function Turnstile({ onToken }, ref) {
const containerRef = useRef(null);
const widgetId = useRef(null);
useImperativeHandle(ref, () => ({
reset() {
if (widgetId.current !== null && window.turnstile) {
window.turnstile.reset(widgetId.current);
onToken?.('');
}
},
}));
useEffect(() => {
let cancelled = false;
loadTurnstileScript()
.then(() => {
if (cancelled || !containerRef.current || widgetId.current !== null) return;
widgetId.current = window.turnstile.render(containerRef.current, {
sitekey: SITE_KEY,
callback: (token) => onToken?.(token),
'expired-callback': () => onToken?.(''),
'error-callback': () => onToken?.(''),
});
})
.catch(() => {/* surfaced via missing token on submit */});
return () => {
cancelled = true;
if (widgetId.current !== null && window.turnstile) {
window.turnstile.remove(widgetId.current);
widgetId.current = null;
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return <div ref={containerRef} className="mt-8" />;
});
export default Turnstile;