import { useEffect, useState } from 'react' import { Link, useParams, useSearchParams } from 'react-router-dom' import { fetchTeacherDashboard, isTeacherDashboardApiEnabled, type TeacherDashboardPayload, } from '../../api/teacherSession' import { useSchoolYearOptions } from '../../hooks/useSchoolYearOptions' import { TeacherShell } from './TeacherShell' import { useTeacherResource } from './useTeacherResource' type TrashRow = { id: number; subject?: string; created_at?: string } type TrashPayload = { trashedMessages?: TrashRow[] } type MsgRow = { id: number; sender_id?: string | number; subject?: string; created_at?: string } type InboxPayload = { receivedMessages?: MsgRow[] } type SentPayload = { sentMessages?: MsgRow[] } type TeacherMessagePayload = { message?: Record; thread?: unknown[] } function appendSchoolYearParam(path: string, schoolYear: string): string { if (!schoolYear) return path const [base, hash = ''] = path.split('#', 2) const [pathname, query = ''] = base.split('?', 2) const params = new URLSearchParams(query) if (!params.get('school_year')) params.set('school_year', schoolYear) const next = `${pathname}?${params.toString()}` return hash ? `${next}#${hash}` : next } /** Every `/app/teacher/*` route so nothing is hidden behind the slim top nav alone. */ const TEACHER_PAGE_GROUPS = [ { heading: 'Overview', links: [ { label: 'Dashboard', to: '/app/teacher_dashboard' }, { label: 'No classes (notice)', to: '/app/teacher/no-classes' }, { label: 'Select semester', to: '/app/teacher/select-semester' }, ], }, { heading: 'Classes & attendance', links: [ { label: 'Class list', to: '/app/teacher/class-view' }, { label: 'Attendance', to: '/app/teacher/showupdate-attendance' }, { label: 'Absence / vacation', to: '/app/teacher/absence-vacation' }, ], }, { heading: 'Grades & coursework', links: [ { label: 'Scores', to: '/app/teacher/scores' }, { label: 'Homework list', to: '/app/teacher/homework-list' }, { label: 'Add homework', to: '/app/teacher/add-homework' }, { label: 'Add quiz', to: '/app/teacher/add-quiz' }, { label: 'Add quiz column', to: '/app/teacher/add-quiz-column-form' }, { label: 'Add midterm exam', to: '/app/teacher/add-midterm-exam' }, { label: 'Add final exam', to: '/app/teacher/add-final-exam' }, { label: 'Add participation', to: '/app/teacher/add-participation' }, { label: 'Add project', to: '/app/teacher/add-project' }, { label: 'Teacher assignments', to: '/app/teacher/teacher-assignment' }, { label: 'Exam drafts', to: '/app/teacher/exam-drafts' }, ], }, { heading: 'Class progress', links: [ { label: 'Submit progress', to: '/app/teacher/class-progress-submit' }, { label: 'Progress history', to: '/app/teacher/class-progress-history' }, { label: 'View progress', to: '/app/teacher/class-progress-view' }, ], }, { heading: 'Competitions', links: [ { label: 'Competition scores', to: '/app/teacher/competition-scores', hint: 'Score entry uses /app/teacher/competition-scores/:competitionId', }, ], }, { heading: 'Calendar', links: [{ label: 'Calendar', to: '/app/teacher/calendar' }], }, { heading: 'Messages', links: [ { label: 'Inbox', to: '/app/teacher/inbox' }, { label: 'Sent', to: '/app/teacher/sent' }, { label: 'Drafts', to: '/app/teacher/drafts' }, { label: 'Trash', to: '/app/teacher/trash' }, { label: 'Message thread', to: '/app/teacher/inbox', hint: '/app/teacher/messages/:messageId — open “View” from inbox.', }, ], }, { heading: 'Help', links: [ { label: 'Contact us', to: '/app/teacher/teacher-contactus' }, { label: 'Support', to: '/app/teacher/teacher-support' }, ], }, ] as const /** `landing_page/teacher_dashboard` — optional `GET /api/v1/teacher/dashboard` (JWT) plus full route index. */ export function TeacherDashboardPage() { const apiEnabled = isTeacherDashboardApiEnabled() const [dash, setDash] = useState(null) const [dashLoading, setDashLoading] = useState(apiEnabled) useEffect(() => { if (!apiEnabled) return let cancelled = false fetchTeacherDashboard() .then((d) => { if (!cancelled) setDash(d) }) .catch(() => { if (!cancelled) setDash(null) }) .finally(() => { if (!cancelled) setDashLoading(false) }) return () => { cancelled = true } }, [apiEnabled]) const termLine = dash?.school_year || dash?.semester ? [dash.school_year, dash.semester].filter(Boolean).join(' · ') : null const defaultSubtitle = 'All teacher portal screens are listed below. The top bar shows shortcuts only.' return ( {dashLoading ?

Loading dashboard…

: null} {termLine ?

{termLine}

: null} {dash?.counts && Object.keys(dash.counts).length > 0 ? (
{Object.entries(dash.counts).map(([k, v]) => (
{k.replace(/_/g, ' ')}
{v != null && v !== '' ? String(v) : '—'}
))}
) : null} {dash?.announcements && dash.announcements.length > 0 ? (
{dash.announcements.map((a, i) => (
{a.title ?
{a.title}
: null} {a.body ?
{a.body}
: null}
))}
) : null}

CI view browser:{' '} /app/browse (registry links now map competition score views to this area).

{TEACHER_PAGE_GROUPS.map((group) => (

{group.heading}

{group.links.map((item) => (
{item.label} {'hint' in item && item.hint ? (

{item.hint}

) : null}
))}
))}
) } /** `teacher/no_classes.php` */ export function TeacherNoClassesPage() { const { data, loading, error } = useTeacherResource<{ message?: string }>('/no-classes') const msg = data?.message return (

If you believe this is an error, contact the school office.

) } /** `teacher/select_semester.php` */ export function TeacherSelectSemesterPage() { const [searchParams] = useSearchParams() const { data, loading, error } = useTeacherResource<{ invalidChoice?: string fallPath?: string springPath?: string }>('/select-semester') const requestedSchoolYear = searchParams.get('school_year')?.trim() ?? '' const { selectedYear } = useSchoolYearOptions({ preferredYear: requestedSchoolYear, }) const activeSchoolYear = requestedSchoolYear || selectedYear const fallTo = appendSchoolYearParam(data?.fallPath ?? '/app/teacher/scores?semester=Fall', activeSchoolYear) const springTo = appendSchoolYearParam(data?.springPath ?? '/app/teacher/scores?semester=Spring', activeSchoolYear) return (

Before viewing scores, pick the semester you want to work with.

{data?.invalidChoice ? (
Note: "{data.invalidChoice}" is not a valid semester selection.
) : null}
Fall Spring
) } /** `teacher/trash.php` */ export function TeacherTrashPage() { const { data, loading, error } = useTeacherResource('/trash') const rows = data?.trashedMessages ?? [] return ( {rows.length === 0 ? (

No messages found in trash.

) : (
{rows.map((m) => ( ))}
Subject Date Actions
{m.subject ?? '—'} {m.created_at ?? ''} Restore / delete via API when wired.
)}
) } /** `teacher/inbox.php` */ export function TeacherInboxPage() { const { data, loading, error } = useTeacherResource('/inbox') const rows = data?.receivedMessages ?? [] return ( {rows.length === 0 ? (

No messages found.

) : (
{rows.map((m) => ( ))}
From Subject Date Actions
{String(m.sender_id ?? '')} {m.subject ?? ''} {m.created_at ?? ''} View
)}
) } /** `teacher/sent.php` */ export function TeacherSentPage() { const { data, loading, error } = useTeacherResource('/sent') const rows = data?.sentMessages ?? [] return ( {rows.length === 0 ? (

No sent messages.

) : (
{rows.map((m) => ( ))}
To Subject Date
{String(m.sender_id ?? '')} {m.subject ?? ''} {m.created_at ?? ''}
)}
) } /** `teacher/teacher_message.php` — thread payload from `/api/v1/teacher/messages/:id`. */ export function TeacherMessagePage() { const { messageId } = useParams() const path = messageId ? `/messages/${messageId}` : '/message' const { data, loading, error } = useTeacherResource(path) return (
        {data ? JSON.stringify(data, null, 2) : null}
      
) }