73 lines
6.4 KiB
Markdown
73 lines
6.4 KiB
Markdown
# 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.tsx` via `<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, update `tablesToSync` in `SyncEngine.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/:id` at `App.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 shared `client/src/pages/exams/ExamForm.tsx` component. Have `ExamEditor` render `<ExamForm mode="edit" id={id} />`. Wire `loadExam(id)` against the existing exams API.
|
||
- **(b) Defer.** Delete the route from `App.tsx:368` and remove the "Edit" button in `ExamViews.tsx` until the editor is actually needed. The "Create" path stays unchanged.
|
||
- **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.random` uses 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` (8 `alert()`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: `ToastProvider` mounted in `App.tsx` near the `<Router>`, exposes a `useToast()` hook returning `{ success, error, info }`. Single-file implementation, no external dependency.
|
||
- In Settings, replace each `alert('All active sessions have been terminated successfully.')` with `toast.success('All active sessions terminated.')`, etc. Error `alert()` → `toast.error(err.response?.data?.error || 'Failed …')`.
|
||
- Verify no other file in `Settings.tsx` uses `alert` after the pass.
|
||
- **Acceptance:** Click each action in Settings — toasts appear, no `alert()`. `grep -n "alert(" client/src/pages/admin/Settings.tsx` returns 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/123` after `npm run build` returns 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.tsx` is empty after C3.
|
||
- `npm run build` is green in your worktree; `<Toast />` renders in dev (`npm run dev`) and shows in the top-right with auto-dismiss.
|
||
|
||
## Manual test
|
||
|
||
1. 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).
|
||
2. Open Settings, click each action. Toasts. No `alert()` or `confirm()`.
|
||
3. Pick a student randomly 10 times in EdutainmentGames → no student wins twice in a row (C2 sanity).
|
||
4. 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. Most `confirm()`s in the codebase are legitimate destructive-action prompts; do not touch on this track.
|