/* ================================================================== Overview → Dashboard ------------------------------------------------------------------ The landing screen. Three headline tiles, then enrolment by wing, the staff check-in ring, and the school calendar. Every figure is read from the two live databases — the Cockpit's own Postgres and the Ledger (finance) — via /admin/cockpit/dashboard and /admin/cockpit/finance. Where a subsystem has recorded nothing, the tile says so rather than printing a zero that reads like a measurement. ================================================================== */ const DashScreen = ({ setScreen }) => { const CX = window.CX; const state = CX.useCockpitData("/admin/cockpit/dashboard", { pollMs: 120000 }); const money = CX.useCockpitData("/admin/cockpit/finance", { pollMs: 300000 }); const [monthOffset, setMonthOffset] = useState(0); const d = state.data; const user = window.APP.CURRENT_USER; const school = window.APP.CURRENT_SCHOOL; const firstName = user?.name?.split(/\s+/)[0]; const hour = new Date().getHours(); const partOfDay = hour < 12 ? "morning" : hour < 17 ? "afternoon" : "evening"; const dateLabel = new Date().toLocaleDateString("en-IN", { weekday: "long", day: "numeric", month: "long", year: "numeric", }).toUpperCase(); const fin = money.data; return (
setScreen("announcements")}> New announcement } /> {d && ( <> {/* ---- Headline tiles ---- */}
setScreen("staff-attendance")} actionLabel="Open staff attendance" footNote={ d.staff.checkInsRecorded ? `${d.staff.present} present · ${d.staff.onLeave} on leave · ${d.staff.unmarked} unmarked` : `${d.staff.onLeave} on approved leave · no check-ins recorded today` } action={Today} /> setScreen("students")} actionLabel="Open students" footNote={`${CX.num(d.students.boarders)} boarders · ${CX.num(d.students.dayScholars)} day scholars`} action={Roster} /> {/* Finance is a separate deployment; the tile carries its own connection state rather than silently showing nothing. */} {money.loading && !fin ? (
) : fin?.connected ? ( = 0 ? "↑" : "↓"} ${Math.abs(fin.collection.deltaPct)}% vs last month` : null} deltaTone={fin.collection.deltaPct >= 0 ? "up" : "down"} onAction={() => setScreen("finance")} actionLabel="Open finance" footNote={`${CX.money(fin.collection.allTime)} all time · ${CX.num(fin.collection.payments)} receipts`} action={Ledger} /> ) : ( )}
{/* ---- Wing enrolment · staff ring · calendar ---- */}
Enrolment by Wing
{d.wings.map((w) => (
{w.label} · {CX.num(w.students)}
))}
{CX.num(d.students.total)}
{CX.num(d.students.boarders)} boarders · {CX.num(d.students.dayScholars)} day scholars
({ label: w.label, value: CX.num(w.students), heightPct: w.heightPct, color: w.color, title: `${w.label}: ${w.students} students`, }))}/>
Wings group the school's classes by level
Staff Check-in
Today
{[ { label: "Checked in", n: d.staff.present, color: "var(--green-solid)" }, { label: "On approved leave", n: d.staff.onLeave, color: "var(--amber-solid)" }, { label: "No record today", n: d.staff.unmarked, color: "var(--grey-solid)" }, ].map((r) => (
{r.label} {r.n}/{d.staff.total}
))}
{!d.staff.checkInsRecorded && (
Check-ins come from the Teacher app. Nothing has been recorded for today yet — this is not the same as everyone being absent.
)}
{(d.calendar.upcoming || []).length === 0 && ( )} {(d.calendar.upcoming || []).map((e, i) => { const dt = new Date(e.date + "T00:00:00"); return (
{dt.getDate()} {dt.toLocaleDateString("en-IN", { month: "short" }).toUpperCase()}
{e.title}
{e.sub}
{e.past && Past}
); })}
)}
); }; window.CockpitDashboard = DashScreen;