geocrop-platform./apps/nextgen/.harness/plans/stubs-sprint-1b/C.md

6.4 KiB
Raw Blame History

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 FisherYates: 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.