// 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