Skip to content

Commit e00ac72

Browse files
authored
org dashboard design updates (#2425)
* adjust styling, CTA copy and properly format HTML description from Wagtail * fix yarn lock * fix test * align CTA and indicator right on mobile
1 parent 1210dce commit e00ac72

File tree

9 files changed

+88
-30
lines changed

9 files changed

+88
-30
lines changed

frontends/api/src/mitxonline/clients.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,37 @@ const BASE_PATH =
2424

2525
const usersApi = new UsersApi(undefined, BASE_PATH, axiosInstance)
2626
const b2bApi = new B2bApi(undefined, BASE_PATH, axiosInstance)
27-
const enrollmentsApi = new EnrollmentsApi(undefined, BASE_PATH, axiosInstance)
2827
const programsApi = new ProgramsApi(undefined, BASE_PATH, axiosInstance)
2928
const programCollectionsApi = new ProgramCollectionsApi(
3029
undefined,
3130
BASE_PATH,
3231
axiosInstance,
3332
)
33+
3434
const programCertificatesApi = new ProgramCertificatesApi(
3535
undefined,
3636
BASE_PATH,
3737
axiosInstance,
3838
)
39+
3940
const coursesApi = new CoursesApi(undefined, BASE_PATH, axiosInstance)
41+
4042
const courseCertificatesApi = new CourseCertificatesApi(
4143
undefined,
4244
BASE_PATH,
4345
axiosInstance,
4446
)
4547

48+
const courseRunEnrollmentsApi = new EnrollmentsApi(
49+
undefined,
50+
BASE_PATH,
51+
axiosInstance,
52+
)
53+
4654
export {
4755
usersApi,
4856
b2bApi,
49-
enrollmentsApi,
57+
courseRunEnrollmentsApi,
5058
programsApi,
5159
programCollectionsApi,
5260
coursesApi,

frontends/api/src/mitxonline/hooks/enrollment/index.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { enrollmentQueries, enrollmentKeys } from "./queries"
22
import { useMutation, useQueryClient } from "@tanstack/react-query"
3-
import { b2bApi, enrollmentsApi } from "../../clients"
3+
import { b2bApi, courseRunEnrollmentsApi } from "../../clients"
44
import {
55
B2bApiB2bEnrollCreateRequest,
66
EnrollmentsApiEnrollmentsPartialUpdateRequest,
@@ -12,7 +12,7 @@ const useCreateEnrollment = (opts: B2bApiB2bEnrollCreateRequest) => {
1212
mutationFn: () => b2bApi.b2bEnrollCreate(opts),
1313
onSuccess: () => {
1414
queryClient.invalidateQueries({
15-
queryKey: enrollmentKeys.enrollmentsList(),
15+
queryKey: enrollmentKeys.courseRunEnrollmentsList(),
1616
})
1717
},
1818
})
@@ -23,10 +23,10 @@ const useUpdateEnrollment = (
2323
) => {
2424
const queryClient = useQueryClient()
2525
return useMutation({
26-
mutationFn: () => enrollmentsApi.enrollmentsPartialUpdate(opts),
26+
mutationFn: () => courseRunEnrollmentsApi.enrollmentsPartialUpdate(opts),
2727
onSuccess: () => {
2828
queryClient.invalidateQueries({
29-
queryKey: enrollmentKeys.enrollmentsList(),
29+
queryKey: enrollmentKeys.courseRunEnrollmentsList(),
3030
})
3131
},
3232
})
@@ -35,10 +35,11 @@ const useUpdateEnrollment = (
3535
const useDestroyEnrollment = (enrollmentId: number) => {
3636
const queryClient = useQueryClient()
3737
return useMutation({
38-
mutationFn: () => enrollmentsApi.enrollmentsDestroy({ id: enrollmentId }),
38+
mutationFn: () =>
39+
courseRunEnrollmentsApi.enrollmentsDestroy({ id: enrollmentId }),
3940
onSuccess: () => {
4041
queryClient.invalidateQueries({
41-
queryKey: enrollmentKeys.enrollmentsList(),
42+
queryKey: enrollmentKeys.courseRunEnrollmentsList(),
4243
})
4344
},
4445
})

frontends/api/src/mitxonline/hooks/enrollment/queries.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
11
import { queryOptions } from "@tanstack/react-query"
22
import type { CourseRunEnrollment } from "@mitodl/mitxonline-api-axios/v2"
33

4-
import { enrollmentsApi } from "../../clients"
4+
import { courseRunEnrollmentsApi } from "../../clients"
55

66
const enrollmentKeys = {
77
root: ["mitxonline", "enrollments"],
8-
enrollmentsList: () => [...enrollmentKeys.root, "programEnrollments", "list"],
8+
courseRunEnrollmentsList: () => [
9+
...enrollmentKeys.root,
10+
"courseRunEnrollments",
11+
"list",
12+
],
13+
programEnrollmentsList: () => [
14+
...enrollmentKeys.root,
15+
"programEnrollments",
16+
"list",
17+
],
918
}
1019

1120
const enrollmentQueries = {
12-
enrollmentsList: () =>
21+
courseRunEnrollmentsList: () =>
1322
queryOptions({
14-
queryKey: enrollmentKeys.enrollmentsList(),
23+
queryKey: enrollmentKeys.courseRunEnrollmentsList(),
1524
queryFn: async (): Promise<CourseRunEnrollment[]> => {
16-
return enrollmentsApi.enrollmentsList().then((res) => res.data)
25+
return courseRunEnrollmentsApi.enrollmentsList().then((res) => res.data)
1726
},
1827
}),
1928
}

frontends/main/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"@tanstack/react-query": "^5.66",
2323
"api": "workspace:*",
2424
"classnames": "^2.5.1",
25+
"dompurify": "^3.2.6",
2526
"formik": "^2.4.6",
2627
"iso-639-1": "^3.1.4",
2728
"lodash": "^4.17.21",

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ describe.each([
147147
course.enrollment?.status === EnrollmentStatus.NotEnrolled ||
148148
!course.enrollment
149149
) {
150-
expect(coursewareCTA).toHaveTextContent("Enroll")
150+
expect(coursewareCTA).toHaveTextContent("Start Course")
151151
} else {
152152
expect(coursewareCTA).toHaveTextContent(
153153
`${expected.labelPrefix} Course`,
@@ -163,7 +163,7 @@ describe.each([
163163
course.enrollment?.status === EnrollmentStatus.NotEnrolled ||
164164
!course.enrollment
165165
) {
166-
expect(coursewareCTA).toHaveTextContent("Enroll")
166+
expect(coursewareCTA).toHaveTextContent(`Start ${courseNoun}`)
167167
} else {
168168
expect(coursewareCTA).toHaveTextContent(
169169
`${expected.labelPrefix} ${courseNoun}`,
@@ -455,7 +455,7 @@ describe.each([
455455
status === undefined ||
456456
!course.enrollment
457457
) {
458-
expect(coursewareButton).toHaveTextContent("Enroll")
458+
expect(coursewareButton).toHaveTextContent("Start Course")
459459
} else {
460460
expect(coursewareButton).toHaveTextContent("Continue Course")
461461
}

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ const getCoursewareText = ({
132132
courseNoun: string
133133
}) => {
134134
if (!enrollmentStatus || enrollmentStatus === EnrollmentStatus.NotEnrolled) {
135-
return "Enroll"
135+
return `Start ${courseNoun}`
136136
}
137137
if (!endDate) return `Continue ${courseNoun}`
138138
if (isInPast(endDate)) {
@@ -398,7 +398,7 @@ const DashboardCard: React.FC<DashboardCardProps> = ({
398398
)
399399
const contextMenu = isLoading ? (
400400
<Skeleton variant="rectangular" width={12} height={24} />
401-
) : menuItems.length > 0 ? (
401+
) : (
402402
<SimpleMenu
403403
items={menuItems}
404404
trigger={
@@ -407,12 +407,13 @@ const DashboardCard: React.FC<DashboardCardProps> = ({
407407
variant="text"
408408
aria-label="More options"
409409
status={enrollment?.status}
410+
hidden={menuItems.length === 0}
410411
>
411412
<RiMore2Line />
412413
</MenuButton>
413414
}
414415
/>
415-
) : null
416+
)
416417
const desktopLayout = (
417418
<CardRoot
418419
screenSize="desktop"
@@ -455,7 +456,7 @@ const DashboardCard: React.FC<DashboardCardProps> = ({
455456
<Stack
456457
direction="row"
457458
alignItems="center"
458-
justifyContent="space-between"
459+
justifyContent="end"
459460
width="100%"
460461
>
461462
{startDateSection}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ const EnrollmentExpandCollapse: React.FC<EnrollmentExpandCollapseProps> = ({
175175

176176
const EnrollmentDisplay = () => {
177177
const { data: enrolledCourses, isLoading } = useQuery({
178-
...enrollmentQueries.enrollmentsList(),
178+
...enrollmentQueries.courseRunEnrollmentsList(),
179179
select: mitxonlineEnrollments,
180180
throwOnError: (error) => {
181181
const err = error as MaybeHasStatusAndDetail

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

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client"
22

33
import React from "react"
4+
import DOMPurify from "dompurify"
45
import Image from "next/image"
56
import { useFeatureFlagEnabled } from "posthog-js/react"
67
import { FeatureFlags } from "@/common/feature_flags"
@@ -89,22 +90,33 @@ const ProgramHeader = styled.div(({ theme }) => ({
8990
flexDirection: "column",
9091

9192
gap: "16px",
92-
backgroundColor: "rgba(243, 244, 248, 0.60)", // lightGray1 at 60%
93+
backgroundColor: theme.custom.colors.white,
9394
borderRadius: "8px 8px 0px 0px",
9495
border: `1px solid ${theme.custom.colors.lightGray2}`,
96+
borderBottom: `1px solid ${theme.custom.colors.red}`,
9597
}))
98+
const ProgramDescription = styled(Typography)({
99+
p: {
100+
margin: 0,
101+
},
102+
})
96103

97104
const OrgProgramCollectionDisplay: React.FC<{
98105
collection: DashboardProgramCollection
99106
enrollments?: CourseRunEnrollment[]
100107
orgId: number
101108
}> = ({ collection, enrollments, orgId }) => {
109+
const sanitizedDescription = DOMPurify.sanitize(collection.description ?? "")
102110
return (
103111
<ProgramRoot data-testid="org-program-collection-root">
104112
<ProgramHeader>
105113
<Typography variant="h5" component="h2">
106114
{collection.title}
107115
</Typography>
116+
<ProgramDescription
117+
variant="body2"
118+
dangerouslySetInnerHTML={{ __html: sanitizedDescription }}
119+
/>
108120
</ProgramHeader>
109121
<PlainList>
110122
{collection.programIds.map((programId) => (
@@ -122,10 +134,10 @@ const OrgProgramCollectionDisplay: React.FC<{
122134

123135
const OrgProgramDisplay: React.FC<{
124136
program: DashboardProgram
125-
enrollments?: CourseRunEnrollment[]
137+
courseRunEnrollments?: CourseRunEnrollment[]
126138
programLoading: boolean
127139
orgId?: number
128-
}> = ({ program, enrollments, programLoading, orgId }) => {
140+
}> = ({ program, courseRunEnrollments, programLoading, orgId }) => {
129141
const courses = useQuery(
130142
coursesQueries.coursesList({ id: program.courseIds, org_id: orgId }),
131143
)
@@ -135,16 +147,20 @@ const OrgProgramDisplay: React.FC<{
135147
if (programLoading || courses.isLoading) return skeleton
136148
const transformedCourses = transform.mitxonlineCourses({
137149
courses: courses.data?.results ?? [],
138-
enrollments: enrollments ?? [],
150+
enrollments: courseRunEnrollments ?? [],
139151
})
152+
const sanitizedHtml = DOMPurify.sanitize(program.description)
140153

141154
return (
142155
<ProgramRoot data-testid="org-program-root">
143156
<ProgramHeader>
144157
<Typography variant="h5" component="h2">
145158
{program.title}
146159
</Typography>
147-
<Typography variant="body1">{program.description}</Typography>
160+
<ProgramDescription
161+
variant="body2"
162+
dangerouslySetInnerHTML={{ __html: sanitizedHtml }}
163+
/>
148164
</ProgramHeader>
149165
<PlainList>
150166
{transform
@@ -217,7 +233,7 @@ const ProgramCard: React.FC<{
217233
Component="li"
218234
key={program.key}
219235
dashboardResource={course}
220-
courseNoun={"Course"}
236+
courseNoun={"Module"}
221237
offerUpgrade={false}
222238
titleHref={course.run.coursewareUrl ?? ""}
223239
buttonHref={course.run.coursewareUrl ?? ""}
@@ -241,7 +257,9 @@ const OrganizationContentInternal: React.FC<
241257
FeatureFlags.OrganizationDashboard,
242258
)
243259
const orgId = org.id
244-
const enrollments = useQuery(enrollmentQueries.enrollmentsList())
260+
const courseRunEnrollments = useQuery(
261+
enrollmentQueries.courseRunEnrollmentsList(),
262+
)
245263
const programs = useQuery(programsQueries.programsList({ org_id: orgId }))
246264
const programCollections = useQuery(
247265
programCollectionQueries.programCollectionsList({}),
@@ -270,7 +288,7 @@ const OrganizationContentInternal: React.FC<
270288
<OrgProgramDisplay
271289
key={program.key}
272290
program={program}
273-
enrollments={enrollments.data}
291+
courseRunEnrollments={courseRunEnrollments.data}
274292
programLoading={programs.isLoading}
275293
orgId={orgId}
276294
/>
@@ -286,7 +304,7 @@ const OrganizationContentInternal: React.FC<
286304
<OrgProgramCollectionDisplay
287305
key={collection.title}
288306
collection={transformedCollection}
289-
enrollments={enrollments.data}
307+
enrollments={courseRunEnrollments.data}
290308
orgId={orgId}
291309
/>
292310
)

yarn.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)