// Admin web screens — Org admin (school owner) + Super admin (Gurukool internal) // ─── Sidebar nav ────────────────────────────────────────────── function AdminSidebar({ active, onNav, items, brand = 'Gurukool', sub = '', collapsed = false }) { return (
G
{!collapsed && (
{brand}
{sub &&
{sub}
}
)}
{items.map(group => (
{!collapsed &&
{group.label}
} {group.items.map(it => (
onNav?.(it.id)} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: collapsed ? '10px 12px' : '9px 12px', borderRadius: 8, cursor: 'pointer', background: active === it.id ? 'var(--accent-soft)' : 'transparent', color: active === it.id ? 'var(--accent-ink)' : 'var(--text-soft)', fontWeight: active === it.id ? 600 : 500, fontSize: 13, marginBottom: 2, }}> {!collapsed && {it.label}} {!collapsed && it.badge && {it.badge}}
))}
))}
{!collapsed && (
Ravi Menon
Principal · Admin
)}
); } // ─── Topbar ─────────────────────────────────────────────────── function AdminTopbar({ title, subtitle, actions, breadcrumb }) { return (
{breadcrumb && (
{breadcrumb.map((b, i) => ( {i > 0 && } {b} ))}
)}

{title}

{subtitle &&
{subtitle}
}
{actions}
); } // ─── KPI stat card ──────────────────────────────────────────── function KPICard({ label, value, delta, trend, icon, tone = 152 }) { const up = trend === 'up'; return (
{label}
{icon && (
)}
{value}
{delta && (
{delta} vs last week
)}
); } // ─── Inline bar chart ──────────────────────────────────────── function BarChart({ data, height = 160, color = 'var(--accent)' }) { const max = Math.max(...data.map(d => d.v)); return (
{data.map((d, i) => (
{d.highlight && (
{d.v}%
)}
{d.l}
))}
); } // ─── Line spark chart ──────────────────────────────────────── function Sparkline({ data, height = 60, color = 'var(--accent)', fill = true }) { const max = Math.max(...data), min = Math.min(...data); const range = max - min || 1; const w = 240, h = height; const points = data.map((v, i) => { const x = (i / (data.length - 1)) * w; const y = h - ((v - min) / range) * (h - 8) - 4; return [x, y]; }); const path = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p[0]} ${p[1]}`).join(' '); const area = `${path} L ${w} ${h} L 0 ${h} Z`; return ( {fill && } ); } // ─── Data table ────────────────────────────────────────────── function DataTable({ columns, rows, selectable = false }) { return ( {selectable && } {columns.map(c => ( ))} {rows.map((r, ri) => ( {selectable && } {columns.map(c => ( ))} ))}
{c.label}
{c.render ? c.render(r) : r[c.key]}
); } // ─── Org admin: Dashboard ──────────────────────────────────── function OrgDashboardScreen() { return (
{/* KPIs */}
{/* Charts row */}
Attendance · this week
Overall 93.4%
{['Week', 'Month', 'Term'].map((l,i) => (
{l}
))}
Present 1,196
Late 38
Absent 50
Credits issued · 30d
18,420
Most credits issued by Ms. Kavita Rao (Math) — 2,140.
{/* Requires attention */}

Needs attention

View all →
{[ { i: 'alert', c: 'danger', t: '3 staff absent · Math, Sci, Hindi', sub: 'Substitute needed by 10:30' }, { i: 'users', c: 'warn', t: '12 students absent 3+ days', sub: 'Contact parents recommended' }, { i: 'book', c: 'warn', t: 'Grade 7A HW completion 42%', sub: 'Below 70% threshold this week' }, { i: 'message', c: 'neutral', t: '4 parent feedback items', sub: 'Pending response over 24h' }, ].map((r,i,a) => (
{r.t}
{r.sub}
))}

Leaderboard · This week

Live
{[ { rank: 1, n: 'Grade 5A', s: 'Ms. Rao', p: 96, c: 328 }, { rank: 2, n: 'Grade 6B', s: 'Mr. Iyer', p: 94, c: 301 }, { rank: 3, n: 'Grade 4A', s: 'Mrs. Desai', p: 93, c: 278 }, { rank: 4, n: 'Grade 5B', s: 'Ms. Rao', p: 92, c: 264 }, { rank: 5, n: 'Grade 3A', s: 'Mr. Mehta', p: 91, c: 241 }, ].map((r,i,a) => (
{r.rank}
{r.n}
{r.s}
{r.p}%
{r.c} credits
))}
); } // ─── Org admin: Students list ──────────────────────────────── function OrgStudentsScreen() { const rows = [ { gr: 'GR-142', n: 'Aanya Patel', cls: 'Grade 5A', par: 'Priya Patel', att: 94, cr: 482, st: 'active' }, { gr: 'GR-143', n: 'Arnav Sharma', cls: 'Grade 5A', par: 'Rajesh Sharma', att: 91, cr: 401, st: 'active' }, { gr: 'GR-144', n: 'Diya Krishnan', cls: 'Grade 5A', par: 'Meera Krishnan', att: 97, cr: 512, st: 'active' }, { gr: 'GR-145', n: 'Ishaan Mehta', cls: 'Grade 5A', par: 'Anil Mehta', att: 85, cr: 290, st: 'warn' }, { gr: 'GR-146', n: 'Kavya Iyer', cls: 'Grade 5A', par: 'Sanjay Iyer', att: 93, cr: 388, st: 'active' }, { gr: 'GR-147', n: 'Manav Patel', cls: 'Grade 5A', par: 'Priya Patel', att: 68, cr: 210, st: 'risk' }, { gr: 'GR-148', n: 'Nisha Rao', cls: 'Grade 5A', par: 'Veena Rao', att: 96, cr: 456, st: 'active' }, { gr: 'GR-149', n: 'Rahul Shah', cls: 'Grade 5A', par: 'Kiran Shah', att: 92, cr: 402, st: 'active' }, { gr: 'GR-150', n: 'Riya Desai', cls: 'Grade 5A', par: 'Sunita Desai', att: 89, cr: 355, st: 'active' }, ]; return (
{/* Filters */}
{['Grade 5A ▾', 'All sections ▾', 'Status: All ▾', 'Attendance: All ▾'].map(l => (
{l}
))}
{/* Summary strip */}
28 students in Grade 5A · 25 active · 2 attention · 1 at risk
{r.gr} }, { key: 'n', label: 'Student', render: r => (
{r.n}
{r.par}
)}, { key: 'cls', label: 'Section' }, { key: 'att', label: 'Attendance', render: r => (
= 90 ? 'var(--gk-success)' : r.att >= 75 ? 'var(--gk-warn)' : 'var(--gk-danger)' }}/>
{r.att}%
)}, { key: 'cr', label: 'Credits', align: 'right', render: r => {r.cr} }, { key: 'st', label: 'Status', render: r => ( {r.st === 'active' ? 'Active' : r.st === 'warn' ? 'Attention' : 'At risk'} )}, { key: 'a', label: '', align: 'right', render: () => }, ]} rows={rows}/> {/* Pagination */}
Showing 1–9 of 28
{['‹', '1', '2', '3', '›'].map((p,i) => (
{p}
))}
); } // ─── Org admin: Student detail (360) ───────────────────────── function OrgStudentDetailScreen() { return (
{/* Hero */}
GR-142 · Grade 5A · Roll 12

