138 lines
5.5 KiB
Markdown
138 lines
5.5 KiB
Markdown
# 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 Pins` stat now carries an optional
|
|
`valueWhenZero: '—'` override.
|
|
- The render path checks `value === 0 && valueWhenZero` and swaps in
|
|
the dash.
|
|
- The `trend` text 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 `tsc` errors (most are missing `@types/vitest` and
|
|
pre-existing shape mismatches in `pages/admin/NoticeBoard.tsx` /
|
|
`pages/exams/ExamViews.tsx`). My branch is at 150 — the 11-line
|
|
increase is all from `terminology.test.ts` (pre-existing test-file
|
|
pattern, no new types needed since I followed the same shape as
|
|
the existing `it(...)` 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.
|