Commit 8365085
authored
feat: scores viewer, auth hardening, perf optimisations, and infra upgrades (#469)
feat(scores): add Scores page with exam/assessment viewer
New protected route /scores showing all exams and assessments grouped by
course.
- ScoresClient: stats strip (total / scored / pending / avg%), filter tabs
(all / assessments / assignments), course-grouped cards, animated detail
drawer, resolved score logic (resolvedScore > pivot.score), maxMark
fallback, ungraded "Pending" state, keyboard-accessible close (Esc /
autoFocus)
- useExams / useAllExamAnswers / useAllExamQuestions hooks with TanStack
Query (staleTime 5 min)
- exam.d.ts: Exam, ExamAnswer, ExamQuestion, ExamParticipant types
- error.tsx boundary scoped to /scores
- robots.ts + sitemap.ts updated to include /scores
- 48 unit tests covering all states and edge cases
- OpenAPI spec updated with /scores entry
fix(auth): harden session expiry and logout flow
- lib/security/auth.ts: handleLogout() clears both EzyGo
(ezygo_access_token) and Supabase session; eliminates bare
router.replace("/") calls that left HttpOnly cookies intact
- protected layout: missing session/user → await handleLogout() instead of
bare redirect; auth session missing errors similarly routed through
handleLogout()
- login-form.tsx: improved post-login redirect handling
perf: reduce unnecessary network requests across protected pages
- user-settings provider: staleTime 30 s → 5 min, gcTime → 30 min,
refetchOnWindowFocus/Interval disabled; cache invalidated only on
SIGNED_IN (not TOKEN_REFRESHED)
- useNotifications: add countOnly param — when true, only the HEAD-only
unread-count query runs; action-conflict and infinite-feed queries (both
with 30 s polling) are skipped
- private-navbar: useNotifications(true, true) — eliminates two wasted
Supabase connections + 30 s polling on every protected page
- protected layout: institution loading/error no longer gates page render;
useInstitutions() still called for cache pre-warming
- DashboardClient ChartSkeleton: <Loading minimal /> instead of full-
viewport <Loading /> inside chart card containers
- GET /api/profile: fast path — DB row exists → return immediately (avatar
renders at once); EzyGo sync deferred to after() background task
feat(ui): Loading minimal prop for compact inline spinner
- loading.tsx: minimal mode uses py-8 compact container, hides ghost
message and timeout buttons; full mode unchanged
- sr-only label updated to "Loading, please wait..."
feat(http): axios interceptors and circuit-breaker integration
- lib/axios.ts: request-signing interceptor, response error normalisation,
circuit-breaker wrapping for EzyGo API calls
refactor(accept-terms): extract AcceptTermsClient component
- Accept-terms page split into server page.tsx + client
AcceptTermsClient.tsx for better RSC boundary separation
- Metadata and OG tags improved
chore(infra): bump npm pin in Dockerfile to 11.10.1
- Updated tarball URL and SHA-256 in base layer
test: fix stale assertions, lint errors, add 48 new tests
- ScoresClient.test.tsx: 48 tests — loading/error/empty states, stats
strip, course grouping, filter tabs, score display, drawer, a11y
- exams.test.tsx: unit tests for useExams and related query hooks
- profile route.test.ts: after() mocked via next/server mock
- robots/sitemap tests updated for new /scores route
- Fixed: unused waitFor/DeepPartial/sectionHeaders imports, stale
jsx-a11y/no-autofocus disable comment, missing activity_name_id: null in
makeExam fixture, unused mockPush in vi.hoisted()1 parent 749105a commit 8365085
36 files changed
Lines changed: 3120 additions & 469 deletions
File tree
- public/api-docs
- src
- app
- (auth)
- (protected)
- dashboard
- scores
- __tests__
- (public)/build-info
- __tests__
- accept-terms
- api/profile
- __tests__
- components
- layout
- user
- __tests__
- hooks
- courses
- __tests__
- notifications
- lib
- security
- providers
- types
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
| 44 | + | |
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
| 17 | + | |
| 18 | + | |
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
27 | 28 | | |
28 | 29 | | |
29 | 30 | | |
| |||
97 | 98 | | |
98 | 99 | | |
99 | 100 | | |
100 | | - | |
| 101 | + | |
101 | 102 | | |
102 | 103 | | |
103 | 104 | | |
| 105 | + | |
104 | 106 | | |
105 | 107 | | |
106 | 108 | | |
| |||
133 | 135 | | |
134 | 136 | | |
135 | 137 | | |
| 138 | + | |
| 139 | + | |
136 | 140 | | |
137 | 141 | | |
138 | 142 | | |
| |||
152 | 156 | | |
153 | 157 | | |
154 | 158 | | |
155 | | - | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
156 | 163 | | |
157 | 164 | | |
158 | 165 | | |
| |||
499 | 506 | | |
500 | 507 | | |
501 | 508 | | |
| 509 | + | |
| 510 | + | |
502 | 511 | | |
503 | 512 | | |
504 | 513 | | |
505 | 514 | | |
506 | | - | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
507 | 519 | | |
508 | 520 | | |
509 | 521 | | |
| |||
544 | 556 | | |
545 | 557 | | |
546 | 558 | | |
| 559 | + | |
| 560 | + | |
547 | 561 | | |
548 | 562 | | |
549 | 563 | | |
| |||
0 commit comments