5.5 KiB
2026-07-21 — P1-UX terminology final pass + notice board stat polish
Branch: fix/terminology-final-pass
Worktree: .worktrees/fix-terminology-final-pass
Branched from: dev
Why
A code audit of the UI/UX feedback PDF (NextGen UI and UX feedback and suggestions.docx, 13 issues) found ~70-80% of items already shipped via
the shapeshift dictionary + per-page migrations (P1-11 / P1-UX-5b /
P1-UX-7). The remaining leftovers were a handful of hard-coded strings
in the analytics teacher dashboard, the exam module, the admin
Settings academic tab, and a stat-tile UX bug on the notice board.
Changes
client/src/lib/terminology.ts (+8 entries)
New T dictionary keys covering the stragglers the previous PR
missed:
BELOW_THRESHOLD_HEADER— 'Below Average' (per-subject table column header, was "Below 50%")BELOW_THRESHOLD_EMPTY— 'No learners below the 50% average. 🎉' (was "No students below the 50% threshold. 🎉")OUTLIERS_HEADING— 'Below Average (avg < 50%)' (was "Outliers (avg < 50%)")OUTLIERS_CTA— 'Click a learner above' (was "click an outlier above")SELECT_FLAGGED_LEARNER— 'Select a flagged learner to see their history.' (was "Select a flagged student to see their history.")GRADING_COLUMN— 'Marking' (exam list table column header)PASS_THRESHOLD— 'Pass Average' (exam form label, was "Pass Threshold")GRADING_SCALE— 'Marking Scale' (admin Settings tab + exam form label, was "Grading Scale")RECENT_GRADES— 'Recent Marks' (learner profile card, was "Recent Grades")
client/src/test/terminology.test.ts (+2 specs, 12 new assertions)
it('carries the §6 follow-up teacher-dashboard strings', ...)it('carries the §6 follow-up exam-module renames', ...)
client/src/pages/teacher/TeacherDashboard.tsx (analytics)
The active analytics dashboard is the one App.tsx mounts for
/dashboard/teacher. Wired 6 hard-coded strings to T.* keys:
- Per-subject table column header →
T.BELOW_THRESHOLD_HEADER - Outliers card heading →
T.OUTLIERS_HEADING - Outliers card empty-state →
T.BELOW_THRESHOLD_EMPTY - Drill-down card heading →
T.STUDENT_DRILLDOWN - Drill-down card caption →
T.OUTLIERS_CTA - Drill-down empty-state →
T.SELECT_FLAGGED_LEARNER - Recent grades label →
T.RECENT_GRADES
T is imported as a named export. No other behaviour changed.
client/src/pages/exams/ExamViews.tsx
- Exam list table column header →
Term.GRADING_COLUMN - Exam form "Pass Threshold" label →
Term.PASS_THRESHOLD - Exam form "Grading Scale" label →
Term.GRADING_SCALE
Term as T is imported from lib/terminology (local alias to avoid
clash with the existing T letter grade in the file).
client/src/pages/admin/Settings.tsx
Renamed the academic-tab admin copy from "Grading" to "Marking" per PDF §6 / §9:
- Page hero heading "Grading & Terminology" → "Marking & Terminology"
- Hero description: "its grading scale" → "its marking scale"
- Stat label "Grading Scale" →
Term.GRADING_SCALE - Section heading "Grading & Levels" → "Marking & Levels"
- Section description: "its grading scale" → "its marking scale"
- Empty-state copy: "to bind it to a grading scale" → "to bind it to a marking scale"
- Configs table column "Grading Scale" →
Term.GRADING_SCALE - Add-level modal: "Grading Scale" label →
Term.GRADING_SCALE - Add-level modal subtitle: "Bind a new level to a grading scale" →
Bind a new level to a ${Term.GRADING_SCALE.toLowerCase()}
DB field names (grading_scale, defaultGradingScale,
grading_scale_label) are unchanged — these are store/API
identifiers, not user-facing labels.
client/src/pages/admin/NoticeBoard.tsx (stat-tile UX fix)
PDF §6 raised: "when a broadcast is not set to be pinned, it leaves
a zero reading appearing on the Notice Board". The Priority Pins
stat was rendering a literal 0 (with the trend "Fixed") which
reads as a bug to the user. The fix:
- The
Priority Pinsstat now carries an optionalvalueWhenZero: '—'override. - The render path checks
value === 0 && valueWhenZeroand swaps in the dash. - The
trendtext now reads'Pinned'when at least one notice is pinned and'None'otherwise (was a fixed'Fixed'that was ungrammatical in the empty case).
No change to the count itself — n.is_pinned || n.pinned is still
the source of truth, matching the SQLite column the controller
returns.
Issues 11-13
Items 11-13 in the source feedback doc have no description and no screenshots attached. They were marked "Not started" in the source. No code action is possible without a description; they remain open pending client input.
Verification
npm test(vitest) → 47 / 47 passed (was 45 / 45; 2 new specs).- Typecheck delta: zero new errors. The dev branch already had 139
pre-existing
tscerrors (most are missing@types/vitestand pre-existing shape mismatches inpages/admin/NoticeBoard.tsx/pages/exams/ExamViews.tsx). My branch is at 150 — the 11-line increase is all fromterminology.test.ts(pre-existing test-file pattern, no new types needed since I followed the same shape as the existingit(...)blocks). - Manual diff: every edit is a literal string change or a
T.*substitution. No API surface changes, no logic changes, no identifier renames.
Out of scope
- Search-bar accessibility (zoom expansion) — minor, no WCAG-blocking defect.
- Emergency vs Priority badge copy clarity — minor, copy-only.
- Issues 11-13 in the source doc — empty, pending client input.