Load Turnstile site key at runtime
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 54s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 54s
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Lock } from 'lucide-react';
|
||||
import { login } from '../dataService';
|
||||
import { getLoginConfig, login } from '../dataService';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -21,8 +21,8 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
const turnstileSiteKey = import.meta.env.VITE_TURNSTILE_SITE_KEY;
|
||||
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.';
|
||||
@@ -34,11 +34,47 @@ const Login = () => {
|
||||
const [captchaToken, setCaptchaToken] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [captchaReady, setCaptchaReady] = useState(!turnstileSiteKey);
|
||||
const [isConfigLoading, setIsConfigLoading] = useState(true);
|
||||
const [turnstileSiteKey, setTurnstileSiteKey] = useState('');
|
||||
const [captchaRequired, setCaptchaRequired] = useState(false);
|
||||
const [captchaReady, setCaptchaReady] = useState(true);
|
||||
const captchaContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
const captchaWidgetIdRef = useRef<string | null>(null);
|
||||
const navigate = useNavigate();
|
||||
const captchaEnabled = Boolean(turnstileSiteKey);
|
||||
const captchaEnabled = Boolean(captchaRequired && turnstileSiteKey);
|
||||
const securityMisconfigured = captchaRequired && !turnstileSiteKey;
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
const loadLoginConfig = async () => {
|
||||
try {
|
||||
const config = await getLoginConfig();
|
||||
if (!isMounted) return;
|
||||
|
||||
setCaptchaRequired(config.captchaRequired);
|
||||
setTurnstileSiteKey(config.turnstileSiteKey);
|
||||
setCaptchaReady(!config.captchaRequired);
|
||||
if (config.captchaRequired && !config.turnstileSiteKey) {
|
||||
setError(securityConfigurationMessage);
|
||||
}
|
||||
} catch {
|
||||
if (!isMounted) return;
|
||||
setCaptchaReady(false);
|
||||
setError(securityConfigLoadMessage);
|
||||
} finally {
|
||||
if (isMounted) {
|
||||
setIsConfigLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void loadLoginConfig();
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!turnstileSiteKey || !captchaContainerRef.current || captchaWidgetIdRef.current) return;
|
||||
@@ -92,10 +128,15 @@ const Login = () => {
|
||||
document.head.appendChild(script);
|
||||
|
||||
return () => script.removeEventListener('load', renderCaptcha);
|
||||
}, [captchaEnabled]);
|
||||
}, [turnstileSiteKey]);
|
||||
|
||||
const handleLogin = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (securityMisconfigured) {
|
||||
setError(securityConfigurationMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (captchaEnabled && !captchaToken) {
|
||||
setError(securityRequiredMessage);
|
||||
return;
|
||||
@@ -173,10 +214,10 @@ const Login = () => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{captchaEnabled && (
|
||||
{(captchaEnabled || securityMisconfigured) && (
|
||||
<div className="min-h-[70px] rounded-xl border border-dark-border bg-dark-input/60 p-3">
|
||||
<div ref={captchaContainerRef} className="flex justify-center" />
|
||||
{!captchaReady && (
|
||||
{captchaEnabled && <div ref={captchaContainerRef} className="flex justify-center" />}
|
||||
{(securityMisconfigured || !captchaReady) && (
|
||||
<p className="mt-2 text-center text-xs font-medium text-red-400">Verificação de segurança indisponível.</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -186,10 +227,10 @@ const Login = () => {
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading || !captchaReady || (captchaEnabled && !captchaToken)}
|
||||
disabled={isLoading || isConfigLoading || securityMisconfigured || !captchaReady || (captchaEnabled && !captchaToken)}
|
||||
className="w-full bg-brand-primary hover:bg-opacity-90 hover:scale-[1.02] active:scale-[0.98] text-zinc-900 font-bold py-3 rounded-xl transition-all duration-200 disabled:opacity-50 disabled:hover:scale-100 disabled:active:scale-100 mt-4 cursor-pointer"
|
||||
>
|
||||
{isLoading ? 'Entrando...' : 'Entrar'}
|
||||
{isLoading || isConfigLoading ? 'Entrando...' : 'Entrar'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user