Skip to content

Dashboard Refactor, useProgramDashboardData#3356

Merged
ChristopherChudzicki merged 10 commits into
mainfrom
cc/dashboard-refactor-phase-4
May 20, 2026
Merged

Dashboard Refactor, useProgramDashboardData#3356
ChristopherChudzicki merged 10 commits into
mainfrom
cc/dashboard-refactor-phase-4

Conversation

@ChristopherChudzicki

@ChristopherChudzicki ChristopherChudzicki commented May 19, 2026

Copy link
Copy Markdown
Contributor

What are the relevant tickets?

For https://github.com/mitodl/hq/issues/11205

Description (What does it do?)

This PR moves logic out of ProgramEnrollmentDisplay. Now:

  1. Changed: ProgramEnrollmentDisplay is display only, essentially zero computation, makes no queries of its own; delgates to useProgramDashboardData
  2. New: useProgramDashboardData makes queries and organizes data for the UI via pure functional utilities (most notability buildRequirementSections). Also new is useDashboardLanguagePicker
    • In addition to keeping the UI components simple, the orchestrating hooks are easier to test directly.
  3. New: buildRequirementSections and other utilities.

The new utilities are thoroughly tested. New tests also for useProgramDashboardData verify it is calling the utilities correctly, and tests for useDashboardLanguagePicker check its state / state mutation behaviors.

How can this be tested?

  1. Enroll in an mitxonline program locally. Use a program with multiple requirement sections and some program-as-course children. (Such as UAI.) Check that:
    • completion counts display correctly
    • cards display correctly (same as main)
    • In general, we should have confidence by the existing (untouched) ProgramEnrollmentDisplay.test.tsx file passing.
  2. Set up langauges for a B2C program as descirbed in dashboard translations UI #3269
    • The language picker should still work.
    • Note: The B2C program langauge feature is not really used / supported in production by real data , but it should work on this branch exactly as it does on main.

@github-actions

github-actions Bot commented May 19, 2026

Copy link
Copy Markdown

OpenAPI Changes

No changes detected

View full changelog

Unexpected changes? Ensure your branch is up-to-date with main (consider rebasing).

* pure model (model/dashboardViewModel.test.ts) or the hook tests
* (hooks/useProgramDashboardData.test.tsx, useDashboardLanguagePicker.test.ts),
* NOT here.
*/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many tests in this file fall outside the categories noted above, but are left in place as a safety net during the refactor.

@ChristopherChudzicki ChristopherChudzicki marked this pull request as ready for review May 19, 2026 20:31
Copilot AI review requested due to automatic review settings May 19, 2026 20:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the program dashboard to separate query/data orchestration from rendering by introducing useProgramDashboardData and moving requirement-tree parsing/section building into pure, well-tested utilities. It also introduces a shared parseProgramRequirementSections helper in @/common/mitxonline to structurally parse req_tree operator sections.

Changes:

  • Added useProgramDashboardData + useDashboardLanguagePicker hooks to own data fetching, composition, and language picker state.
  • Added/expanded pure model utilities (buildCourseEntry, buildRequirementSections) and updated adapters/tests to align with the new “entry”-based dashboard model.
  • Added parseProgramRequirementSections as a shared req_tree structural parser, with unit tests.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated no comments.

Show a summary per file
File Description
frontends/main/src/common/mitxonline/index.ts Adds shared parseProgramRequirementSections + exported type for structural parsing of program req_tree.
frontends/main/src/common/mitxonline.test.ts Adds unit tests for parseProgramRequirementSections.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/test-utils.ts Adds buildProgramScenario to standardize hook test API mocking.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/ProgramEnrollmentDisplay.tsx Converts component into a display-only renderer backed by useProgramDashboardData.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/ProgramEnrollmentDisplay.test.tsx Adds test-layering documentation comment (scope guidance).
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/model/dashboardViewModel.ts Adds buildCourseEntry + buildRequirementSections; integrates shared parser; renames slot→entry resolver export.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/model/dashboardViewModel.test.ts Adds extensive unit coverage for the new pure utilities and updated resolver name.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/model/dashboardAdapters.ts Renames adapter to entry-based naming (adaptCourseEntryToLegacyDashboardCardProps).
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/model/dashboardAdapters.test.ts Updates tests to entry-based adapter naming and types.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/hooks/useProgramDashboardData.ts New composer hook that performs the 6 queries and returns render-ready program dashboard data.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/hooks/useProgramDashboardData.test.tsx Adds renderHook suite asserting query→helper wiring + durable returned contract.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/hooks/useDashboardLanguagePicker.ts New hook for language picker state (derive-during-render approach).
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/hooks/useDashboardLanguagePicker.test.ts Unit tests for language picker behavior across option changes.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/HomeEnrollmentsDisplay.test.tsx Adds test-layering documentation comment (scope guidance).
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/dashboardRefactorPlan.md Updates plan doc terminology and Phase 4 “settled decisions” notes (slot→entry terminology, etc.).
frontends/main/src/app-pages/DashboardPage/ContractContent.tsx Renames usage to resolveCourseEntryForLanguage to match the entry-based model export.

@gumaerc gumaerc self-assigned this May 20, 2026
@gumaerc gumaerc added the Needs Review An open Pull Request that is ready for review label May 20, 2026

@gumaerc gumaerc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good to go, just noticed one small typo.

*
* Fetches the 6 program-dashboard queries (course-run enrollments,
* programDetail, program enrollments, program courses, required programs,
* required-program courses) and composes the pure helpers in

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "required program-courses"

