import React, { useState, useEffect } from 'react'; import Header from './components/landing/Header'; import Hero from './components/landing/Hero'; import CoachHighlight from './components/landing/CoachHighlight'; import HowItWorks from './components/landing/HowItWorks'; import Features from './components/landing/Features'; import Testimonials from './components/landing/Testimonials'; import Pricing from './components/landing/Pricing'; import FAQ from './components/landing/FAQ'; import Footer from './components/landing/Footer'; import RegistrationModal from './components/modals/RegistrationModal'; import CalculatorsModal from './components/modals/CalculatorsModal'; import Dashboard from './pages/Dashboard'; import AdminPanel from './pages/AdminPanel'; import ProfessionalDashboard from './pages/ProfessionalDashboard'; import FAQPage from './pages/FAQPage'; import { LanguageProvider } from './contexts/LanguageContext'; import { supabase } from './lib/supabase'; import { Loader2 } from 'lucide-react'; import { User } from './types'; // removed User interface definition const AppContent: React.FC = () => { const [isModalOpen, setIsModalOpen] = useState(false); const [isToolsOpen, setIsToolsOpen] = useState(false); const [authMode, setAuthMode] = useState<'login' | 'register'>('register'); const [selectedPlan, setSelectedPlan] = useState('starter'); const [currentView, setCurrentView] = useState<'home' | 'faq'>('home'); // Estado de navegação const [isCompletingProfile, setIsCompletingProfile] = useState(false); // Novo estado para controle de perfil incompleto const [user, setUser] = useState(null); const [isAdminView, setIsAdminView] = useState(false); const [isProfessionalView, setIsProfessionalView] = useState(false); const [isLoadingSession, setIsLoadingSession] = useState(true); // Check active session on load // Check active session on load useEffect(() => { let mounted = true; const initializeAuth = async () => { try { // Obter sessão inicial sem race conditions complexas const { data: { session }, error } = await supabase.auth.getSession(); if (error) { console.error("Erro ao obter sessão inicial:", error); if (mounted) setIsLoadingSession(false); return; } if (session?.user) { console.log("App: Sessão encontrada, carregando perfil..."); if (mounted) { await fetchUserProfile(session.user.id, session.user.email); } } else { console.log("App: Nenhuma sessão ativa."); if (mounted) setIsLoadingSession(false); } } catch (err) { console.error("Erro inesperado na autenticação:", err); if (mounted) setIsLoadingSession(false); } }; initializeAuth(); const { data: { subscription } } = supabase.auth.onAuthStateChange(async (event, session) => { console.log(`Auth event: ${event}`); if (!mounted) return; if (event === 'SIGNED_OUT') { setUser(null); setIsAdminView(false); setIsProfessionalView(false); setIsLoadingSession(false); setCurrentView('home'); setIsCompletingProfile(false); } else if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') { if (session?.user) { // Apenas recarrega se o usuário ainda não estiver setado ou se mudou // Mas para garantir atualização de claims/perfil, recarregamos. await fetchUserProfile(session.user.id, session.user.email); } } }); return () => { mounted = false; subscription.unsubscribe(); }; }, []); const fetchUserProfile = async (userId: string, email?: string) => { try { let profile = null; // Tentativa única de buscar perfil. O cliente Supabase já trata retries de rede. const { data, error } = await supabase .from('profiles') .select('*') .eq('id', userId) .maybeSingle(); if (error) throw error; profile = data; // Se não tem perfil ou falta telefone, solicitamos completar cadastro if (!profile || !profile.phone_e164) { console.warn("Perfil incompleto. Solicitando dados."); // Não fazemos signOut, apenas abrimos o modal para completar setIsCompletingProfile(true); setAuthMode('register'); // Visualmente irrelevante pois isCompletingProfile domina setIsModalOpen(true); // User fica null, então cai na Landing Page com Modal aberto. Perfeito. return; } // Se perfil ok, garante que flag de completar está false setIsCompletingProfile(false); const { data: entitlement } = await supabase .from('user_entitlements') .select('*') .eq('user_id', userId) .maybeSingle(); let plan: 'free' | 'pro' | 'trial' = 'free'; if (entitlement) { const code = entitlement.entitlement_code; const isActive = entitlement.is_active; // Map various paid plans to 'pro' status if (isActive && (code === 'pro' || code === 'mensal' || code === 'trimestral' || code === 'anual')) { plan = 'pro'; } else if (isActive && code === 'trial') { plan = 'trial'; } } setUser({ id: userId, name: profile.full_name || 'Usuário', email: email || profile.email || '', phone: profile.phone_e164, public_id: profile.public_id, avatar: undefined, // Column does not exist in DB, using undefined to trigger UI fallback is_admin: profile.is_admin, is_professional: profile.is_professional, plan: plan, plan_valid_until: entitlement?.valid_until }); // Auto-switch logic: // If user is professional, default to Professional View. // If user is Admin, they usually see Admin View but we might default to user dashboard for them unless they toggle. // Logic requested: "System verifies and logs him in correct panel". const loginIntent = localStorage.getItem('login_intent'); if (profile.is_professional) { setIsProfessionalView(true); } else { setIsProfessionalView(false); } // Override if explicit intent was set (though we removed the button, old intents might linger, safe to ignore or keep) if (loginIntent === 'user') { // If they explicitly wanted user view but are pro, maybe respect it? // For now, let's stick to the requested "System verifies" rule above. } } catch (error) { console.error('Error fetching profile:', error); setUser(null); } finally { setIsLoadingSession(false); } }; const handleOpenRegister = (plan: string = 'starter') => { setSelectedPlan(plan); setAuthMode('register'); setIsModalOpen(true); setIsCompletingProfile(false); }; const handleOpenLogin = (context?: 'user' | 'professional') => { // If context is professional, we can store this intent to redirect after login // For now, we'll use a simple localStorage flag or state if (context === 'professional') { localStorage.setItem('login_intent', 'professional'); } else { localStorage.setItem('login_intent', 'user'); } setAuthMode('login'); setIsModalOpen(true); setIsCompletingProfile(false); }; const handleAuthSuccess = async () => { setIsModalOpen(false); setIsCompletingProfile(false); // Force refresh profile to ensure we have latest data const { data: { session } } = await supabase.auth.getSession(); if (session?.user) { await fetchUserProfile(session.user.id, session.user.email); // Check intent const intent = localStorage.getItem('login_intent'); if (intent === 'professional') { // We can't know for sure if they are pro yet inside this function scope easily unless we use the user state which might be stale // But fetchUserProfile updates 'user'. // Ideally we wait for user state to update. // For simplicity, let's rely on the useEffect that watches 'user' or just check 'isProfessionalView' toggle inside fetchUserProfile? // Lets keep it simple: We just set the view if the profile allows it. // Actually, fetchUserProfile runs, updates User. // We can check localstorage IN fetchUserProfile. } localStorage.removeItem('login_intent'); } }; const handleLogout = async () => { await supabase.auth.signOut(); setUser(null); setIsAdminView(false); }; const toggleAdminView = () => { if (user?.is_admin) { setIsAdminView(!isAdminView); } }; // Helper function for navigating const handleNavigate = (view: 'home' | 'faq') => { setCurrentView(view); window.scrollTo({ top: 0, behavior: 'smooth' }); }; if (isLoadingSession) { return (
); } // Rota Admin if (user && isAdminView && user.is_admin) { return ; } // Rota Profissional if (user && isProfessionalView) { return setIsProfessionalView(false)} onLogout={handleLogout} />; } // Rota Dashboard Usuário if (user) { return ( setIsProfessionalView(true)} /> ); } // Rota Pública (Landing Page ou FAQ Page) return (
handleOpenRegister('starter')} onLogin={handleOpenLogin} onOpenTools={() => setIsToolsOpen(true)} onNavigate={handleNavigate} // Passa navegação />
{currentView === 'home' ? ( <> handleOpenRegister('starter')} /> handleOpenRegister('starter')} /> ) : ( handleNavigate('home')} /> )}
handleOpenRegister('starter')} onNavigate={handleNavigate} // Passa navegação /> setIsModalOpen(false)} plan={selectedPlan} mode={authMode} isCompletingProfile={isCompletingProfile} // Passa o estado de completar perfil onSuccess={handleAuthSuccess} /> setIsToolsOpen(false)} />
); }; const App: React.FC = () => { return ( ); }; export default App;