Skip to content

Commit 65811d5

Browse files
authored
enrollments dashboard expand collapse (#2195)
* add expand / collapse to enrollments display * use styled DashboardCard component * fix test and add one for the show more functionality * refactor list rendering code a bit * whoops had ternary backwards * fix issue with maintaining scroll position * restructure to allow for expand / collapse animation * don't nest lists and fix spacing * fix sorting * fix border issue * fix tests
1 parent 5b2569f commit 65811d5

File tree

2 files changed

+126
-28
lines changed

2 files changed

+126
-28
lines changed

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

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import React from "react"
2-
import { renderWithProviders, screen, setMockResponse } from "@/test-utils"
2+
import {
3+
renderWithProviders,
4+
screen,
5+
setMockResponse,
6+
user,
7+
} from "@/test-utils"
38
import { EnrollmentDisplay } from "./EnrollmentDisplay"
49
import * as mitxonline from "api/mitxonline-test-utils"
510
import moment from "moment"
@@ -9,7 +14,13 @@ const courseEnrollment = mitxonline.factories.enrollment.courseEnrollment
914
const grade = mitxonline.factories.enrollment.grade
1015
describe("EnrollmentDisplay", () => {
1116
const setupApis = () => {
12-
const ended = [
17+
const completed = [
18+
courseEnrollment({
19+
run: { title: "C Course Ended" },
20+
grades: [grade({ passed: true })],
21+
}),
22+
]
23+
const expired = [
1324
courseEnrollment({
1425
run: {
1526
title: "A Course Ended",
@@ -22,10 +33,6 @@ describe("EnrollmentDisplay", () => {
2233
end_date: faker.date.past().toISOString(),
2334
},
2435
}),
25-
courseEnrollment({
26-
run: { title: "C Course Ended" },
27-
grades: [grade({ passed: true })],
28-
}),
2936
]
3037
const started = [
3138
courseEnrollment({
@@ -54,7 +61,8 @@ describe("EnrollmentDisplay", () => {
5461
}),
5562
]
5663
const mitxonlineCourseEnrollments = faker.helpers.shuffle([
57-
...ended,
64+
...expired,
65+
...completed,
5866
...started,
5967
...notStarted,
6068
])
@@ -66,7 +74,7 @@ describe("EnrollmentDisplay", () => {
6674

6775
return {
6876
mitxonlineCourseEnrollments,
69-
mitxonlineCourses: { started, ended, notStarted },
77+
mitxonlineCourses: { completed, expired, started, notStarted },
7078
}
7179
}
7280

@@ -80,7 +88,28 @@ describe("EnrollmentDisplay", () => {
8088
const expectedTitles = [
8189
...mitxonlineCourses.started,
8290
...mitxonlineCourses.notStarted,
83-
...mitxonlineCourses.ended,
91+
...mitxonlineCourses.completed,
92+
].map((e) => e.run.title)
93+
94+
expectedTitles.forEach((title, i) => {
95+
expect(cards[i]).toHaveTextContent(title)
96+
})
97+
})
98+
99+
test("Clicking show all reveals ended courses", async () => {
100+
const { mitxonlineCourses } = setupApis()
101+
renderWithProviders(<EnrollmentDisplay />)
102+
103+
await user.click(screen.getByText("Show all"))
104+
105+
screen.getByRole("heading", { name: "My Learning" })
106+
107+
const cards = await screen.findAllByTestId("enrollment-card-desktop")
108+
const expectedTitles = [
109+
...mitxonlineCourses.started,
110+
...mitxonlineCourses.notStarted,
111+
...mitxonlineCourses.completed,
112+
...mitxonlineCourses.expired,
84113
].map((e) => e.run.title)
85114

86115
expectedTitles.forEach((title, i) => {

frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/EnrollmentDisplay.tsx

Lines changed: 88 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import React from "react"
22
import { enrollmentQueries } from "api/mitxonline-hooks/enrollment"
33
import {
4+
Collapse,
5+
Link,
46
PlainList,
57
PlainListProps,
68
Typography,
79
TypographyProps,
810
styled,
11+
theme,
912
} from "ol-components"
1013
import { useQuery } from "@tanstack/react-query"
1114
import { mitxonlineEnrollments } from "./transform"
@@ -42,7 +45,7 @@ const Title = styled(Typography)<Pick<TypographyProps, "component">>(
4245
}),
4346
)
4447

45-
const EnrollmentList = styled(PlainList)<Pick<PlainListProps, "itemSpacing">>(
48+
const EnrollmentsList = styled(PlainList)<Pick<PlainListProps, "itemSpacing">>(
4649
({ theme }) => ({
4750
[theme.breakpoints.down("md")]: {
4851
borderTop: `1px solid ${theme.custom.colors.lightGray2}`,
@@ -53,6 +56,23 @@ const EnrollmentList = styled(PlainList)<Pick<PlainListProps, "itemSpacing">>(
5356
}),
5457
)
5558

59+
const HiddenEnrollmentsList = styled(EnrollmentsList)({
60+
marginTop: "16px",
61+
[theme.breakpoints.down("md")]: {
62+
borderTop: "none",
63+
marginTop: "0",
64+
},
65+
})
66+
67+
const ShowAllContainer = styled.div(({ theme }) => ({
68+
display: "flex",
69+
justifyContent: "center",
70+
marginTop: "24px",
71+
[theme.breakpoints.down("md")]: {
72+
marginBottom: "24px",
73+
},
74+
}))
75+
5676
const alphabeticalSort = (a: DashboardCourse, b: DashboardCourse) =>
5777
a.title.localeCompare(b.title)
5878

@@ -65,15 +85,18 @@ const startsSooner = (a: DashboardCourse, b: DashboardCourse) => {
6585
return x.getTime() - y.getTime()
6686
}
6787
const sortEnrollments = (resources: DashboardCourse[]) => {
68-
const ended: DashboardCourse[] = []
88+
const expired: DashboardCourse[] = []
89+
const completed: DashboardCourse[] = []
6990
const started: DashboardCourse[] = []
7091
const notStarted: DashboardCourse[] = []
7192
resources.forEach((resource) => {
72-
if (
73-
resource.enrollment?.status === EnrollmentStatus.Completed ||
74-
(resource.run.endDate && new Date(resource.run.endDate) < new Date())
93+
if (resource.enrollment?.status === EnrollmentStatus.Completed) {
94+
completed.push(resource)
95+
} else if (
96+
resource.run.endDate &&
97+
new Date(resource.run.endDate) < new Date()
7598
) {
76-
ended.push(resource)
99+
expired.push(resource)
77100
} else if (
78101
resource.run.startDate &&
79102
new Date(resource.run.startDate) < new Date()
@@ -85,12 +108,62 @@ const sortEnrollments = (resources: DashboardCourse[]) => {
85108
})
86109

87110
return {
88-
ended: ended.sort(alphabeticalSort),
111+
completed: completed.sort(alphabeticalSort),
112+
expired: expired.sort(alphabeticalSort),
89113
started: started.sort(alphabeticalSort),
90114
notStarted: notStarted.sort(startsSooner),
91115
}
92116
}
93117

118+
interface EnrollmentExpandCollapseProps {
119+
shownEnrollments: DashboardCourse[]
120+
hiddenEnrollments: DashboardCourse[]
121+
}
122+
123+
const EnrollmentExpandCollapse: React.FC<EnrollmentExpandCollapseProps> = ({
124+
shownEnrollments,
125+
hiddenEnrollments,
126+
}) => {
127+
const [shown, setShown] = React.useState(false)
128+
129+
const handleToggle = (event: React.MouseEvent) => {
130+
event.preventDefault()
131+
setShown(!shown)
132+
}
133+
134+
return (
135+
<>
136+
<EnrollmentsList itemSpacing={"16px"}>
137+
{shownEnrollments.map((course) => (
138+
<DashboardCardStyled
139+
key={course.id}
140+
Component="li"
141+
dashboardResource={course}
142+
showNotComplete={false}
143+
/>
144+
))}
145+
</EnrollmentsList>
146+
<Collapse orientation="vertical" in={shown}>
147+
<HiddenEnrollmentsList itemSpacing={"16px"}>
148+
{hiddenEnrollments.map((course) => (
149+
<DashboardCardStyled
150+
key={course.id}
151+
Component="li"
152+
dashboardResource={course}
153+
showNotComplete={false}
154+
/>
155+
))}
156+
</HiddenEnrollmentsList>
157+
</Collapse>
158+
<ShowAllContainer>
159+
<Link color="red" size="medium" onClick={handleToggle}>
160+
{shown ? "Show less" : "Show all"}
161+
</Link>
162+
</ShowAllContainer>
163+
</>
164+
)
165+
}
166+
94167
const EnrollmentDisplay = () => {
95168
const { data: enrolledCourses } = useQuery({
96169
...enrollmentQueries.coursesList(),
@@ -106,24 +179,20 @@ const EnrollmentDisplay = () => {
106179
* The constants below are separate for impending "Show All" functionality.
107180
* The above TODO could be handled then.
108181
*/
109-
const { ended, started, notStarted } = sortEnrollments(enrolledCourses || [])
110-
const sorted = [...started, ...notStarted, ...ended]
182+
const { completed, expired, started, notStarted } = sortEnrollments(
183+
enrolledCourses || [],
184+
)
185+
const shownEnrollments = [...started, ...notStarted, ...completed]
111186

112187
return (
113188
<Wrapper>
114189
<Title variant="h5" component="h2">
115190
My Learning
116191
</Title>
117-
<EnrollmentList itemSpacing={"16px"}>
118-
{sorted?.map((course) => (
119-
<DashboardCardStyled
120-
key={course.id}
121-
Component="li"
122-
showNotComplete={false}
123-
dashboardResource={course}
124-
/>
125-
))}
126-
</EnrollmentList>
192+
<EnrollmentExpandCollapse
193+
shownEnrollments={shownEnrollments}
194+
hiddenEnrollments={expired}
195+
/>
127196
</Wrapper>
128197
)
129198
}

0 commit comments

Comments
 (0)