Auto-deploy: 2026-01-13 13:47:12 | 1 arquivo(s) alterado(s)

This commit is contained in:
daivid.alves 2026-01-13 13:47:13 -03:00
parent 357e07063c
commit 3c54f529ce
1 changed files with 48 additions and 18 deletions

View File

@ -23,9 +23,12 @@ export const LoginView = () => {
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);
const [error, setError] = useState(''); const [error, setError] = useState('');
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [step, setStep] = useState(1); // 1: Login, 2: Verification (Visual Demo) const [step, setStep] = useState(1); // 1: Login, 2: OTP
const navigate = useNavigate(); const navigate = useNavigate();
const [otp, setOtp] = useState(['', '', '', '', '', '']);
const otpRefs = React.useRef([]);
const handleLogin = async (e) => { const handleLogin = async (e) => {
e.preventDefault(); e.preventDefault();
setIsLoading(true); setIsLoading(true);
@ -37,7 +40,7 @@ export const LoginView = () => {
setTimeout(() => { setTimeout(() => {
if (allowedPasswords.includes(password)) { if (allowedPasswords.includes(password)) {
sessionStorage.setItem('workspace_access', 'granted'); sessionStorage.setItem('workspace_access', 'granted');
setStep(2); // Muda para o passo de verificação visual setStep(2);
setIsLoading(false); setIsLoading(false);
} else { } else {
setError('Chave de acesso inválida ou expirada.'); setError('Chave de acesso inválida ou expirada.');
@ -46,6 +49,30 @@ export const LoginView = () => {
}, 800); }, 800);
}; };
const handleOtpChange = (index, value) => {
if (!/^\d*$/.test(value)) return;
const newOtp = [...otp];
newOtp[index] = value.slice(-1);
setOtp(newOtp);
// Auto focus next
if (value && index < 5) {
otpRefs.current[index + 1]?.focus();
}
// Auto submit if full
if (newOtp.every(digit => digit !== '')) {
setTimeout(() => handleFinalize(), 600);
}
};
const handleKeyDown = (index, e) => {
if (e.key === 'Backspace' && !otp[index] && index > 0) {
otpRefs.current[index - 1]?.focus();
}
};
const handleFinalize = () => { const handleFinalize = () => {
navigate('/plataforma/workspace'); navigate('/plataforma/workspace');
window.location.reload(); window.location.reload();
@ -95,7 +122,7 @@ export const LoginView = () => {
</div> </div>
{/* Right Panel - Interactive Form */} {/* Right Panel - Interactive Form */}
<div className="flex-[0.8] flex items-center justify-center p-8 bg-[#0a0a0a] relative overflow-hidden"> <div className="flex-[0.8] flex items-center justify-center p-8 bg-[var(--workspace-sec-5-dark)] relative overflow-hidden">
{/* Decorative Grid */} {/* Decorative Grid */}
<div className="absolute inset-0 opacity-[0.02] pointer-events-none" <div className="absolute inset-0 opacity-[0.02] pointer-events-none"
style={{ backgroundImage: 'radial-gradient(#fff 1px, transparent 0)', backgroundSize: '40px 40px' }} style={{ backgroundImage: 'radial-gradient(#fff 1px, transparent 0)', backgroundSize: '40px 40px' }}
@ -186,33 +213,36 @@ export const LoginView = () => {
</div> </div>
</motion.div> </motion.div>
) : ( ) : (
/* Verification Step (Image 1 reference) */ /* Step 2 - Digite o Código (Reference Image 1 style) */
<motion.div <motion.div
key="step2" key="step2"
initial={{ opacity: 0, scale: 0.9 }} initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }} animate={{ opacity: 1, scale: 1 }}
className="bg-[#0f1d2b] border border-[#22bb6c]/30 p-12 rounded-[40px] shadow-2xl shadow-emerald-950/40 flex flex-col items-center text-center max-w-[480px] w-full" className="bg-[#002137] p-16 rounded-[60px] shadow-2xl flex flex-col items-center text-center max-w-[600px] w-full border border-white/5"
> >
<div className="w-20 h-20 bg-gradient-to-br from-[#22bb6c] to-[#22c0a3] rounded-3xl flex items-center justify-center mb-8 shadow-lg shadow-emerald-500/30"> <h2 className="text-5xl font-extrabold text-white tracking-tight mb-12">Digite o Código</h2>
<ShieldCheck size={42} className="text-[#050505]" />
</div>
<h2 className="text-3xl font-black text-white italic tracking-tighter mb-4 uppercase">Chave Confirmada</h2>
<p className="text-white/50 text-sm font-medium mb-12">O ambiente de teste do Workspace está liberado para o seu perfil administrativo.</p>
{/* Decorative numeric placeholders (Image 1 style) */} <div className="flex gap-4 mb-12">
<div className="flex gap-3 mb-12"> {otp.map((digit, i) => (
{[1,2,3,4,5,6].map(i => ( <input
<div key={i} className="w-12 h-16 bg-white/5 border border-white/10 rounded-2xl flex items-center justify-center"> key={i}
<div className="w-2 h-2 bg-[#22bb6c] rounded-full animate-pulse" /> ref={el => otpRefs.current[i] = el}
</div> type="text"
maxLength={1}
value={digit}
onChange={(e) => handleOtpChange(i, e.target.value)}
onKeyDown={(e) => handleKeyDown(i, e)}
autoFocus={i === 0}
className="w-16 h-20 bg-white rounded-[20px] text-[#002137] text-4xl font-black text-center outline-none focus:ring-4 focus:ring-[#22bb6c]/50 transition-all shadow-lg"
/>
))} ))}
</div> </div>
<button <button
onClick={handleFinalize} onClick={handleFinalize}
className="w-full bg-white text-[#050505] rounded-[20px] py-4 font-black uppercase tracking-widest hover:bg-[#22bb6c] hover:text-white transition-all shadow-xl" className="px-12 py-4 bg-white text-[#002137] rounded-2xl font-black text-xl hover:bg-[#22bb6c] hover:text-white transition-all shadow-xl hover:scale-105 active:scale-95"
> >
Entrar no Sistema Enviar
</button> </button>
</motion.div> </motion.div>
)} )}