Skip to content

FAC-WEB feat: show academic year alongside semester labels#154

Merged
y4nder merged 1 commit into
developfrom
feat/semester-label-academic-year
Apr 23, 2026
Merged

FAC-WEB feat: show academic year alongside semester labels#154
y4nder merged 1 commit into
developfrom
feat/semester-label-academic-year

Conversation

@y4nder

@y4nder y4nder commented Apr 23, 2026

Copy link
Copy Markdown
Member

Closes #153.

Summary

  • Add shared formatSemesterDisplay util at lib/format-semester.ts composing label + academicYear into "Semester 2 • 2025-2026" (bullet matches the existing separator convention).
  • Wire the util into mapSemesterOptionsToViewModel — propagates the composed label to all three semester dropdowns (dashboard header, scoped faculty list, faculty-evaluation toolbar) and every downstream selectedSemesterLabel consumer (tab empty states, export dialogs, attention cards, section headers, faculty cards, evaluate action menus).
  • Wire the util into useFacultyReportDetailViewModel — the faculty-report sticky header reads report?.semester.label off the report response and bypasses the ViewModel chain.
  • Drop the now-redundant academicYear field from ScopedSemesterOption to prevent consumers from accidentally rendering both sides of the composed string.
  • Widen the dashboard-header semester dropdown trigger from md:w-48 to md:w-64 so the longer composed label fits without truncation.

No API / backend changes — the backend already ships academicYear on every semester DTO; this is purely presentation.

Why

Current UI shows bare Semester 2 in dropdowns and headers — ambiguous when data spans multiple academic years (Semester 2 of 2024-2025 vs Semester 2 of 2025-2026).

Fallback behavior

  • label + academicYear present → "Semester 2 • 2025-2026"
  • label present, academicYear absent → "Semester 2 (year unknown)"
  • label absent, code + academicYear present → "S22526 • 2025-2026" (preserves the pre-existing fallback)
  • everything absent → "Unknown Semester (year unknown)"

Whitespace-only values are treated as missing.

Quality gates

  • bun run typecheck
  • bun run lint ✅ (including no-nested-ternary — the report-detail fallback chain was refactored to named consts)
  • bun run build ✅ (28/28 pages)

Test plan

  • Dean / scoped analytics dashboard — semester dropdown trigger + items show the composed label; trigger is wide enough to avoid ellipsis at md+ viewports
  • Dean / faculty list screen — semester dropdown shows composed label
  • Dean/Faculty / faculty-evaluation toolbar — semester dropdown shows composed label
  • Faculty / /faculty/analytics — sticky header on the faculty report screen shows composed label
  • Dean / per-faculty report screen — same sticky header, same composed format
  • Spot-check one downstream selectedSemesterLabel consumer per grouping (tab empty state, export dialog, attention card, section header, faculty card, evaluate action menu) — each inherits the composed label from the ViewModel
  • URL round-trip: land on /faculty/analytics with no semesterId, confirm the URL bar has ?semesterId=<uuid>&semesterLabel=Semester+2+%E2%80%A2+2025-2026; copy-paste into a new tab and verify the sticky header decodes correctly
  • On a 13–14" viewport (~900–1000px content width with sidebar open), open the Campus-scope dashboard (four dropdowns on one row). If layout wraps awkwardly, drop md:w-64 to md:w-56 (224px still fits the composed label at text-sm)
  • If any seeded semester rows have academic_year IS NULL, verify they render as "Semester 2 (year unknown)" (or inject via DevTools React Query cache)

Tech-spec

api.faculytics/_bmad-output/implementation-artifacts/tech-spec-semester-label-with-academic-year.md

Follow-ups (not this PR)

  • admin.faculytics copy of the util (separate ticket)
  • Server-rendered faculty PDF reports — compose on the backend if that format should also change
  • Align the three semester response DTO optionality variants (SemesterFilterResponseDto required vs SemesterShortResponseDto / SemesterItemResponseDto optional) — API-side audit

Compose "Semester 2 • 2025-2026" via a shared formatSemesterDisplay
util at lib/format-semester.ts, wired into two composition points:
mapSemesterOptionsToViewModel (propagates to the three semester
dropdowns and every downstream selectedSemesterLabel consumer) and
useFacultyReportDetailViewModel (the faculty-report sticky header,
which reads report?.semester.label directly and bypasses the
ViewModel chain). Drops the now-redundant academicYear field from
ScopedSemesterOption and widens the dashboard-header semester
trigger to md:w-64 so the longer composed label doesn't truncate at
md+ viewports.

The API already ships academicYear on every semester DTO — this is
presentation-only. Fallback to "(year unknown)" when academicYear is
absent, surfacing data gaps instead of silently dropping the year.

Closes #153
@vercel

vercel Bot commented Apr 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app-faculytics Ready Ready Preview, Comment Apr 23, 2026 5:06pm

@y4nder y4nder linked an issue Apr 23, 2026 that may be closed by this pull request
4 tasks
@y4nder y4nder self-assigned this Apr 23, 2026
@y4nder y4nder merged commit 8b65891 into develop Apr 23, 2026
3 checks passed
y4nder added a commit that referenced this pull request Apr 23, 2026
Compose "Semester 2 • 2025-2026" via a shared formatSemesterDisplay
util at lib/format-semester.ts, wired into two composition points:
mapSemesterOptionsToViewModel (propagates to the three semester
dropdowns and every downstream selectedSemesterLabel consumer) and
useFacultyReportDetailViewModel (the faculty-report sticky header,
which reads report?.semester.label directly and bypasses the
ViewModel chain). Drops the now-redundant academicYear field from
ScopedSemesterOption and widens the dashboard-header semester
trigger to md:w-64 so the longer composed label doesn't truncate at
md+ viewports.

The API already ships academicYear on every semester DTO — this is
presentation-only. Fallback to "(year unknown)" when academicYear is
absent, surfacing data gaps instead of silently dropping the year.

Closes #153
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FAC-WEB feat: show academic year alongside semester labels

1 participant