import { useState, useEffect } from 'react' import { adminApi } from './api' import AdminDashboard from './AdminDashboard' import CohortsView from './CohortsView' import StudentsView from './StudentsView' import styles from './Admin.module.css' // Instructor/Admin portal — clearly separate from the student experience (/admin route, // separate rn_admin session cookie, separate login). A student session cannot reach any of // these views or their underlying /api/admin/* routes — see // docs/PHASE2B_ADMIN_AND_PLATFORM_DATA.md §10. export default function AdminPortal() { const [authed, setAuthed] = useState(null) // null = checking, false = need login, true = in const [view, setView] = useState('dashboard') useEffect(() => { adminApi.whoami().then(() => setAuthed(true)).catch(() => setAuthed(false)) }, []) if (authed === null) return null if (!authed) return setAuthed(true)} /> return (
⚙ RootNode Admin
{view === 'dashboard' && } {view === 'cohorts' && } {view === 'students' && }
) } function AdminLogin({ onLogin }) { const [password, setPassword] = useState('') const [error, setError] = useState(null) const [busy, setBusy] = useState(false) const submit = async (e) => { e.preventDefault() setBusy(true); setError(null) try { await adminApi.login(password); onLogin() } catch (e) { setError('Incorrect password.') } finally { setBusy(false) } } return (
⚙ RootNode Admin

Instructor sign-in. Not connected to student accounts.

{error &&
{error}
} setPassword(e.target.value)} autoFocus />
) }