const { useState: useStateV, useMemo: useMemoV, useEffect: useEffectV } = React; /* ============================================================ DASHBOARD VIEW ============================================================ */ function DashboardView() { return ( <>
); } /* ============================================================ TIMETABLE VIEW ============================================================ */ function TimetableView() { return ( <> } /> ); } function WeekGrid() { const days = ['Mon','Tue','Wed','Thu','Fri']; const hours = ['08','09','10','11','12','13','14','15','16','17','18']; const slots = [ { day:1, h:8, span:1.5, code:'ELEC-DB', name:'Electronics Lab', type:'lab', tone:'oklch(0.94 0.05 240)', stroke:'oklch(0.5 0.12 240)' }, { day:3, h:10.25, span:1.75, code:'STAT-DC', name:'Math. Statistics — lecture', type:'lecture', tone:'oklch(0.94 0.05 25)', stroke:'oklch(0.5 0.15 25)' }, { day:3, h:12.25, span:1.75, code:'STAT-DC', name:'Math. Statistics — lab', type:'lab', tone:'oklch(0.93 0.04 145)', stroke:'oklch(0.4 0.1 145)' }, { day:0, h:11.75, span:1.5, code:'PY-2', name:'Python — Data Mining', type:'lab', tone:'oklch(0.93 0.04 145)', stroke:'oklch(0.4 0.1 145)' }, { day:4, h:9, span:1.5, code:'OR-DC', name:'Operations Research', type:'lecture', tone:'oklch(0.94 0.05 25)', stroke:'oklch(0.5 0.15 25)' }, { day:1, h:13.5, span:1.5, code:'DIP-DB', name:'Diploma project', type:'project', tone:'oklch(0.94 0.04 290)', stroke:'oklch(0.45 0.12 290)' }, ]; return ( } action={Even week · May 25 — 31} >Weekly view
{days.map((d, i) => (
{d} {25+i}
))} {hours.map((h, hi) => (
{h}:00
{days.map((_, di) => (
))}
))}
{/* overlay blocks */}
{[0,1,2,3,4].map(di => (
{slots.filter(s=>s.day===di).map((s, j) => (
{s.name}
{s.code} · {s.type}
))}
))}
); } /* ============================================================ GRADES VIEW ============================================================ */ const gradesData = [ { code:'STAT-DC', name:'Mathematical Statistics', ects:5, grade:null, status:'in progress', teacher:'Dr. K. Miller' }, { code:'PY-2', name:'Python — Data Mining', ects:4, grade:null, status:'in progress', teacher:'Dr. M. Collins' }, { code:'ELEC-DB', name:'Electronics Laboratory', ects:3, grade:null, status:'in progress', teacher:'J. Sawyer, MSc' }, { code:'OR-DC', name:'Operations Research', ects:4, grade:null, status:'in progress', teacher:'Dr. B. Jenkins' }, { code:'NET-DC', name:'Computer Networks', ects:4, grade:null, status:'in progress', teacher:'Dr. R. Hayes' }, { code:'DIP-DB', name:'Diploma Project Seminar', ects:2, grade:null, status:'in progress', teacher:'Prof. A. Novak' }, { code:'SE-LE', name:'Software Engineering', ects:5, grade:4.5, status:'completed', teacher:'Dr. K. Adams' }, { code:'DB-2', name:'Databases II', ects:5, grade:5.0, status:'completed', teacher:'Dr. P. Winters' }, { code:'ALG-DC', name:'Algorithms & Data Structures', ects:6, grade:4.0, status:'completed', teacher:'Prof. T. Brooks' }, { code:'NUM-DC', name:'Numerical Methods', ects:3, grade:4.5, status:'completed', teacher:'Dr. E. Fontaine' }, { code:'OS-LE', name:'Operating Systems', ects:5, grade:3.5, status:'completed', teacher:'Prof. A. Novak' }, ]; function GradesView() { const completed = gradesData.filter(g=>g.status==='completed'); const avg = completed.reduce((s,g)=>s+g.grade*g.ects,0) / completed.reduce((s,g)=>s+g.ects,0); const ectsDone = completed.reduce((s,g)=>s+g.ects,0); return ( <>
s+g.ects,0)} this semester`}/>
}>Course list
CodeCourseECTSGradeStatus
{gradesData.map((g, i) => (
{g.code}
{g.name}
{g.teacher}
{g.ects} {g.grade ?? '—'} {g.status}
))}
); } function Stat({ label, big, sub }) { return (
{label}
{big}
{sub}
); } /* ============================================================ COURSES VIEW ============================================================ */ function CoursesView() { const courses = gradesData.filter(g=>g.status==='in progress').map((g,i) => ({ ...g, progress: [62, 48, 70, 34, 55, 40][i] || 50, next: ['lab — Tuesday','lecture — Wednesday','lab — Friday','lecture — Thursday','lab — Monday','seminar — Friday'][i] || '—' })); return ( <>
{courses.map((c, i) => (
{c.code}·{c.ects} ECTS

{c.name}

{c.teacher}
Semester progress{c.progress}%
Next: {c.next}
))}
); } /* ============================================================ FINANCE VIEW ============================================================ */ function FinanceView() { const tx = [ { date:'May 14', label:'Tuition · spring semester — installment IV', amount:-720, status:'paid' }, { date:'May 05', label:'Student ID — renewal', amount:-22, status:'paid' }, { date:'Apr 14', label:'Tuition · spring semester — installment III', amount:-720, status:'paid' }, { date:'Apr 02', label:'Merit scholarship', amount:1100, status:'received' }, { date:'Mar 14', label:'Tuition · spring semester — installment II', amount:-720, status:'paid' }, { date:'Feb 14', label:'Tuition · spring semester — installment I', amount:-720, status:'paid' }, ]; return ( <> Pay now } />
Balance due
720.00 EUR
due · installment V June 14
Personal account number (IBAN)
EU00 0000 1111 2222 3333 4444
Semester payment progress {[ ['Inst. I', 720, 720], ['Inst. II', 720, 720], ['Inst. III', 720, 720], ['Inst. IV', 720, 720], ['Inst. V', 720, 0], ].map(([label, total, paid], i) => (
{label}
{paid===total ? 'paid' : `${total} EUR`}
))}
}>Transaction history
{tx.map((t, i) => (
{t.date} {t.label} 0 ? 'var(--green)' : 'var(--ink)' }}> {t.amount>0?'+':''}{t.amount.toFixed(2)} EUR 0?'accent':'neutral'} size="xs">{t.status}
))}
); } /* ============================================================ PROFILE VIEW ============================================================ */ function ProfileView() { return ( <>
{me.name}
{me.programs[0]} · {me.programs[1]}
ID {me.album}
Contact details {[ ['School e-mail', me.email, true], ['Personal e-mail', 'name.surname@example.com', false], ['Phone', '+00 000 ··· 000', false], ['Mailing address', '12 Example St., Apt. 4, 00-000 City', false], ].map(([k,v,locked], i) => (
{k} {v} {locked ? locked : }
))}
Notification preferences {[ ['New announcements from lecturers', true, true], ['Upcoming midterms and exams', true, true], ['Timetable changes', true, true], ['School news', false, true], ['Push notifications in the mobile app', true, false], ].map(([label, emailOn, pushOn], i) => (
{label}
))}
); } function Toggle({ on, label }) { const [v, setV] = useStateV(on); return ( ); } /* ============================================================ ANNOUNCEMENTS VIEW ============================================================ */ function AnnouncementsView() { return ( <> ); } /* ============================================================ DOCUMENTS VIEW ============================================================ */ function DocumentsView() { const [q, setQ] = useStateV(''); const filteredGroups = fileGroups.map(g => ({ ...g, items: g.items.filter(f => f.name.toLowerCase().includes(q.toLowerCase())) })).filter(g => g.items.length>0); return ( <>
setQ(e.target.value)} placeholder="Search files by name…" style={{ background:'transparent', border:0, outline:'none', flex:1, fontSize:13.5, color:'var(--ink)', minWidth:0 }}/> {q && }
{['All','PDF','PPT','Code'].map((l, i) => ( ))}
{filteredGroups.map((g, i) => )} {filteredGroups.length===0 && (
No files match "{q}".
)}
); } /* ============================================================ ENROLLMENT VIEW ============================================================ */ function EnrollmentView() { const courses = [ { id:1, code:'ML-DC', name:'Machine Learning', ects:5, slots:8, total:24, teacher:'Dr. M. Collins', tone:'green' }, { id:2, code:'CRY-DC', name:'Applied Cryptography', ects:4, slots:2, total:18, teacher:'Dr. P. Winters', tone:'warn' }, { id:3, code:'WEB-DC', name:'Web Applications — Vue/Next', ects:4, slots:15, total:24, teacher:'P. Cook, MSc', tone:'green' }, { id:4, code:'UX-DC', name:'UX/UI Design', ects:3, slots:0, total:20, teacher:'A. Ross, MSc', tone:'red' }, { id:5, code:'CV-DC', name:'Computer Vision', ects:5, slots:6, total:18, teacher:'Prof. T. Brooks', tone:'green' }, ]; const [selected, setSelected] = useStateV(new Set([1,3])); const toggle = (id) => { const n = new Set(selected); n.has(id) ? n.delete(id) : n.add(id); setSelected(n); }; const selectedCourses = courses.filter(c=>selected.has(c.id)); const ects = selectedCourses.reduce((s,c)=>s+c.ects,0); return ( <>
{ects} / 12 ECTS
{selectedCourses.length} courses selected
} /> } action={} >Available courses
{courses.map(c => { const isSel = selected.has(c.id); const full = c.slots===0; const slotsTone = c.tone==='red' ? 'warn' : c.tone==='warn' ? 'info' : 'accent'; return (
!full && toggle(c.id)}> {isSel && }
{c.code} {c.name}
{c.teacher} · {c.ects} ECTS
{full ? 'full' : `${c.slots}/${c.total} open`}
); })}
); } /* ============================================================ APP ============================================================ */ function App() { const [active, setActive] = useStateV('dashboard'); const [menuOpen, setMenuOpen] = useStateV(false); useEffectV(()=> { window.scrollTo({ top:0, behavior:'smooth' }); }, [active]); const select = (id) => { setActive(id); setMenuOpen(false); }; const views = { dashboard: , timetable: , grades: , courses: , finance: , profile: , announcements: , documents: , enrollment: , }; return (
setMenuOpen(false)}/>
setMenuOpen(false)}>
setMenuOpen(true)} onSelect={select}/>
{views[active] || }
School · student portal · v3.0 redesign · © 2026
); } ReactDOM.createRoot(document.getElementById('root')).render();