Skip to content

Commit 4c8d68d

Browse files
authored
Fix ordering of modules in UAI dashboard (#2232)
* add a function for sorting uai dashboard courses and associated tests * remove unnecessary manual ordering of unenrolled modules * move setupProgramsAndCourses to its proper spot in test-utils
1 parent 435ae2d commit 4c8d68d

File tree

5 files changed

+124
-45
lines changed

5 files changed

+124
-45
lines changed

frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/test-utils.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ import {
66
EnrollmentStatus,
77
} from "./types"
88
import type { DashboardCourse } from "./types"
9+
import * as u from "api/test-utils"
10+
import { urls, factories } from "api/mitxonline-test-utils"
11+
import { setMockResponse } from "../../../test-utils"
12+
import { mockOrgData } from "api/mitxonline-hooks/enrollment"
13+
14+
const makeCourses = factories.courses.courses
15+
const makeProgram = factories.programs.program
916

1017
const dashboardCourse: PartialFactory<DashboardCourse> = (...overrides) => {
1118
return mergeOverrides<DashboardCourse>(
@@ -31,4 +38,39 @@ const dashboardCourse: PartialFactory<DashboardCourse> = (...overrides) => {
3138
)
3239
}
3340

34-
export { dashboardCourse }
41+
const setupProgramsAndCourses = () => {
42+
const user = u.factories.user.user()
43+
setMockResponse.get(u.urls.userMe.get(), user)
44+
45+
const orgId = mockOrgData.orgX.id
46+
const coursesA = makeCourses({ count: 4 })
47+
const coursesB = makeCourses({ count: 3 })
48+
const programA = makeProgram({
49+
courses: coursesA.results.map((c) => c.id),
50+
})
51+
const programB = makeProgram({
52+
courses: coursesB.results.map((c) => c.id),
53+
})
54+
55+
setMockResponse.get(
56+
urls.programs.programsList({ orgId: mockOrgData.orgX.id }),
57+
{ results: [programA, programB] },
58+
)
59+
setMockResponse.get(urls.courses.coursesList({ id: programA.courses }), {
60+
results: coursesA.results,
61+
})
62+
setMockResponse.get(urls.courses.coursesList({ id: programB.courses }), {
63+
results: coursesB.results,
64+
})
65+
66+
return {
67+
orgId,
68+
user,
69+
programA,
70+
programB,
71+
coursesA: coursesA.results,
72+
coursesB: coursesB.results,
73+
}
74+
}
75+
76+
export { dashboardCourse, setupProgramsAndCourses }

frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/transform.test.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ import { factories as mitx } from "api/mitxonline-test-utils"
22
import * as transform from "./transform"
33
import { DashboardResourceType, EnrollmentStatus } from "./types"
44
import type { DashboardResource } from "./types"
5+
import {
6+
mitxonlineCourses,
7+
mitxonlineProgram,
8+
sortDashboardCourses,
9+
} from "./transform"
10+
import { setupProgramsAndCourses } from "./test-utils"
511

612
describe("Transforming mitxonline enrollment data to DashboardResource", () => {
713
test.each([
@@ -53,4 +59,33 @@ describe("Transforming mitxonline enrollment data to DashboardResource", () => {
5359
expect(transformed).toHaveLength(1)
5460
expect(transformed[0].run.certificateUpgradePrice).toEqual("10")
5561
})
62+
63+
test("sortDashboardCourses sorts courses by enrollment status and program order", () => {
64+
const { programA, coursesA } = setupProgramsAndCourses()
65+
66+
const enrollments = [
67+
mitx.enrollment.courseEnrollment({
68+
run: { course: { id: coursesA[0].id } },
69+
grades: [mitx.enrollment.grade({ passed: true })],
70+
enrollment_mode: "audit",
71+
}),
72+
mitx.enrollment.courseEnrollment({
73+
run: { course: { id: coursesA[1].id } },
74+
grades: [],
75+
enrollment_mode: "verified",
76+
}),
77+
]
78+
79+
const sortedCourses = sortDashboardCourses(
80+
mitxonlineProgram(programA),
81+
mitxonlineCourses({ courses: coursesA, enrollments }),
82+
)
83+
84+
expect(sortedCourses.map((course) => course.id)).toEqual([
85+
`mitxonline-course-${coursesA[1].id}`, // Enrolled course
86+
`mitxonline-course-${coursesA[0].id}`, // Completed course
87+
`mitxonline-course-${coursesA[2].id}`, // Not enrolled course
88+
`mitxonline-course-${coursesA[3].id}`, // Not enrolled course
89+
])
90+
})
5691
})

frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/transform.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,34 @@ const mitxonlineProgram = (raw: V2Program): DashboardProgram => {
105105
}
106106
}
107107

108-
export { mitxonlineEnrollments, mitxonlineCourses, mitxonlineProgram }
108+
const sortDashboardCourses = (
109+
program: DashboardProgram,
110+
courses: DashboardCourse[],
111+
) => {
112+
return courses.sort((a, b) => {
113+
const aCompleted = a.enrollment?.status === EnrollmentStatus.Completed
114+
const bCompleted = b.enrollment?.status === EnrollmentStatus.Completed
115+
const aEnrolled = a.enrollment?.status === EnrollmentStatus.Enrolled
116+
const bEnrolled = b.enrollment?.status === EnrollmentStatus.Enrolled
117+
if (aEnrolled && !bEnrolled) {
118+
return -1
119+
}
120+
if (!aEnrolled && bEnrolled) {
121+
return 1
122+
}
123+
if (aCompleted && !bCompleted) {
124+
return -1
125+
}
126+
if (!aCompleted && bCompleted) {
127+
return 1
128+
}
129+
return 0
130+
})
131+
}
132+
133+
export {
134+
mitxonlineEnrollments,
135+
mitxonlineCourses,
136+
mitxonlineProgram,
137+
sortDashboardCourses,
138+
}

frontends/main/src/app-pages/DashboardPage/OrganizationContent.test.tsx

Lines changed: 14 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import React from "react"
22
import { renderWithProviders, screen, within } from "@/test-utils"
33
import OrganizationContent from "./OrganizationContent"
4-
import * as u from "api/test-utils"
54
import { setMockResponse } from "api/test-utils"
65
import { urls, factories } from "api/mitxonline-test-utils"
76
import { mockOrgData } from "api/mitxonline-hooks/enrollment"
87
import { useFeatureFlagEnabled } from "posthog-js/react"
8+
import {
9+
mitxonlineCourses,
10+
mitxonlineProgram,
11+
sortDashboardCourses,
12+
} from "./CoursewareDisplay/transform"
13+
import { setupProgramsAndCourses } from "./CoursewareDisplay/test-utils"
914

1015
const makeCourseEnrollment = factories.enrollment.courseEnrollment
1116
const makeGrade = factories.enrollment.grade
12-
const makeProgram = factories.programs.program
13-
const makeCourses = factories.courses.courses
1417

1518
jest.mock("posthog-js/react")
1619
const mockedUseFeatureFlagEnabled = jest
@@ -22,41 +25,6 @@ describe("OrganizationContent", () => {
2225
mockedUseFeatureFlagEnabled.mockReturnValue(true)
2326
})
2427

25-
const setupProgramsAndCourses = () => {
26-
const user = u.factories.user.user()
27-
setMockResponse.get(u.urls.userMe.get(), user)
28-
29-
const orgId = mockOrgData.orgX.id
30-
const coursesA = makeCourses({ count: 4 })
31-
const coursesB = makeCourses({ count: 3 })
32-
const programA = makeProgram({
33-
courses: coursesA.results.map((c) => c.id),
34-
})
35-
const programB = makeProgram({
36-
courses: coursesB.results.map((c) => c.id),
37-
})
38-
39-
setMockResponse.get(
40-
urls.programs.programsList({ orgId: mockOrgData.orgX.id }),
41-
{ results: [programA, programB] },
42-
)
43-
setMockResponse.get(urls.courses.coursesList({ id: programA.courses }), {
44-
results: coursesA.results,
45-
})
46-
setMockResponse.get(urls.courses.coursesList({ id: programB.courses }), {
47-
results: coursesB.results,
48-
})
49-
50-
return {
51-
orgId,
52-
user,
53-
programA,
54-
programB,
55-
coursesA: coursesA.results,
56-
coursesB: coursesB.results,
57-
}
58-
}
59-
6028
it("displays a header for each program returned and cards for courses in program", async () => {
6129
const { orgId, programA, programB, coursesA, coursesB } =
6230
setupProgramsAndCourses()
@@ -82,7 +50,7 @@ describe("OrganizationContent", () => {
8250
})
8351

8452
test("Shows correct enrollment status", async () => {
85-
const { orgId, coursesA } = setupProgramsAndCourses()
53+
const { orgId, programA, coursesA } = setupProgramsAndCourses()
8654
const enrollments = [
8755
makeCourseEnrollment({
8856
run: { course: { id: coursesA[0].id, title: coursesA[0].title } },
@@ -104,15 +72,19 @@ describe("OrganizationContent", () => {
10472
"enrollment-card-desktop",
10573
)
10674
expect(cards.length).toBeGreaterThan(0)
75+
const sortedCourses = sortDashboardCourses(
76+
mitxonlineProgram(programA),
77+
mitxonlineCourses({ courses: coursesA, enrollments: enrollments }),
78+
)
10779
cards.forEach((card, i) => {
108-
const course = coursesA[i]
80+
const course = sortedCourses[i]
10981
expect(card).toHaveTextContent(course.title)
11082
const indicator = within(card).getByTestId("enrollment-status")
11183

11284
if (i === 0) {
113-
expect(indicator).toHaveTextContent("Completed")
114-
} else if (i === 1) {
11585
expect(indicator).toHaveTextContent("Enrolled")
86+
} else if (i === 1) {
87+
expect(indicator).toHaveTextContent("Completed")
11688
} else {
11789
expect(indicator).toHaveTextContent("Not Enrolled")
11890
}

frontends/main/src/app-pages/DashboardPage/OrganizationContent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ const OrgProgramDisplay: React.FC<{
146146
<Typography variant="body1">{program.description}</Typography>
147147
</ProgramHeader>
148148
<PlainList itemSpacing={0}>
149-
{courses.map((course) => (
149+
{transform.sortDashboardCourses(program, courses).map((course) => (
150150
<DashboardCardStyled
151151
Component="li"
152152
key={course.id}

0 commit comments

Comments
 (0)