microtecflix/src/App.tsx

761 lines
33 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import {
Play, Shield, User, GraduationCap, ArrowRight, Lock, Mail,
Plus, CheckCircle, ChevronRight, HelpCircle, Film, Laptop, Eye, EyeOff
} from 'lucide-react';
import Navbar from './components/Navbar';
import HeroBanner from './components/HeroBanner';
import CourseCarousel from './components/CourseCarousel';
import CourseView from './components/CourseView';
import SubscriptionView from './components/SubscriptionView';
import CourseUnlockModal from './components/CourseUnlockModal';
import CertificatesTab from './components/CertificatesTab';
import ProfileView from './components/ProfileView';
import HelpView from './components/HelpView';
import { User as UserType, Course as CourseType, SubscriptionStatus } from './types';
export default function App() {
const [token, setToken] = useState<string | null>(localStorage.getItem('app_token'));
const [user, setUser] = useState<{
name: string;
email: string;
role: 'admin' | 'student';
subscriptionStatus: SubscriptionStatus;
} | null>(null);
// App routing
const [activeView, setView] = useState<string>('home'); // home, course-view, subscription, admin-dashboard, admin-content
const [selectedCourseId, setSelectedCourseId] = useState<string | null>(null);
const [unlockingCourse, setUnlockingCourse] = useState<CourseType | null>(null);
const [expandedCourseId, setExpandedCourseId] = useState<string | null>(null);
const [selectedLessonId, setSelectedLessonId] = useState<string | null>(null);
// Authentication forms
const [isRegister, setIsRegister] = useState(false);
const [isForgotPassword, setIsForgotPassword] = useState(false);
const [resetToken, setResetToken] = useState<string | null>(null);
const [loginEmail, setLoginEmail] = useState('');
const [loginPassword, setLoginPassword] = useState('');
const [showPassword, setShowPassword] = useState(false);
const [showRegPassword, setShowRegPassword] = useState(false);
const [regName, setRegName] = useState('');
const [regEmail, setRegEmail] = useState('');
const [regPassword, setRegPassword] = useState('');
const [regCpf, setRegCpf] = useState('');
const [regBirthDate, setRegBirthDate] = useState('');
const [regWhatsapp, setRegWhatsapp] = useState('');
const [authError, setAuthError] = useState<string | null>(null);
const [authSuccess, setAuthSuccess] = useState<string | null>(null);
const [authLoading, setAuthLoading] = useState(false);
// Course catalogue
const [courses, setCourses] = useState<(CourseType & { progress?: number; totalLessons?: number; completedLessons?: number })[]>([]);
const [isLoadingCourses, setIsLoadingCourses] = useState(false);
const [settings, setSettings] = useState<{ brandName?: string; brandSlogan?: string; cnpj?: string; address?: string } | null>(null);
useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
const tokenParam = urlParams.get('token');
if (window.location.pathname === '/reset-password' && tokenParam) {
setResetToken(tokenParam);
setIsForgotPassword(true);
}
fetch('/api/settings')
.then(res => res.json())
.then(data => {
setSettings(data);
if (data.brandName) {
document.title = `${data.brandName}FLIX - Plataforma de Estudos`;
}
})
.catch(err => console.error('Error fetching settings:', err));
}, []);
useEffect(() => {
if (token) {
fetchUserProfile();
}
}, [token]);
useEffect(() => {
if (user) {
fetchCourses();
}
}, [user]);
const fetchUserProfile = async () => {
try {
const res = await fetch('/api/auth/me', {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (res.ok) {
const data = await res.json();
setUser(data);
} else {
// Stale token
handleLogout();
}
} catch (err) {
console.error('Failed to load profile:', err);
}
};
const fetchCourses = async () => {
setIsLoadingCourses(true);
try {
const res = await fetch('/api/courses', {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (res.ok) {
const data = await res.json();
setCourses(data);
}
} catch (err) {
console.error('Failed to fetch courses:', err);
} finally {
setIsLoadingCourses(false);
}
};
const handleForgotPassword = async (e: React.FormEvent) => {
e.preventDefault();
setAuthError(null);
setAuthSuccess(null);
setAuthLoading(true);
try {
const res = await fetch('/api/auth/forgot-password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ identifier: loginEmail, channel: loginEmail.includes('@') ? 'email' : 'whatsapp' })
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Erro ao solicitar recuperação.');
setAuthSuccess(data.message || 'Link de recuperação enviado.');
} catch (err: any) {
setAuthError(err.message);
} finally {
setAuthLoading(false);
}
};
const handleResetPassword = async (e: React.FormEvent) => {
e.preventDefault();
if (regPassword !== regPassword.trim() || regPassword.length < 6) {
setAuthError('A senha deve ter no mínimo 6 caracteres.');
return;
}
setAuthError(null);
setAuthSuccess(null);
setAuthLoading(true);
try {
const res = await fetch('/api/auth/reset-password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: resetToken, newPassword: regPassword })
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Erro ao redefinir senha.');
setAuthSuccess(data.message || 'Senha redefinida com sucesso! Redirecionando...');
setTimeout(() => {
window.location.href = '/';
}, 3000);
} catch (err: any) {
setAuthError(err.message);
} finally {
setAuthLoading(false);
}
};
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
setAuthError(null);
setAuthLoading(true);
try {
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: loginEmail, password: loginPassword })
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || 'Erro ao efetuar login');
}
localStorage.setItem('app_token', data.token);
setToken(data.token);
setUser(data.user);
setLoginEmail('');
setLoginPassword('');
} catch (err: any) {
setAuthError(err.message);
} finally {
setAuthLoading(false);
}
};
const handleRegister = async (e: React.FormEvent) => {
e.preventDefault();
setAuthError(null);
setAuthSuccess(null);
setAuthLoading(true);
try {
const res = await fetch('/api/auth/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: regName, email: regEmail, password: regPassword, cpf: regCpf, birthDate: regBirthDate, whatsapp: regWhatsapp })
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || 'Erro ao efetuar cadastro');
}
localStorage.setItem('app_token', data.token);
setToken(data.token);
setUser(data.user);
setRegName('');
setRegEmail('');
setRegPassword('');
} catch (err: any) {
setAuthError(err.message);
} finally {
setAuthLoading(false);
}
};
const handleLogout = () => {
localStorage.removeItem('app_token');
setToken(null);
setUser(null);
setView('home');
setSelectedCourseId(null);
setExpandedCourseId(null);
setSelectedLessonId(null);
};
const handleSelectCourse = (courseId: string) => {
const selected = courses.find(c => c.id === courseId);
if (selected && (selected as any).isUnlocked === false) {
setUnlockingCourse(selected);
return;
}
if (expandedCourseId === courseId) {
setExpandedCourseId(null);
} else {
setExpandedCourseId(courseId);
}
};
// Group courses by Category
const categories = Array.from(new Set(courses.map(c => c.category))) as string[];
// Preset quick-fill logins for easy testing
const quickFill = (email: string, pass: string) => {
setLoginEmail(email);
setLoginPassword(pass);
setAuthError(null);
};
// Check if active student is blocked (overdue or cancelled)
const isBlocked = user?.subscriptionStatus === 'OVERDUE' || user?.subscriptionStatus === 'CANCELED';
return (
<div className="min-h-screen bg-[#141414] text-white flex flex-col selection:bg-[#E50914] selection:text-white">
{token && user ? (
/* --- AUTHENTICATED AREA --- */
<>
<Navbar
user={user}
activeView={activeView}
setView={(v) => { setView(v); setSelectedCourseId(null); }}
onLogout={handleLogout}
settings={settings}
/>
<main className="flex-grow p-4 md:p-8 max-w-7xl mx-auto w-full space-y-8">
{/* RENDER VIEW: HOME CATALOGUE */}
{activeView === 'home' && (
<div className="space-y-12">
{/* Hero Banner (Featured last course or first catalogue course) */}
<HeroBanner
course={courses.length > 0 ? courses[0] : null}
onPlay={handleSelectCourse}
subscriptionStatus={user.subscriptionStatus}
setView={setView}
/>
{/* Categories Carousels */}
<div className="space-y-10">
{isLoadingCourses ? (
<div className="flex justify-center py-12">
<div className="w-8 h-8 border-4 border-[#E50914] border-t-transparent rounded-full animate-spin" />
</div>
) : courses.length === 0 ? (
<div className="text-center text-zinc-500 py-12 border border-zinc-800 rounded-xl bg-[#1c1c1c]">
Nenhum curso disponível no momento.
</div>
) : (
categories.map(cat => {
const categoryCourses = courses.filter(c => c.category === cat);
const expandedCourse = categoryCourses.find(c => c.id === expandedCourseId);
return (
<div key={cat} className="space-y-4">
<CourseCarousel
title={cat}
courses={categoryCourses}
onSelectCourse={handleSelectCourse}
onUnlockCourse={(course) => setUnlockingCourse(course)}
subscriptionStatus={user.subscriptionStatus}
/>
{/* Expanded Lessons Shelf */}
{expandedCourse && expandedCourse.lessons && expandedCourse.lessons.length > 0 && (
<div className="bg-[#141414]/90 border border-white/5 rounded-2xl p-6 space-y-4 shadow-2xl relative overflow-hidden animate-fadeIn">
<div className="absolute top-0 left-0 w-2 h-full bg-[#E50914]" />
<div className="flex items-center justify-between pl-2">
<div>
<h3 className="text-sm font-bold text-[#E50914] uppercase tracking-wider">Aulas de:</h3>
<p className="text-base md:text-lg font-extrabold text-white">{expandedCourse.title}</p>
</div>
<button
onClick={() => setExpandedCourseId(null)}
className="text-zinc-400 hover:text-white p-2 rounded-full hover:bg-zinc-800/50 transition-colors text-sm font-bold"
title="Fechar"
>
</button>
</div>
<div className="flex overflow-x-auto gap-4 py-2 pl-2 scrollbar-hide snap-x scroll-smooth">
{expandedCourse.lessons.map(lesson => (
<div
key={lesson.id}
onClick={() => {
setSelectedCourseId(expandedCourse.id);
setSelectedLessonId(lesson.id);
setView('course-view');
}}
className="flex-shrink-0 w-60 md:w-64 bg-zinc-900/80 border border-white/5 rounded-xl overflow-hidden hover:border-[#E50914]/80 transition-all duration-300 group/lesson cursor-pointer snap-start"
>
<div className="relative aspect-video w-full bg-zinc-950 overflow-hidden">
{lesson.thumbnailUrl ? (
<img
src={lesson.thumbnailUrl}
alt={lesson.title}
className="w-full h-full object-cover transition-transform duration-500 group-hover/lesson:scale-105"
referrerPolicy="no-referrer"
/>
) : (
<div className="w-full h-full bg-gradient-to-br from-zinc-900 to-zinc-950 flex flex-col items-center justify-center p-4 text-center">
<span className="text-[10px] text-zinc-500 font-extrabold tracking-widest uppercase mb-1">AULA {lesson.order}</span>
<span className="text-xs text-white/40 font-bold line-clamp-2">{lesson.title}</span>
</div>
)}
<div className="absolute inset-0 bg-black/60 opacity-0 group-hover/lesson:opacity-100 transition-opacity flex items-center justify-center">
<div className="bg-[#E50914] text-white p-2.5 rounded-full transform scale-75 group-hover/lesson:scale-100 transition-all duration-300 shadow-lg">
<svg className="w-5 h-5 fill-white" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z"/>
</svg>
</div>
</div>
</div>
<div className="p-3 space-y-1">
<span className="text-[9px] font-bold text-[#E50914] tracking-wider uppercase">
Aula {lesson.order}
</span>
<h4 className="text-xs font-bold text-white group-hover/lesson:text-[#E50914] transition-colors line-clamp-2 leading-relaxed">
{lesson.title}
</h4>
</div>
</div>
))}
</div>
</div>
)}
</div>
);
})
)}
</div>
</div>
)}
{/* RENDER VIEW: COURSE STUDY ROOM */}
{activeView === 'course-view' && selectedCourseId && (
<CourseView
courseId={selectedCourseId}
token={token}
initialLessonId={selectedLessonId}
onBack={() => { setView('home'); setSelectedCourseId(null); setSelectedLessonId(null); fetchCourses(); }}
/>
)}
{/* RENDER VIEW: ACCOUNT & BILLING / SUBSCRIPTION */}
{activeView === 'subscription' && (
<SubscriptionView
user={user}
token={token}
onStatusUpdate={(newStatus) => setUser(prev => prev ? { ...prev, subscriptionStatus: newStatus } : null)}
/>
)}
{/* RENDER VIEW: CERTIFICATES */}
{activeView === 'certificates' && (
<CertificatesTab
token={token}
studentName={user.name}
/>
)}
{/* RENDER VIEW: PROFILE */}
{activeView === 'profile' && (
<ProfileView
user={user as any}
onBack={() => setView('home')}
onUpdateUser={(updated) => setUser(updated)}
/>
)}
{/* RENDER VIEW: HELP */}
{activeView === 'help' && (
<HelpView
token={token}
onBack={() => setView('home')}
/>
)}
</main>
{/* Unlock Modal */}
{unlockingCourse && (
<CourseUnlockModal
course={unlockingCourse}
user={user}
onClose={() => setUnlockingCourse(null)}
onSuccess={() => {
setUnlockingCourse(null);
fetchCourses();
fetchUserProfile();
}}
token={token || ''}
/>
)}
{/* Footer */}
<footer className="border-t border-zinc-900 bg-zinc-950 py-8 px-4 text-center text-xs text-zinc-500 space-y-2 mt-12">
<p className="font-semibold text-zinc-400">{(settings?.brandName || 'Plataforma')}FLIX - Plataforma de Cursos Profissionalizantes</p>
<p className="max-w-md mx-auto">Desenvolvido com foco em alta experiência de estudo para Windows, Pacote Office (Word, Excel, PowerPoint) e informática profissionalizante.</p>
{settings?.cnpj && (
<p className="text-[11px] text-zinc-650">CNPJ: {settings.cnpj} Endereço: {settings.address}</p>
)}
<p className="text-zinc-600">© 2026 {(settings?.brandName || 'Plataforma')}FLIX Inc. Todos os direitos reservados. Integrado oficialmente com a API Asaas.</p>
</footer>
</>
) : (
/* --- UNAUTHENTICATED PORTAL (LOGIN / REGISTER) --- */
<div className="flex-grow flex items-center justify-center p-4 md:p-8 bg-cover bg-center bg-no-repeat relative" style={{ backgroundImage: `linear-gradient(rgba(20,20,20,0.85), rgba(20,20,20,0.85)), url('https://images.unsplash.com/photo-1558494949-ef010cbdcc31?q=80&w=1200&auto=format&fit=crop')` }}>
<div className="absolute inset-0 bg-[#141414]/90 z-0" />
{/* Login Container */}
<div className="relative z-10 w-full max-w-md glass-card rounded-2xl p-6 md:p-10 space-y-6 shadow-2xl">
{/* Logo */}
<div className="flex flex-col items-center space-y-2 text-center">
<div className="bg-[#E50914] text-white p-2 rounded flex items-center justify-center shadow-lg">
<Play className="fill-white w-6 h-6" />
</div>
<h1 className="font-display font-black text-2xl tracking-tighter text-[#E50914]">
{(settings?.brandName || 'Plataforma')}<span className="text-white">FLIX</span>
</h1>
<p className="text-xs text-zinc-400 font-medium">
{settings?.brandSlogan || 'Acelere seus estudos em informática e pacote Office no estilo Netflix.'}
</p>
</div>
{authError && (
<div className="bg-red-950/40 border border-red-900/50 text-red-400 p-3 rounded-lg text-xs leading-relaxed text-center">
{authError}
</div>
)}
{authSuccess && (
<div className="bg-emerald-950/40 border border-emerald-900/50 text-emerald-400 p-3 rounded-lg text-xs leading-relaxed text-center">
{authSuccess}
</div>
)}
{resetToken ? (
/* RESET PASSWORD FORM */
<form onSubmit={handleResetPassword} className="space-y-4">
<div className="space-y-1">
<label className="text-[10px] text-zinc-400 font-bold uppercase tracking-wider">Nova Senha</label>
<div className="relative">
<Lock className="absolute left-3 top-3 w-4 h-4 text-zinc-500" />
<input
type={showPassword ? "text" : "password"}
required
value={regPassword}
onChange={(e) => setRegPassword(e.target.value)}
placeholder="Mínimo 6 caracteres"
className="w-full glass-input rounded-lg p-3 pl-10 pr-10 text-xs text-white focus:outline-none"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-3 top-3 text-zinc-500 hover:text-white transition-colors"
>
{showPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
</div>
<button
type="submit"
disabled={authLoading}
className="w-full glass-btn-primary text-white text-xs font-bold py-3 px-4 rounded-lg flex items-center justify-center space-x-1.5 cursor-pointer disabled:opacity-50"
>
<span>{authLoading ? 'Redefinindo...' : 'Salvar Nova Senha'}</span>
</button>
</form>
) : isForgotPassword ? (
/* FORGOT PASSWORD FORM */
<form onSubmit={handleForgotPassword} className="space-y-4">
<div className="space-y-1">
<label className="text-[10px] text-zinc-400 font-bold uppercase tracking-wider">E-mail ou WhatsApp (com DDI ex: 5511999999999)</label>
<div className="relative">
<Mail className="absolute left-3 top-3 w-4 h-4 text-zinc-500" />
<input
type="text"
required
value={loginEmail}
onChange={(e) => setLoginEmail(e.target.value)}
placeholder="email@exemplo.com ou 5511999999999"
className="w-full glass-input rounded-lg p-3 pl-10 text-xs text-white focus:outline-none"
/>
</div>
</div>
<button
type="submit"
disabled={authLoading}
className="w-full glass-btn-primary text-white text-xs font-bold py-3 px-4 rounded-lg flex items-center justify-center space-x-1.5 cursor-pointer disabled:opacity-50"
>
<span>{authLoading ? 'Enviando...' : 'Receber Link de Recuperação'}</span>
</button>
<p className="text-center text-xs text-zinc-500">
Lembrou a senha?{' '}
<button
type="button"
onClick={() => { setIsForgotPassword(false); setAuthError(null); setAuthSuccess(null); }}
className="text-white hover:underline font-bold"
>
Fazer Login
</button>
</p>
</form>
) : isRegister ? (
/* REGISTER FORM */
<form onSubmit={handleRegister} className="space-y-4">
<div className="space-y-1">
<label className="text-[10px] text-zinc-400 font-bold uppercase tracking-wider">Seu Nome Completo</label>
<input
type="text"
required
value={regName}
onChange={(e) => setRegName(e.target.value)}
placeholder="Seu nome"
className="w-full glass-input rounded-lg p-3 text-xs text-white focus:outline-none"
/>
</div>
<div className="space-y-1">
<label className="text-[10px] text-zinc-400 font-bold uppercase tracking-wider">E-mail para Acesso</label>
<input
type="email"
required
value={regEmail}
onChange={(e) => setRegEmail(e.target.value)}
placeholder="email@exemplo.com"
className="w-full glass-input rounded-lg p-3 text-xs text-white focus:outline-none"
/>
</div>
<div className="space-y-1">
<label className="text-[10px] text-zinc-400 font-bold uppercase tracking-wider">CPF</label>
<input
type="text"
required
value={regCpf}
onChange={(e) => setRegCpf(e.target.value)}
placeholder="000.000.000-00"
className="w-full glass-input rounded-lg p-3 text-xs text-white focus:outline-none"
/>
</div>
<div className="space-y-1">
<label className="text-[10px] text-zinc-400 font-bold uppercase tracking-wider">Data de Nascimento</label>
<input
type="date"
required
value={regBirthDate}
onChange={(e) => setRegBirthDate(e.target.value)}
className="w-full glass-input rounded-lg p-3 text-xs text-white focus:outline-none"
/>
</div>
<div className="space-y-1">
<label className="text-[10px] text-zinc-400 font-bold uppercase tracking-wider">WhatsApp</label>
<input
type="text"
required
value={regWhatsapp}
onChange={(e) => setRegWhatsapp(e.target.value)}
placeholder="(11) 99999-9999"
className="w-full glass-input rounded-lg p-3 text-xs text-white focus:outline-none"
/>
</div>
<div className="space-y-1">
<label className="text-[10px] text-zinc-400 font-bold uppercase tracking-wider">Crie uma Senha</label>
<div className="relative">
<input
type={showRegPassword ? "text" : "password"}
required
value={regPassword}
onChange={(e) => setRegPassword(e.target.value)}
placeholder="Mínimo 6 caracteres"
className="w-full glass-input rounded-lg p-3 pr-10 text-xs text-white focus:outline-none"
/>
<button
type="button"
onClick={() => setShowRegPassword(!showRegPassword)}
className="absolute right-3 top-2.5 text-zinc-500 hover:text-white transition-colors"
>
{showRegPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
</div>
<button
type="submit"
disabled={authLoading}
className="w-full glass-btn-primary text-white text-xs font-bold py-3 px-4 rounded-lg flex items-center justify-center space-x-1.5 cursor-pointer disabled:opacity-50"
>
<span>{authLoading ? 'Registrando...' : 'Criar Conta & Iniciar Teste'}</span>
<ArrowRight className="w-4 h-4" />
</button>
<p className="text-center text-xs text-zinc-500">
possui cadastro?{' '}
<button
type="button"
onClick={() => { setIsRegister(false); setAuthError(null); }}
className="text-white hover:underline font-bold"
>
Fazer Login
</button>
</p>
</form>
) : (
/* LOGIN FORM */
<form onSubmit={handleLogin} className="space-y-4">
<div className="space-y-1">
<label className="text-[10px] text-zinc-400 font-bold uppercase tracking-wider">E-mail ou WhatsApp</label>
<div className="relative">
<Mail className="absolute left-3 top-3 w-4 h-4 text-zinc-500" />
<input
type="text"
required
value={loginEmail}
onChange={(e) => setLoginEmail(e.target.value)}
placeholder="email@exemplo.com ou 5585981145217"
className="w-full glass-input rounded-lg p-3 pl-10 text-xs text-white focus:outline-none"
/>
</div>
</div>
<div className="space-y-1">
<label className="text-[10px] text-zinc-400 font-bold uppercase tracking-wider">Senha</label>
<div className="relative">
<Lock className="absolute left-3 top-3 w-4 h-4 text-zinc-500" />
<input
type={showPassword ? "text" : "password"}
required
value={loginPassword}
onChange={(e) => setLoginPassword(e.target.value)}
placeholder="Digite sua senha"
className="w-full glass-input rounded-lg p-3 pl-10 pr-10 text-xs text-white focus:outline-none"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-3 top-3 text-zinc-500 hover:text-white transition-colors animate-fade-in"
>
{showPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
</div>
<div className="flex justify-end">
<button
type="button"
onClick={() => { setIsForgotPassword(true); setAuthError(null); setAuthSuccess(null); }}
className="text-[10px] text-zinc-400 hover:text-white transition-colors"
>
Esqueci minha senha
</button>
</div>
<button
type="submit"
disabled={authLoading}
className="w-full glass-btn-primary text-white text-xs font-bold py-3 px-4 rounded-lg flex items-center justify-center space-x-1.5 cursor-pointer disabled:opacity-50"
>
<span>{authLoading ? 'Autenticando...' : 'Entrar na Plataforma'}</span>
<ArrowRight className="w-4 h-4" />
</button>
<p className="text-center text-xs text-zinc-500">
Novo por aqui?{' '}
<button
type="button"
onClick={() => { setIsRegister(true); setAuthError(null); }}
className="text-white hover:underline font-bold"
>
Registre-se gratuitamente
</button>
</p>
{/* QUICK PRESETS FOR SANDBOX DEMO */}
<div className="border-t border-white/10 pt-4 space-y-3">
<p className="text-center text-[10px] text-zinc-500 font-bold uppercase tracking-wider">Acesso de Teste Rápido (Iframe Sandbox)</p>
<div className="flex justify-center">
<button
type="button"
onClick={() => quickFill('aluno@microtecflix.com', 'aluno123')}
className="w-full glass-btn-secondary text-zinc-300 font-semibold p-2.5 rounded text-[10px] transition-colors text-center"
>
Logar como Aluno
</button>
</div>
</div>
</form>
)}
</div>
</div>
)}
</div>
);
}