function useNow(ms = 1000) { const [n, setN] = React.useState(new Date()); React.useEffect(() => { const t = setInterval(() => setN(new Date()), ms); return () => clearInterval(t); }, [ms]); return n; } function ClockCard() { const S = useStore(); const { me, m, toast } = useApp(); const now = useNow(); const [mode, setMode] = React.useState('office'); const k = AKH.todayIso(); const rec = (S.attendance[me.id] || {})[k]; const hol = AKH.holidayOn(k); const weekend = AKH.isWeekend(AKH.today()); const onLeave = rec && rec.status === 'leave'; const nowHM = String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0'); const worked = rec && rec.in ? Math.max(0, AKH.mins(rec.out || nowHM) - AKH.mins(rec.in)) : 0; let status = 'You haven\u2019t checked in yet'; if (hol) status = 'Holiday · ' + hol.name; else if (weekend) status = 'It\u2019s the weekend'; else if (onLeave) status = 'You\u2019re on ' + AKStore.LEAVE_TYPES[rec.type].toLowerCase() + ' today'; else if (rec && rec.out) status = 'Checked out at ' + fmt.t(rec.out); else if (rec && rec.in) status = 'Checked in at ' + fmt.t(rec.in) + ' · ' + (rec.status === 'wfh' ? 'Working from home' : 'Office'); const canIn = !hol && !weekend && !onLeave && !(rec && rec.in); const canOut = rec && rec.in && !rec.out; return (

Today · {now.toLocaleDateString('en-IN', { weekday: 'long', day: 'numeric', month: 'short' })}

{now.toLocaleTimeString('en-IN', { hour: 'numeric', minute: '2-digit', hour12: true }).replace(/\s?(am|pm)/i, '')} {String(now.getSeconds()).padStart(2, '0')} · {now.getHours() < 12 ? 'am' : 'pm'}

{status}

{rec && rec.in ? (
{Math.floor(worked / 60)}h {String(worked % 60).padStart(2, '0')}m workedTarget 9h
) : null}
{canIn ? : null} {canIn ? { AKStore.act.checkIn(me.id, mode); toast('Checked in · ' + (mode === 'wfh' ? 'working from home' : 'office')); }}>Check in : null} {canOut ? { AKStore.act.checkOut(me.id); toast('Checked out. See you tomorrow!'); }}>Check out : null}
); } function LeaveBalances({ me, compact }) { return (
{Object.entries(AKStore.LEAVE_TYPES).map(([k, label]) => { const b = me.leave[k]; const left = b.total - b.used; return (

{compact ? k : label}

{left} / {b.total}

); })}
); } function HomePage({ go }) { const S = useStore(); const { me, m } = useApp(); const t = AKH.todayIso(); const now = AKH.today(); const tasks = S.tasks.filter((x) => x.assigneeId === me.id && x.status !== 'done').sort((a, b) => a.due.localeCompare(b.due)).slice(0, 4); const hols = S.holidays.filter((h) => h.date >= t).slice(0, 3); const st = AKH.monthStats(me.id, now.getFullYear(), now.getMonth()); const notes = S.notifications.filter((n) => n.userId === me.id).sort((a, b) => b.at.localeCompare(a.at)).slice(0, 4); const c = navCounts(S, me); const waiting = (c.team || 0) + (['hr_admin', 'super_admin'].includes(me.role) ? (c['admin-employees'] || 0) + (c['admin-approvals'] || 0) : 0); const link = (label, r) => ; return ( <>

{greet()}, {firstName(me)}.

{me.designation} · {me.dept} · {me.empId}

{tasks.length === 0 ? : tasks.map((x, i) => { const over = x.due < t; return (

{x.title}

{over ? 'Overdue · ' : x.due === t ? 'Due today · ' : 'Due ' + fmt.dw(x.due) + ' · '}{AKH.user(x.byId).name}

{x.priority === 'High' ? High : null}
); })}
{waiting ? (
{waiting}

Waiting for you

Approvals and access requests

go(c.team ? 'team' : c['admin-employees'] ? 'admin-employees' : 'admin-approvals')}>Review
) : null} {hols.map((h, i) => { const d = AKH.parse(h.date); const days = Math.round((d - now) / 864e5); return (

{d.toLocaleDateString('en-IN', { month: 'short' })}

{d.getDate()}

{h.name}

{d.toLocaleDateString('en-IN', { weekday: 'long' })}{AKH.isWeekend(d) ? ' · falls on a weekend' : ''}

{days === 0 ? 'Today' : days === 1 ? 'Tomorrow' : 'in ' + days + 'd'}
); })}
{notes.length === 0 ? : notes.map((n, i) => (

{n.title}

{n.body}

{fmt.ago(n.at)}
))}
); } const CELL = { blue: ['#E7F1FD', '#1D6AE3'], grey: ['#EDF1F8', '#4A5670'], amber: ['#FDF1DC', '#8A5A00'], red: ['#FCEAE8', '#B9382F'], navy: ['#06367E', '#FFFFFF'] }; function CorrectionModal({ open, onClose, date }) { const { me, toast } = useApp(); const S = useStore(); const rec = (S.attendance[me.id] || {})[date] || {}; const [f, setF] = React.useState({ date: date || AKH.todayIso(), in: rec.in || '09:30', out: rec.out || '18:30', reason: '' }); const [err, setErr] = React.useState(''); React.useEffect(() => { const r = (S.attendance[me.id] || {})[date] || {}; setF({ date: date || AKH.iso(AKH.addDays(AKH.today(), -1)), in: r.in || '09:30', out: r.out || '18:30', reason: '' }); setErr(''); }, [open, date]); const submit = () => { if (f.date > AKH.todayIso()) return setErr('You can only correct today or earlier.'); if (AKH.mins(f.out) <= AKH.mins(f.in)) return setErr('Check-out must be after check-in.'); if (!f.reason.trim()) return setErr('Add a short reason for your manager.'); AKStore.act.requestCorrection(me.id, f); onClose(); toast('Correction sent to your manager and HR'); }; return (
setF({ ...f, date: e.target.value })} />
setF({ ...f, in: e.target.value })} /> setF({ ...f, out: e.target.value })} />