Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

05 — Screen Inventory (Timetable Module)

Every screen of the Timetable module, its intent, route, composition, states, permissions, platform behaviour and events. Authoritative components in 00-shared/03; this file enumerates which ones each screen uses with module specifics. The weekly grid is the hero component — see 06 §S1 and 07 §A1.


Legend

States = idle / loading / success / empty / error(offline, rate, invalid) / disabled / permission. Analytics events follow {module}.{screen}.{action} (proposed; SDK open — 00-shared/10 §8).


S1 — Class Timetable Grid (/academics/timetable?classId=:id)

FieldDetail
PurposeWeekly grid for one class: 6 day columns × time rows; slot cards = subject · teacher · room
EntryAcademics nav → pick class; deep link; FAB "Add slot"
Exittap slot → S4; scope switch → S2; room chip → S3 (planned)
Inputsscope picker (class/teacher/room), week navigator, class picker
Primary CTAFAB "Add slot" (opens S4 prefilled with class)
SourceGET /timetable?classId= (timetable.controller.ts:23), server-sorted dayOfWeek, startTime (timetable.service.ts:48-53)
Statesloading (skeleton grid), empty (no entries), error, offline (cached last-good + banner), permission (timetable.read, permissions.constants.ts:44)
Analyticstimetable.class.view, timetable.slot.tap (proposed)
Adaptivephone: vertical list of days with horizontal time strip; tablet/desktop: true 6-column grid, drag & drop (15 §8)
a11yeach slot a single button semantics with full label; grid headers announced; focus order left→right, top→bottom
Motiongrid fade m-fast; slot insert/remove AnimatedList m-base (10 §4)

S2 — Teacher Timetable Grid (/academics/timetable/teacher/:teacherId)

FieldDetail
PurposeSame grid component, teacher scope; read-only for teacher self
EntryTeacher detail · Schedule tab; scope switch from S1; deep link
SourceGET /timetable?teacherId= (timetable.controller.ts:26), sorted dayOfWeek, startTime (timetable.service.ts:55-60)
Writesnone for teacher role — no editor affordances (02 §3)
Statesas S1; "no classes scheduled" empty state (no CTA for teachers)
Analyticstimetable.teacher.view (proposed)

S3 — Room Timetable Grid (/academics/timetable/room/:roomId) (planned)

FieldDetail
PurposeBooked slots per room, read-only
Entryslot's room chip; Rooms module detail
Sourceno roomId filter exists (timetable.controller.ts:22-25) → client merges GET /timetable?classId= responses for classes using the room; native filter (planned) (IMPLEMENTATION_PLAN.md:226)
Statesas S1; "No bookings for this room"
Analyticstimetable.room.view (proposed)

S4 — Entry Editor (bottom sheet on phone / dialog on desktop)

FieldDetail
PurposeCreate one timetable entry (the only server write)
EntryFAB / empty cell tap / slot "Duplicate"
Exitsuccess → grid insert; cancel; 409 conflict → stays open with banner
Inputsclass ▾, subject ▾, teacher ▾, room ▾ (optional), day ▾, start time, end time, academic year ▾ (default isCurrent) — full spec 08 F1
Primary CTA"Save" (disabled until valid; double-submit guard)
SourcePOST /timetable (timetable.controller.ts:14-18), CreateTimetableEntryDto (create-timetable-entry.dto.ts:5-38)
Statesidle / submitting / 400 field errors / 409 conflict banner (timetable.service.ts:28) / 5xx
Conflict UXAppBanner: "Teacher already booked {day} {start}–{end}" or "Room already in use…" — derived from the single server message + local pre-flight (06 §S4)
Analyticstimetable.entry.submit, timetable.entry.conflict, timetable.entry.success (proposed)

S5 — Conflict banner (inline state, not a page)

FieldDetail
PurposeSurface the single server conflict rule: teacher or room double-booking on the same day with overlapping time (timetable.service.ts:16-30,62-69)
Trigger409 from POST /timetable; also local pre-flight warnings before submit (races possible — server authoritative)
Placementinside S4, above the submit button
Actionsdismiss; "Change time/teacher/room" (focus related picker)
Copytimetable.conflict.teacher / timetable.conflict.room — one generic server message ("Schedule conflict detected", timetable.service.ts:28) mapped to the specific pre-flight cause
a11ylive-region announce; errorContainer tokens (11 §2)

S6 — Week Navigation & Today View

FieldDetail
PurposeMove between weeks; collapse to today
BehaviourWeekNavigator (07 §A7): ‹ today › offset −1..0..+n (forward-looking: weekly shift) — pure client state, no server concept of "week"; entries are weekly-recurring by model (timetable.schema.ts:30-37 stores weekday + time only, no date)
NoteThe backend has no date dimension — week navigation merely re-filters the same 6-day data; push notifications for "class in 15 min" (forward-looking) would need a new date-aware model

Shared components used

AppDropdown, AppButton, AppSnackbar, AppCard, AppBottomSheet, AppDialog, AppMenu, AppSkeleton, AppEmptyState, AppErrorState, AppOfflineBanner, AppFAB, AppChips, AppBadge, AppTabs, AppSectionHeader, AppTimePicker-style time field, AppSearchBar-style searchable pickers. Module-specific: TimetableGrid, TimetableSlotCard, DayHeader, TimeGutter, GridCell, ConflictBanner, WeekNavigator — defined in 07_Component_Library.md.

Analytics events (proposed)

timetable.{class,teacher,room}.view, timetable.slot.tap, timetable.entry.{submit,conflict,success}, timetable.week.{prev,next,today}, timetable.conflict.dismiss (all proposed).

Keyboard, landscape, tablet, desktop

  • Phone portrait: day-strip list; landscape/tablet: grid with fixed day headers.
  • Desktop: true grid + drag & drop (15 §8), +/N new slot, ←/→ week nav.
  • Grid scrolls horizontally on narrow widths; time gutter + day headers pinned (15 §9).