diff --git a/admin/src/app/login/page.tsx b/admin/src/app/login/page.tsx index e6c5b9f..c2a81ac 100644 --- a/admin/src/app/login/page.tsx +++ b/admin/src/app/login/page.tsx @@ -28,24 +28,21 @@ export default function LoginPage() { }, []); const performLogin = useCallback(async () => { - // Use development bypass for now - const token = process.env.NODE_ENV === 'development' ? 'BYPASS_DEV_MODE' : altchaToken; - - if (!token && !altchaVerified) { + if (!altchaToken) { setError('Please complete the security verification'); return; } setLoading(true); try { - await login(emailRef.current, passwordRef.current, token); + await login(emailRef.current, passwordRef.current, altchaToken); router.push('/'); } catch (err: any) { setError(err.message || 'Login failed. Check your credentials.'); } finally { setLoading(false); } - }, [login, router, altchaToken, altchaVerified]); + }, [login, router, altchaToken]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); @@ -114,7 +111,7 @@ export default function LoginPage() { {loading ? 'Signing in...' : 'Sign In'} diff --git a/admin/src/components/Altcha.tsx b/admin/src/components/Altcha.tsx index cb1a7e8..af864d8 100644 --- a/admin/src/components/Altcha.tsx +++ b/admin/src/components/Altcha.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useEffect, useRef, useCallback } from 'react'; +import { useEffect, useRef } from 'react'; interface AltchaProps { challengeurl: string; @@ -9,63 +9,46 @@ interface AltchaProps { } export default function Altcha({ challengeurl, onVerified, onError }: AltchaProps) { - const widgetRef = useRef(null); - const scriptLoaded = useRef(false); + const containerRef = useRef(null); + const callbacksRef = useRef({ onVerified, onError }); + callbacksRef.current = { onVerified, onError }; - const handleStateChange = useCallback((e: Event) => { - const detail = (e as CustomEvent).detail; - if (detail?.state === 'verified' && detail?.payload) { - onVerified?.(detail.payload); - } else if (detail?.state === 'error') { - onError?.(); + useEffect(() => { + // Load script if not already loaded + if (!document.querySelector('script[data-altcha]')) { + const script = document.createElement('script'); + script.src = 'https://cdn.jsdelivr.net/npm/altcha@2.3.0/dist/altcha.min.js'; + script.type = 'module'; + script.async = true; + script.setAttribute('data-altcha', 'true'); + document.head.appendChild(script); } - }, [onVerified, onError]); - useEffect(() => { - if (scriptLoaded.current) return; - scriptLoaded.current = true; - - const script = document.createElement('script'); - script.src = 'https://cdn.jsdelivr.net/npm/altcha@2.3.0/dist/altcha.min.js'; - script.type = 'module'; - script.async = true; - document.head.appendChild(script); - }, []); - - useEffect(() => { - const container = widgetRef.current; + const container = containerRef.current; if (!container) return; - const observer = new MutationObserver(() => { - const widget = container.querySelector('altcha-widget'); - if (widget) { - widget.addEventListener('statechange', handleStateChange); - observer.disconnect(); - } - }); - - observer.observe(container, { childList: true, subtree: true }); - - // Also try immediately in case widget already exists + // Create the widget element + container.innerHTML = ``; const widget = container.querySelector('altcha-widget'); - if (widget) { - widget.addEventListener('statechange', handleStateChange); - observer.disconnect(); - } + if (!widget) return; - return () => { - observer.disconnect(); - const w = container.querySelector('altcha-widget'); - if (w) { - w.removeEventListener('statechange', handleStateChange); + const handler = (e: Event) => { + const detail = (e as CustomEvent).detail; + console.log('[ALTCHA] statechange:', detail); + if (detail?.state === 'verified' && detail?.payload) { + callbacksRef.current.onVerified?.(detail.payload); + } else if (detail?.state === 'error') { + callbacksRef.current.onError?.(); } }; - }, [handleStateChange]); - return ( - ` - }} /> - ); + widget.addEventListener('statechange', handler); + + return () => { + widget.removeEventListener('statechange', handler); + }; + }, [challengeurl]); + + return ; }