Aanya Patel

Priya Patel (Mother) · +91 98765 43210 · Admitted Jun 2022
{[ { l: 'Attendance', v: '94%', s: 'success' }, { l: 'Credits', v: '482', s: 'accent' }, { l: 'HW done', v: '8/12', s: 'warn' }, { l: 'Behaviour', v: '4.6/5', s: 'success' }, ].map(k => (
{k.v}
{k.l}
))}
{/* Tab bar */}
{['Overview', 'Attendance', 'Academics', 'Homework', 'Behaviour', 'Credits', 'Fees', 'Documents'].map((t,i) => (
{t}
))}

Attendance · Apr

14 of 15 days

Recent activity

{[ { t: 'Marked "Very Good" in Math by Ms. Rao', when: '2h ago', i: 'star', tone: 'lime' }, { t: 'Homework verified — Science', when: '1d ago', i: 'check', tone: 'success' }, { t: 'Fractions worksheet submitted', when: '1d ago', i: 'book', tone: 'info' }, { t: 'Arrived late — 9:18 AM', when: '8 Apr', i: 'clock', tone: 'warn' }, { t: 'Earned "Attendance Master" badge', when: '1 Apr', i: 'trophy', tone: 'lime' }, ].map((r,i,a) => (
{r.t}
{r.when}
))}

Subjects

{[ { s: 'Math', g: 'A', p: 88 }, { s: 'English', g: 'A', p: 84 }, { s: 'Science', g: 'A+', p: 94 }, { s: 'Hindi', g: 'B+', p: 78 }, { s: 'Social', g: 'A', p: 86 }, ].map(s => (
{s.s}
{s.g}
))}

Quick actions

); } // ─── Org admin: Timetable builder ──────────────────────────── function OrgTimetableScreen() { const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; const periods = ['9:00', '9:45', '10:30', '10:45', '11:30', '12:15', '1:00', '1:45', '2:30']; // grid[dayIdx][periodIdx] const grid = { '0-0': { s: 'Math', t: 'Rao', c: 195 }, '0-1': { s: 'English', t: 'Mehta', c: 25 }, '0-2': { b: true }, '0-3': { s: 'Science', t: 'Desai', c: 145 }, '0-4': { s: 'Hindi', t: 'Sharma', c: 55 }, '0-5': { s: 'PE', t: 'Singh', c: 270 }, '0-6': { l: true }, '0-7': { s: 'Social', t: 'Patel', c: 35 }, '0-8': { s: 'Art', t: 'Iyer', c: 340 }, '1-0': { s: 'English', t: 'Mehta', c: 25 }, '1-1': { s: 'Math', t: 'Rao', c: 195 }, '1-2': { b: true }, '1-3': { s: 'Hindi', t: 'Sharma', c: 55 }, '1-4': { empty: true }, '1-5': { s: 'Science', t: 'Desai', c: 145 }, '1-6': { l: true }, '1-7': { s: 'Math', t: 'Rao', c: 195 }, '1-8': { s: 'Library', t: '—', c: 300 }, '2-0': { s: 'Science', t: 'Desai', c: 145 }, '2-1': { s: 'Math', t: 'Rao', c: 195, now: true }, '2-3': { s: 'English', t: 'Mehta', c: 25 }, '2-2': { b: true }, '2-6': { l: true }, }; return (
Grade 5A Term 2 · 2025-26
{periods.map((p,i) => ( ))} {days.map((d, di) => ( {periods.map((_, pi) => { const cell = grid[`${di}-${pi}`] || {}; if (cell.b) return ; if (cell.l) return ; if (cell.empty) return ; if (!cell.s) return ); })} ))}
Day P{i+1}
{p}
{d}breaklunch+; return (
{cell.s}
{cell.t}
Drag to move · click empty cell to add · right-click for options · 1 clash detected (Mr. Sharma, Tue P5)
); } // ─── Org admin: Announcements ───────────────────────────────── function OrgAnnouncementsScreen() { return (

Compose announcement

Draft