const NAV = [ { group: 'Me', items: [['home', 'Home', 'LayoutDashboard'], ['attendance', 'Attendance', 'CalendarCheck'], ['leave', 'Leave', 'CalendarDays'], ['tasks', 'Tasks', 'ListChecks'], ['performance', 'Performance', 'Target'], ['holidays', 'Holidays', 'PartyPopper']] }, { group: 'My team', roles: ['manager', 'hr_admin', 'super_admin'], items: [['team', 'Team', 'Users']] }, { group: 'Admin', roles: ['hr_admin', 'super_admin'], items: [['admin', 'Overview', 'LayoutGrid'], ['admin-employees', 'Employees', 'UserCheck'], ['admin-approvals', 'Approvals', 'Inbox'], ['admin-holidays', 'Holidays & festivals', 'CalendarHeart'], ['admin-outbox', 'Email outbox', 'Mail'], ['admin-roles', 'Roles & access', 'KeyRound', ['super_admin']]] }, ]; const routeAllowed = (route, role) => NAV.some((g) => (!g.roles || g.roles.includes(role)) && g.items.some(([k, , , r]) => k === route && (!r || r.includes(role)))); const navFor = (role) => NAV.filter((g) => !g.roles || g.roles.includes(role)).map((g) => ({ ...g, items: g.items.filter(([, , , r]) => !r || r.includes(role)) })); const ROUTE_LABEL = Object.fromEntries(NAV.flatMap((g) => g.items.map(([k, l]) => [k, l]))); function navCounts(S, me) { const t = AKH.todayIso(); const reports = S.users.filter((u) => u.managerId === me.id).map((u) => u.id); return { tasks: S.tasks.filter((x) => x.assigneeId === me.id && x.status !== 'done' && x.due <= t).length, team: S.leaves.filter((l) => l.status === 'pending' && l.approverId === me.id).length + S.corrections.filter((c) => c.status === 'pending' && reports.includes(c.userId)).length, 'admin-employees': S.users.filter((u) => u.status === 'pending').length, 'admin-approvals': S.corrections.filter((c) => c.status === 'pending').length + S.leaves.filter((l) => l.status === 'pending').length, }; } function CountDot({ n, light }) { if (!n) return null; return {n}; } function NavItem({ k, label, icon, active, count, onClick }) { const [h, setH] = React.useState(false); return ( ); } function Sidebar({ route, go }) { const S = useStore(); const { me } = useApp(); const counts = navCounts(S, me); return ( ); } function NotifPanel({ go, onClose }) { const S = useStore(); const { me, m } = useApp(); const list = S.notifications.filter((n) => n.userId === me.id).sort((a, b) => b.at.localeCompare(a.at)).slice(0, 12); return (

Notifications

{list.length === 0 ? : list.map((n) => ( ))}
); } function Bell({ go }) { const S = useStore(); const { me } = useApp(); const [open, setOpen] = React.useState(false); const unread = S.notifications.filter((n) => n.userId === me.id && !n.read).length; return ( <> {open ? <>
setOpen(false)} style={{ position: 'fixed', inset: 0, zIndex: 30 }}>
setOpen(false)} /> : null} ); } function Topbar({ go }) { const { me } = useApp(); return (
{me.location} · {new Date().toLocaleDateString('en-IN', { weekday: 'long', day: 'numeric', month: 'long' })}
Website ↗
); } const TABS = [['home', 'Home', 'LayoutDashboard'], ['attendance', 'Attendance', 'CalendarCheck'], ['tasks', 'Tasks', 'ListChecks'], ['leave', 'Leave', 'CalendarDays']]; function MoreSheet({ route, go, onClose }) { const S = useStore(); const { me } = useApp(); const counts = navCounts(S, me); return (

{me.name}

{me.designation} · {AKStore.ROLES[me.role]}

{navFor(me.role).map((g) => (

{g.group}

{g.items.map(([k, label, icon]) => { onClose(); go(k); }} />)}
))} AKStore.act.signOut()}>Sign out
); } function AppShell({ route, go, children }) { const { m } = useApp(); const [more, setMore] = React.useState(false); const scroller = React.useRef(null); React.useEffect(() => { if (scroller.current) scroller.current.scrollTop = 0; else window.scrollTo(0, 0); }, [route]); if (m) { const inTabs = TABS.some(([k]) => k === route); return (
Aarniksha Solutions

{ROUTE_LABEL[route]}

{children}
{more ? setMore(false)} /> : null}
); } return (
{children}
); } Object.assign(window, { AppShell, routeAllowed, navCounts, ROUTE_LABEL });