6.4 KiB
6.4 KiB
Track C — Module Placeholders & Toast Foundation
Owner: Person C
Branch: fix/stubs-module-placeholders (worktree at .worktrees/stubs-module-placeholders/)
Files in scope: client/src/pages/exams/ExamEditor.tsx, client/src/pages/exams/ExamViews.tsx (Edit button + create-mode extraction only), client/src/App.tsx (route decision in C1 only), client/src/pages/admin/Settings.tsx (alert → toast pass), client/src/components/EdutainmentGames.tsx (optional C4), client/src/components/Toast.tsx (new).
Conventions (from AGENTS.md)
- Work in a worktree branched from
dev. Do not edit the main checkout. - Use the shared axios instance at
client/src/store/api.ts. - Route gating stays in
App.tsxvia<ProtectedRoute allowedRoles>— do not gate inside pages. - All new tables go in
server/src/database/init.js(this track adds none, but if you do, updatetablesToSyncinSyncEngine.js). - PWA service worker is only built by
npm run build. - Do not commit or push without an explicit "go" from the reviewer.
Tasks
C1. ExamEditor — Placeholder page
- File:
client/src/pages/exams/ExamEditor.tsx(whole file, 43 lines, route/exams/edit/:idatApp.tsx:368) - Current: The page renders only a "Module Under Construction" card. Anyone clicking "Edit" from the exam list lands here.
- Pick one with the user (this is a design call, not yours):
- (a) Implement. Extract the create-mode form in
ExamViews.tsx(around the new-exam modal: title, description, exam_type, academic_year, dates) into a sharedclient/src/pages/exams/ExamForm.tsxcomponent. HaveExamEditorrender<ExamForm mode="edit" id={id} />. WireloadExam(id)against the existing exams API. - (b) Defer. Delete the route from
App.tsx:368and remove the "Edit" button inExamViews.tsxuntil the editor is actually needed. The "Create" path stays unchanged.
- (a) Implement. Extract the create-mode form in
- Recommended starting point: (b). It is one commit, removes a misleading page, and leaves the form work for a real session.
- Acceptance: No route resolves to the placeholder. Either a real editor renders, or there is no UI surface at all that lands on the placeholder.
C2. EdutainmentGames — Biased random-shuffle
- File:
client/src/components/EdutainmentGames.tsx:77 - Current:
const shuffled = [...students].sort(() => 0.5 - Math.random());— the comparator pattern is biased for arrays longer than ~5. - Desired: Replace with a proper Fisher–Yates:
for (let i = arr.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [arr[i], arr[j]] = [arr[j], arr[i]]; }. Extract to a helper at the top of the file (function shuffleInPlace<T>(arr: T[])). - Acceptance: Picking a random student 100 times with a 10-student class produces each name between 5 and 25 times (rough uniformity check, not exact).
- Note: Other
Math.randomuses in the file (lines 424, 428-447, 596) are for generating maths problems and seed values — leave them. The bug only matters for student picker fairness.
C3. Settings — Toast foundation and alert sweep
- Files: New
client/src/components/Toast.tsx,client/src/App.tsx(mount provider),client/src/pages/admin/Settings.tsx(8alert()s at :114, :116, :135, :143, :145, :153, :175, :178). - Current: Every action in Settings (terminate sessions, integrity check, run diagnostics, download backup, upload logo) reports success or failure via
alert(...). - Desired:
- Add a tiny toast system:
ToastProvidermounted inApp.tsxnear the<Router>, exposes auseToast()hook returning{ success, error, info }. Single-file implementation, no external dependency. - In Settings, replace each
alert('All active sessions have been terminated successfully.')withtoast.success('All active sessions terminated.'), etc. Erroralert()→toast.error(err.response?.data?.error || 'Failed …'). - Verify no other file in
Settings.tsxusesalertafter the pass.
- Add a tiny toast system:
- Acceptance: Click each action in Settings — toasts appear, no
alert().grep -n "alert(" client/src/pages/admin/Settings.tsxreturns no hits.
C4. (Optional, time permitting) Toast sweep in other admin pages
- Files:
HRManagement.tsx,Inventory.tsx,Library.tsx,Users.tsx,Teachers.tsx(after Track A's modal work, success/error alert()s will mostly be gone already), PostalDispatch, PhoneCalls, AdmissionEnquiry. - Current: Each page owns its own success/error
alert()s. - Desired: Swap them to the toast hook from C3. Pure mechanical pass — no UX changes.
- Acceptance: "Send message" in Messages, "Save" in Inventory, etc. all show toasts. No
alert(left in the touched files.
C5. Reservation page thinness — walk-through + scope
- File:
client/src/pages/librarian/Reservations.tsx(7.6 KB, 227 lines) - Current: Functional thin page.
- Desired: Read it once. If there are real gaps (filters, bulk-cancel, overdue flag), write a small ticket under
.harness/reins/or as a comment in the file. Do not silently expand scope. If it is honest as-is, close it with a one-line "no action" note in your PR. - Acceptance: Either a follow-up ticket exists, or the PR explicitly says "reviewed and intentionally left as-is".
Cross-cutting checks
curl http://localhost:3000/exams/edit/123afternpm run buildreturns 200 from the SPA — but clicking an Edit button in the UI does not land on "Module Under Construction" copy (C1).grep -rn "alert(" client/src/pages/admin/Settings.tsxis empty after C3.npm run buildis green in your worktree;<Toast />renders in dev (npm run dev) and shows in the top-right with auto-dismiss.
Manual test
- As
school_admin, open the exam registry, click "Edit" on any exam. Either an editor renders (C1a) or there is no Edit button at all (C1b). - Open Settings, click each action. Toasts. No
alert()orconfirm(). - Pick a student randomly 10 times in EdutainmentGames → no student wins twice in a row (C2 sanity).
- If you did C4, click "Save" / "Delete" / "Issue" across HRManagement, Inventory, Library — toasts.
Out of scope here (other tracks)
- Login, Profile, Teachers password resets and filters — see Track A.
- Fees, MyCourses classes fallback, AdminDashboard avatars — see Track B.
- "Every
confirm()becomes a styled modal" — separate task. Mostconfirm()s in the codebase are legitimate destructive-action prompts; do not touch on this track.