import { useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Lock } from 'lucide-react'; import { getLoginConfig, login } from '../dataService'; declare global { interface Window { turnstile?: { render: ( container: HTMLElement, options: { sitekey: string; callback: (token: string) => void; 'expired-callback': () => void; 'error-callback': () => void; theme: 'dark' | 'light' | 'auto'; } ) => string; reset: (widgetId?: string) => void; }; } } const turnstileScriptId = 'turnstile-api-script'; const securityConfigLoadMessage = 'Não foi possível carregar as configurações de segurança. Atualize a página e tente novamente.'; const securityUnavailableMessage = 'Não foi possível carregar a verificação de segurança. Atualize a página e tente novamente.'; const securityConfigurationMessage = 'Verificação de segurança indisponível. Entre em contato com o administrador.'; const securityRequiredMessage = 'Conclua a verificação de segurança para continuar.'; const securityFailedMessage = 'Não foi possível validar a verificação de segurança. Atualize a página e tente novamente.'; const turnstileSiteKeyPattern = /^[0-9]x[0-9A-Za-z_-]{20,}$/; const Login = () => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [captchaToken, setCaptchaToken] = useState(''); const [error, setError] = useState(''); const [isLoading, setIsLoading] = useState(false); const [isConfigLoading, setIsConfigLoading] = useState(true); const [turnstileSiteKey, setTurnstileSiteKey] = useState(''); const [captchaRequired, setCaptchaRequired] = useState(false); const [captchaReady, setCaptchaReady] = useState(true); const captchaContainerRef = useRef(null); const captchaWidgetIdRef = useRef(null); const navigate = useNavigate(); const hasValidSiteKey = turnstileSiteKeyPattern.test(turnstileSiteKey); const captchaEnabled = Boolean(captchaRequired && hasValidSiteKey); const securityMisconfigured = captchaRequired && !hasValidSiteKey; useEffect(() => { let isMounted = true; const loadLoginConfig = async () => { try { const config = await getLoginConfig(); if (!isMounted) return; setCaptchaRequired(config.captchaRequired); setTurnstileSiteKey(config.turnstileSiteKey.trim()); setCaptchaReady(!config.captchaRequired); if (config.captchaRequired && !config.captchaConfigured) { setError(securityConfigurationMessage); } } catch { if (!isMounted) return; setCaptchaReady(false); setError(securityConfigLoadMessage); } finally { if (isMounted) { setIsConfigLoading(false); } } }; void loadLoginConfig(); return () => { isMounted = false; }; }, []); useEffect(() => { if (!hasValidSiteKey || !captchaContainerRef.current || captchaWidgetIdRef.current) return; const siteKey = turnstileSiteKey; const renderCaptcha = () => { if (!window.turnstile || !captchaContainerRef.current || captchaWidgetIdRef.current) return; try { captchaWidgetIdRef.current = window.turnstile.render(captchaContainerRef.current, { sitekey: siteKey, theme: 'dark', callback: (token) => { setCaptchaToken(token); setCaptchaReady(true); }, 'expired-callback': () => { setCaptchaToken(''); setCaptchaReady(true); }, 'error-callback': () => { setCaptchaToken(''); setCaptchaReady(false); setError(securityUnavailableMessage); }, }); setCaptchaReady(true); } catch { setCaptchaToken(''); setCaptchaReady(false); setError(securityConfigurationMessage); } }; if (window.turnstile) { renderCaptcha(); return; } const existingScript = document.getElementById(turnstileScriptId); if (existingScript) { existingScript.addEventListener('load', renderCaptcha, { once: true }); return () => existingScript.removeEventListener('load', renderCaptcha); } const script = document.createElement('script'); script.id = turnstileScriptId; script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit'; script.async = true; script.defer = true; script.addEventListener('load', renderCaptcha, { once: true }); script.addEventListener('error', () => { setCaptchaReady(false); setError(securityUnavailableMessage); }, { once: true }); document.head.appendChild(script); return () => script.removeEventListener('load', renderCaptcha); }, [hasValidSiteKey, turnstileSiteKey]); const handleLogin = async (e: React.FormEvent) => { e.preventDefault(); if (securityMisconfigured) { setError(securityConfigurationMessage); return; } if (captchaEnabled && !captchaToken) { setError(securityRequiredMessage); return; } setIsLoading(true); setError(''); try { const result = await login(email, password, captchaToken); if (result === 'success') { navigate('/graph'); } else if (result === 'captcha_failed') { setError(captchaEnabled ? securityFailedMessage : securityConfigurationMessage); if (captchaEnabled) { setCaptchaToken(''); window.turnstile?.reset(captchaWidgetIdRef.current ?? undefined); } } else if (result === 'invalid_credentials') { setError('E-mail ou senha incorretos.'); if (captchaEnabled) { setCaptchaToken(''); window.turnstile?.reset(captchaWidgetIdRef.current ?? undefined); } } else { setError('Erro ao conectar ao servidor.'); if (captchaEnabled) { setCaptchaToken(''); window.turnstile?.reset(captchaWidgetIdRef.current ?? undefined); } } } catch { setError('Erro ao conectar ao servidor.'); if (captchaEnabled) { setCaptchaToken(''); window.turnstile?.reset(captchaWidgetIdRef.current ?? undefined); } } finally { setIsLoading(false); } }; return (

Acesso Restrito

Insira suas credenciais para acessar o painel administrativo.

setEmail(e.target.value)} className="w-full bg-dark-input border border-dark-border text-dark-text rounded-xl px-4 py-3 focus:outline-none focus:border-brand-primary focus:ring-1 focus:ring-brand-primary transition-all" placeholder="admin@admin.com" required />
setPassword(e.target.value)} className="w-full bg-dark-input border border-dark-border text-dark-text rounded-xl px-4 py-3 focus:outline-none focus:border-brand-primary focus:ring-1 focus:ring-brand-primary transition-all" placeholder="••••••••" required />
{(captchaEnabled || securityMisconfigured) && (
{captchaEnabled &&
} {(securityMisconfigured || !captchaReady) && (

Verificação de segurança indisponível.

)}
)} {error &&

{error}

}
); }; export default Login;