// ============================================================ // JuFlow — Main App (state + routing) // ============================================================ const { useState: useStApp, useReducer, useCallback: useCbApp } = React; const UAPP = window.JFUtils; const App = () => { // ── Auth ────────────────────────────────────────────── const [loggedIn, setLoggedIn] = useStApp(false); // ── Navigation ──────────────────────────────────────── const [page, setPage] = useStApp('dashboard'); const [sidebarCollapsed, setSidebarCollapsed] = useStApp(false); const [mobileMenuOpen, setMobileMenuOpen] = useStApp(false); const isMobile = useIsMobile(900); // ── Data (mutable state) ────────────────────────────── const [appointments, setAppointments] = useStApp(window.JF.APPOINTMENTS); const [clients, setClients] = useStApp(window.JF.CLIENTS); // ── Agenda state ────────────────────────────────────── const [agendaDate, setAgendaDate] = useStApp(new Date(window.JF.TODAY)); const [agendaView, setAgendaView] = useStApp('daily'); // ── Modals ──────────────────────────────────────────── const [apptModal, setApptModal] = useStApp(null); // { type:'new'|'detail', data:{} } const [clientDetail, setClientDetail] = useStApp(null); // client object // ── Toasts ──────────────────────────────────────────── const [toasts, setToasts] = useStApp([]); const addToast = useCbApp((message, type = 'success') => { const id = Date.now() + Math.random(); setToasts(prev => [...prev, { id, message, type }]); setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), 3500); }, []); // ── Appointment actions ─────────────────────────────── const handleSaveAppt = (newAppt) => { setAppointments(prev => { const exists = prev.find(a => a.id === newAppt.id); if (exists) return prev.map(a => a.id === newAppt.id ? newAppt : a); return [...prev, newAppt]; }); }; const handleCancelAppt = (apptId) => { setAppointments(prev => prev.map(a => a.id === apptId ? { ...a, status:'cancelled' } : a)); }; // ── Client actions ──────────────────────────────────── const handleSaveClient = (newClient) => { setClients(prev => { const exists = prev.find(c => c.id === newClient.id); if (exists) return prev.map(c => c.id === newClient.id ? newClient : c); return [...prev, newClient]; }); }; // ── Navigation helpers ──────────────────────────────── const openNewAppt = (initial = {}) => setApptModal({ type:'new', data:initial }); const openApptDetail = (appt) => setApptModal({ type:'detail', data:appt }); const closeApptModal = () => setApptModal(null); const navigateTo = (p) => { setPage(p); setClientDetail(null); setApptModal(null); setMobileMenuOpen(false); }; // ── Login screen ────────────────────────────────────── if (!loggedIn) { return ( <> setLoggedIn(true)} /> ); } // ── Main layout ─────────────────────────────────────── const renderPage = () => { switch (page) { case 'dashboard': return openNewAppt()} />; case 'agenda': return ( ); case 'clientes': return ( ); case 'atendimentos': return ( ); case 'servicos': return ; case 'profissionais': return ; case 'financeiro': return ; case 'marketing': return ; case 'relatorios': return ; case 'configuracoes': return ; default: return openNewAppt()} />; } }; return (
{/* Sidebar */} setSidebarCollapsed(c => !c)} isMobile={isMobile} mobileOpen={mobileMenuOpen} onMobileClose={() => setMobileMenuOpen(false)} /> {/* Main content */}
{/* Header */}
setLoggedIn(false)} onMenuOpen={() => setMobileMenuOpen(true)} isMobile={isMobile} /> {/* Page content */}
{renderPage()}
{/* Client detail overlay */} {clientDetail && ( setClientDetail(null)} onNewAppt={openNewAppt} addToast={addToast} /> )} {/* Appointment modals */} {apptModal?.type === 'detail' && ( setApptModal({ type:'new', data:appt })} onCancel={handleCancelAppt} addToast={addToast} /> )} {apptModal?.type === 'new' && ( )} {/* Toasts */}
); }; // ── Mount ──────────────────────────────────────────────── const root = ReactDOM.createRoot(document.getElementById('root')); root.render();