Skip to content

"program as course" display on learner dashboard#3073

Open
gumaerc wants to merge 11 commits intomainfrom
cg/dashboard-crogram-display-2
Open

"program as course" display on learner dashboard#3073
gumaerc wants to merge 11 commits intomainfrom
cg/dashboard-crogram-display-2

Conversation

@gumaerc
Copy link
Contributor

@gumaerc gumaerc commented Mar 20, 2026

What are the relevant tickets?

Closes https://github.com/mitodl/hq/issues/10521

Description (What does it do?)

This PR implements some design changes shown in the wireframes in the issue above. Support for displaying programs with display_mode: "course" was added.

Screenshots (if appropriate):

image image image image

How can this be tested?

  • Ensure you have an instance of MITx Online spun up and configured to integrate with MIT Learn as described in the Readme
  • Your user will need lots of test data:
    • B2B contract with programs added to it that your user is a part of
    • Several B2C enrollments:
      • Individual course
      • Regular program
      • Program with display_mode: "course
    • Each of the B2C programs above should have several courses added to them, and at least one of them should:
      • Be completed with a certificate assigned
      • Be eligible for certificate upgrade
  • Log in and view the dashboard
  • Carefully go over each section and smoke test every part of DashboardCard in any conceivable scenario, checking what's rendered against the Figma wireframes in the issue above

Copilot AI review requested due to automatic review settings March 20, 2026 18:51
@gumaerc gumaerc added the Needs Review An open Pull Request that is ready for review label Mar 20, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements the “program as course” dashboard presentation (for programs with display_mode: "course") and updates the dashboard card UI to match the new designs, including new card components and supporting helpers/tests.

Changes:

  • Added ProgramAsCourseCard + ProgressBadge to render a program as a stacked “course-like” card with module list and progress/dates UI.
  • Extended dashboard helpers and enrollment display logic to compute/render program-as-course enrollments on both the dashboard home and within program requirement sections.
  • Introduced a ModuleCard variant for stacked module display and added/updated Jest/RTL tests for the new behaviors.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/helpers.ts Adds helper functions to compute enrollment status for course runs and program enrollments.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/helpers.test.tsx Adds unit coverage for the new helper functions.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/ProgressBadge.tsx New UI component for displaying progress state (“Not Started”/“In Progress”/“Completed”).
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/ProgramAsCourseCard.tsx New composite card to display a program as a course with module list and date popover.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/ProgramAsCourseCard.test.tsx Adds RTL tests for rendering and the date popover interaction.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/ModuleCard.tsx New/updated card implementation used to render stacked module cards inside ProgramAsCourseCard.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/EnrollmentDisplay.tsx Integrates program-as-course rendering into dashboard home + program requirement sections and adds supporting queries/mappings.
frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/EnrollmentDisplay.test.tsx Adds coverage for program-as-course rendering on dashboard home and within program requirements.

return sum + parseInt(section.node.data.operator_value, 10)
}
return sum + section.courses.length
return sum + section.items.length
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

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

completedCount only counts items where resourceType === "course", but totalCount sums section.items.length (which now includes required programs and program-as-course items). This makes the "{completedCount} of {totalCount} courses" progress summary incorrect when program requirements are present. Either count completion/total consistently across all item types (and update the label accordingly), or restrict totalCount to course-only items to match completedCount.

Suggested change
return sum + section.items.length
const courseItemsCount = section.items.filter(
(item) => item.resourceType === "course",
).length
return sum + courseItemsCount

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

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

@gumaerc I think this is a real issue, see

Screenshot 2026-03-20 at 4 51 10 PM

Comment on lines 594 to 611
@@ -414,7 +607,7 @@ const ProgramEnrollmentDisplay: React.FC<ProgramEnrollmentDisplayProps> = ({
section.node.data.operator === "min_number_of" &&
section.node.data.operator_value
? parseInt(section.node.data.operator_value, 10)
: section.courses.length
: section.items.length

Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

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

Section progress uses sectionCompletedCount computed from course-only items, but sectionRequiredCount falls back to section.items.length (including programs). This will misreport progress (e.g., "Completed 0 of 2" when the section has 1 course + 1 required program). Align both counts to the same set of requirement types, or compute separate counts per type.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

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

Copilot's observation is true, though it is assumed that ... Program as Course will only have course children

@gumaerc I think you've added some comments around this (I will look more) but if we don't have one, a docstring for ProgramAsCourseCard would be worthwhile mentioning this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had added a docstring but added a clarification about this, thanks.

Copy link
Contributor

@ChristopherChudzicki ChristopherChudzicki left a comment

Choose a reason for hiding this comment

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

This looks good. Am noticing a few issues, and will still look at the code a bit more.

@gumaerc gumaerc force-pushed the cg/dashboard-crogram-display-2 branch from 4129e0f to 9230d5c Compare March 20, 2026 21:26
Comment on lines +162 to +172
function getIdsFromReqTree(
nodes: V2ProgramRequirement[],
type?: ReqTreeResourceType,
): ReqTreeResourceItem[] | number[] {
const resources = getReqTreeResources(nodes)
if (!type) return resources

return resources
.filter((resource) => resource.type === type)
.map((resource) => resource.id)
}
Copy link

Choose a reason for hiding this comment

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

Bug: The function getIdsFromReqTree is declared twice with conflicting signatures. The const declaration on line 178 overwrites the overloaded function, causing new calls expecting an array to fail.
Severity: CRITICAL

Suggested Fix

Rename one of the getIdsFromReqTree functions to resolve the naming conflict. The new overloaded function (lines 157-172) should have a unique name, and all new call sites in EnrollmentDisplay.tsx should be updated to use this new name. This will ensure that both the new and existing logic call the correct function implementations.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: frontends/main/src/common/mitxonline.ts#L157-L172

Potential issue: The file `frontends/main/src/common/mitxonline.ts` contains two
conflicting declarations for `getIdsFromReqTree`. An overloaded function is defined
(lines 157-172), but it is immediately overwritten by a `const` assignment with a
different implementation and return type (lines 178-200). New usages in
`EnrollmentDisplay.tsx` call the function expecting an array (`number[]` or
`ReqTreeResourceItem[]`) as per the new overloads. However, at runtime, they will
receive an object (`{ courseIds: number[], programIds: number[] }`), leading to
`TypeError` exceptions when attempting to iterate over the result (e.g., with `new
Set()` or `.map()`). This will cause a runtime crash when rendering program enrollments.

@pdpinch pdpinch changed the title "program as course" display "program as course" display on dashboard Mar 22, 2026
@pdpinch pdpinch changed the title "program as course" display on dashboard "program as course" display on learner dashboard Mar 22, 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