*
* Fetches the 6 program-dashboard queries (course-run enrollments,
* programDetail, program enrollments, program courses, required programs,
* required-program courses) and composes the pure helpers in

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* required-program courses) and composes the pure helpers in
* required program-courses) and composes the pure helpers in

ChristopherChudzicki and others added 10 commits May 20, 2026 13:15
Folds the Phase 4 brainstorming outcomes into the plan as a SETTLED block:
- (A) build the real entry constructor + adapter; rename DashboardCourseSlot →
  DashboardCourseEntry (code + remainder of plan doc) as step 0
- composer emits the RequirementSectionItem discriminated union + shared aux
  (enrollmentsByCourseId / pre-derived ancestorProgramEnrollment)
- buildProgramScenario = thin entities-in mock-wirer (2a); tests own scenario
- language picker: hook-owned, derive-during-render, effective key, own test
- shared structure-only parseProgramRequirementSections in @/common/mitxonline;
  buildRequirementSections owns dashboard display policy; product parseReqTree
  migration is the next stacked PR; re-ask at Phase 4 exit
- behavior-preservation scope: stable render is the contract, first paint
  negotiable except loading states

Full design record (rationale + rejected alternatives) in
feature_work/TODOS_AND_IDEAS/phase4-design.md (local).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…step 0)

Pure rename, zero behavior change, zero production callers today:
- DashboardCourseSlot → DashboardCourseEntry
- resolveSlotForLanguage → resolveCourseEntryForLanguage
- adaptCourseSlotToLegacyDashboardCardProps → adaptCourseEntryToLegacyDashboardCardProps
- dashboardRefactorPlan.md slot vocabulary swept to "entry"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…(Phase 4 Task B)

Shared req-tree → ordered operator sections parse (ids + operator metadata +
rawTitle only; no display copy/completion/entity resolution). Composed by the
Phase 4 dashboard helpers (Task C). Product parseReqTree migration is a later PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…se 4 Task C)

Pure model helpers composing the shared parseProgramRequirementSections into the
RequirementSectionItem discriminated union; behavior-preserving extraction of the
inline ProgramEnrollmentDisplay logic. getRequirementSectionTitle moved into the
model. Flat-req_tree assumption documented.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Derive-during-render language-picker state (no reconcile effect). Stable
contract preserved (effective key ∈ options or "" ; default = options[0];
user pick persists while valid, falls back when it disappears). Reused by
Phase 5. setSelectedLanguageKey records the raw user choice.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…cenario (Phase 4 Task E)

Thin composer: replicates the program dashboard's 6-query orchestration exactly
and composes the pure helpers (grouping, getDistinctDashboardLanguageOptions,
useDashboardLanguagePicker, buildRequirementSections) into the durable returned
contract incl. shared aux (enrollmentsByCourseId, ancestorProgramEnrollment).
renderHook suite asserts the returned contract (never through the adapter);
buildProgramScenario is a thin entities-in mock-wirer (tests own scenario shape).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…boardData (Phase 4 Task F)

Component is now purely presentational: consumes the composer hook and routes the
course arm through adaptCourseEntryToLegacyDashboardCardProps. All inline query
orchestration / language state / req-tree shaping removed. Behavior byte-identical
— ProgramEnrollmentDisplay.test.tsx unchanged and green (the regression oracle).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Branch-review follow-ups, no production behavior change:

1. test-utils buildProgramScenario: derive requiredProgramIds via
   getIdsFromReqTree(program.req_tree) + Set dedup so it truly mirrors
   the hook's useMemo (the drift-protection comment was inaccurate;
   closes a silent mock-key-drift trap).
2. useProgramDashboardData: reword stale '6 queries (replicated
   exactly from oracle)' comment (the hook is canonical post-Task-F).
3. useProgramDashboardData: drop dead re-export of
   V3UserProgramEnrollment + its now-unused import.
4. dashboardViewModel: make getRequirementSectionTitle module-private
   (only exercised internally via buildRequirementSections; not
   imported directly by tests).
5. useProgramDashboardData.test: add a composer renderHook scenario
   exercising the program-enrollment arm (closes a wiring-layer gap).
6. parseProgramRequirementSections: doc the recursion ≡ direct-children
   parity under the flat-req_tree invariant.

Verified: yarn test DashboardPage/ (458 pass), mitxonline.test.ts
(34 pass), frontends typecheck — all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a file-header comment to HomeEnrollmentsDisplay.test.tsx and
ProgramEnrollmentDisplay.test.tsx stating what belongs in these
component (layer-3) suites — seam/smoke + genuine component concerns —
and that exhaustive case coverage belongs in the pure model / hook
tests. Anti-bloat guardrail for future contributors.

Comment-only: +33/-0, zero assertion/code changes. This is the single
change to the otherwise-frozen Phase-4 behavior oracle
(ProgramEnrollmentDisplay.test.tsx) — the oracle's diff vs origin/main
is now exactly this one comment-only commit, no behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ChristopherChudzicki ChristopherChudzicki force-pushed the cc/dashboard-refactor-phase-4 branch from 3152be5 to 6989528 Compare May 20, 2026 17:15
@ChristopherChudzicki ChristopherChudzicki merged commit 240511e into main May 20, 2026
14 checks passed
@ChristopherChudzicki ChristopherChudzicki deleted the cc/dashboard-refactor-phase-4 branch May 20, 2026 17:35
This was referenced May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs Review An open Pull Request that is ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants