// Main App — routing, state, tweaks panel const { useState: appUseState, useEffect: appUseEffect } = React; const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "role": "reception", "theme": "light", "sidebar": "expanded", "density": "comfortable", "brand": "slate" }/*EDITMODE-END*/; function App() { // Real auth: session loaded from localStorage via api.js const initialUser = window.Auth ? window.Auth.getUser() : null; const [authed, setAuthed] = useState(!!(initialUser && window.Auth && window.Auth.getToken())); const [currentUser, setCurrentUser] = useState(initialUser); const [page, setPage] = useState('dashboard'); const [pageProps, setPageProps] = useState({}); const [showNotif, setShowNotif] = useState(false); const [showTweaks, setShowTweaks] = useState(false); const [tweaks, setTweaks] = useState(() => { const d = { ...TWEAK_DEFAULTS }; if (initialUser) d.role = initialUser.role; return d; }); // Listen for global logout (token expired etc.) useEffect(() => { const onLogout = () => { setAuthed(false); setCurrentUser(null); }; window.addEventListener('ysr:logout', onLogout); return () => window.removeEventListener('ysr:logout', onLogout); }, []); // On mount: refresh user/role from server (validates token, picks up role changes) useEffect(() => { if (!authed || !window.API) return; let alive = true; window.API.me() .then(u => { if (!alive || !u) return; setCurrentUser(u); setTweaks(t => ({ ...t, role: u.role })); if (window.Auth) { const s = window.Auth.getUser() || {}; localStorage.setItem('ysr_user', JSON.stringify({ ...s, ...u })); } }) .catch(() => {/* 401 holatini api.js logout eventi hal qiladi */}); return () => { alive = false; }; }, []); // Apply theme useEffect(() => { document.documentElement.dataset.theme = tweaks.theme; }, [tweaks.theme]); // Apply brand useEffect(() => { const styles = { slate: { primary: '#0F172A', hover: '#1E293B', soft: '#F1F5F9', secondary: '#38BDF8' }, sky: { primary: '#0EA5E9', hover: '#0284C7', soft: '#E0F2FE', secondary: '#0F172A' }, indigo: { primary: '#4F46E5', hover: '#4338CA', soft: '#EEF2FF', secondary: '#A5B4FC' }, teal: { primary: '#0D9488', hover: '#0F766E', soft: '#CCFBF1', secondary: '#5EEAD4' }, }; const s = styles[tweaks.brand] || styles.slate; document.documentElement.style.setProperty('--brand-primary', s.primary); document.documentElement.style.setProperty('--brand-primary-hover', s.hover); document.documentElement.style.setProperty('--brand-primary-soft', s.soft); document.documentElement.style.setProperty('--brand-secondary', s.secondary); }, [tweaks.brand]); // Auto-route when role changes useEffect(() => { const nav = NAV_BY_ROLE[tweaks.role] || NAV_BY_ROLE.reception; const allIds = nav.flatMap(s => s.items.map(i => i.id)); if (!allIds.includes(page)) { setPage(tweaks.role === 'doctor' ? 'doctor-dashboard' : 'dashboard'); } }, [tweaks.role]); // Tweaks panel protocol (host integration) useEffect(() => { const handler = (e) => { if (e.data?.type === '__activate_edit_mode') setShowTweaks(true); else if (e.data?.type === '__deactivate_edit_mode') setShowTweaks(false); }; window.addEventListener('message', handler); window.parent.postMessage({ type: '__edit_mode_available' }, '*'); return () => window.removeEventListener('message', handler); }, []); useEffect(() => { if (!showTweaks) { window.parent.postMessage({ type: '__edit_mode_dismissed' }, '*'); } }, [showTweaks]); // Persist tweaks const updateTweaks = (next) => { setTweaks(next); window.parent.postMessage({ type: '__edit_mode_set_keys', edits: next }, '*'); }; const nav = useCallback((p, props) => { setPage(p); setPageProps(props || {}); if (p === 'login') { if (window.API) window.API.logout(); setAuthed(false); setCurrentUser(null); setPage('dashboard'); } window.scrollTo(0, 0); }, []); const handleLogin = (user) => { setCurrentUser(user); setAuthed(true); // Switch role to actual user role setTweaks(t => ({ ...t, role: user.role })); setPage(user.role === 'doctor' ? 'doctor-dashboard' : 'dashboard'); }; if (!authed) { return ; } const meta = pageMeta(page, tweaks.role, pageProps); const me = currentUser || initialUser || {}; return ( ); } function AppInner({ page, pageProps, nav, meta, tweaks, setTweaks, me, showNotif, setShowNotif, showTweaks, setShowTweaks }) { const toast = useToast(); return (
setTweaks({ ...tweaks, sidebar: tweaks.sidebar === 'collapsed' ? 'expanded' : 'collapsed' })} theme={tweaks.theme} onToggleTheme={() => setTweaks({ ...tweaks, theme: tweaks.theme === 'dark' ? 'light' : 'dark' })} onShowNotif={() => setShowNotif(true)} onShowTweaks={() => setShowTweaks(true)} />
nav('dashboard')} key={page}> {renderPage(page, pageProps, nav, toast, me)}
setShowNotif(false)} /> setShowTweaks(false)} state={tweaks} setState={setTweaks} />
); } function renderPage(page, props, nav, toast, me) { switch (page) { case 'dashboard': return ; case 'new-visit': return ; case 'patients': return ; case 'patient-detail': return ; case 'kassa': return ; case 'debts': return ; case 'reports': return ; case 'services': return ; case 'doctors': return ; case 'users': return ; case 'audit': return ; case 'settings': return ; case 'doctor-dashboard': return ; case 'doctor-patients': return ; case 'doctor-xray': return ; default: return ; } } function pageMeta(page, role, props) { const m = { 'dashboard': { title: "Boshqaruv paneli", breadcrumbs: [ROLE_LABELS[role]] }, 'new-visit': { title: "Yangi rentgen", breadcrumbs: [ROLE_LABELS[role], "Yangi rentgen"] }, 'patients': { title: 'Bemorlar', breadcrumbs: [ROLE_LABELS[role], 'Bemorlar'] }, 'patient-detail': { title: 'Bemor', breadcrumbs: [ROLE_LABELS[role], 'Bemorlar', 'Detail'] }, 'kassa': { title: 'Kassa', breadcrumbs: [ROLE_LABELS[role], 'Kassa'] }, 'debts': { title: 'Qarzlar', breadcrumbs: [ROLE_LABELS[role], 'Kassa', 'Qarzlar'] }, 'reports': { title: 'Hisobotlar', breadcrumbs: [ROLE_LABELS[role], 'Hisobotlar'] }, 'services': { title: 'Xizmatlar', breadcrumbs: [ROLE_LABELS[role], 'Xizmatlar'] }, 'doctors': { title: 'Shifokorlar', breadcrumbs: [ROLE_LABELS[role], 'Shifokorlar'] }, 'users': { title: 'Foydalanuvchilar', breadcrumbs: [ROLE_LABELS[role], 'Foydalanuvchilar'] }, 'audit': { title: 'Audit log', breadcrumbs: [ROLE_LABELS[role], 'Audit'] }, 'settings': { title: 'Sozlamalar', breadcrumbs: [ROLE_LABELS[role], 'Sozlamalar'] }, 'doctor-dashboard': { title: "Boshqaruv paneli", breadcrumbs: ['Shifokor'] }, 'doctor-patients': { title: 'Bemorlarim', breadcrumbs: ['Shifokor', 'Bemorlarim'] }, 'doctor-xray': { title: 'Rentgen', breadcrumbs: ['Shifokor', 'Bemorlarim', 'Rentgen'] }, }; return m[page] || m.dashboard; } ReactDOM.createRoot(document.getElementById('root')).render();