Skip to content

Commit 81d5b20

Browse files
feat: parse exam note as markdown
1 parent 9c16bf9 commit 81d5b20

3 files changed

Lines changed: 42 additions & 13 deletions

File tree

src/components/exam-card.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ export function ExamCard({ exam }: ExamCardProps) {
149149
navigate({
150150
to: ExamLandingRoute.to,
151151
params: { examId: exam.id },
152-
search: { note: exam.config.note },
153152
});
154153
}}
155154
style={{ width: "100%" }}

src/pages/exam-landing.tsx

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,45 @@ import {
77
Checkbox,
88
Code,
99
Progress,
10+
Spinner,
1011
} from "@chakra-ui/react";
1112
import { createRoute, useNavigate } from "@tanstack/react-router";
1213
import { Button, Spacer } from "@freecodecamp/ui";
1314
import { useEffect, useState } from "react";
14-
import { useMutation } from "@tanstack/react-query";
15+
import { useMutation, useQuery } from "@tanstack/react-query";
1516

1617
import { ProtectedRoute } from "../components/protected-route";
1718
import { Header } from "../components/header";
1819
import { rootRoute } from "./root";
1920
import { ExamRoute } from "./exam";
20-
import { checkForUpdate } from "../utils/fetch";
21+
import { checkForUpdate, getExams } from "../utils/fetch";
2122
import { restartApp } from "../utils/commands";
2223
import { captureException } from "@sentry/react";
23-
import { getErrorMessage } from "../utils/errors";
24+
import { captureAndNavigate, getErrorMessage } from "../utils/errors";
25+
import { PrismFormatted } from "../components/prism-formatted";
26+
import { parseMarkdown } from "../utils/markdown";
2427

2528
export function ExamLanding() {
2629
const [hasAgreed, setHasAgreed] = useState(false);
2730
const [progress, setProgress] = useState(0);
2831
const navigate = useNavigate();
2932

3033
const { examId } = ExamLandingRoute.useParams();
31-
const { note } = ExamLandingRoute.useSearch();
34+
35+
const noteQuery = useQuery({
36+
queryKey: ["exams"],
37+
queryFn: getExams,
38+
retry: false,
39+
refetchOnWindowFocus: false,
40+
select: (data) => {
41+
const exam = data.find((e) => e.id === examId);
42+
if (!exam) {
43+
throw new Error(`Invalid exam id ${examId}.`);
44+
}
45+
46+
return exam.config.note;
47+
},
48+
});
3249

3350
const updateMutation = useMutation({
3451
mutationKey: ["checkForUpdate"],
@@ -94,6 +111,10 @@ export function ExamLanding() {
94111
}
95112
}, []);
96113

114+
if (noteQuery.isError) {
115+
captureAndNavigate(noteQuery.error.message, navigate);
116+
}
117+
97118
return (
98119
<>
99120
<Header />
@@ -121,13 +142,20 @@ export function ExamLanding() {
121142
<Text>
122143
If you run out of time, your attempt will be auto-submitted.
123144
</Text>
124-
{!!note && (
125-
<>
126-
<Heading as="h2" size={"md"}>
127-
Exam Note
128-
</Heading>
129-
<Text>{note}</Text>
130-
</>
145+
{noteQuery.isFetching ? (
146+
<Spinner />
147+
) : (
148+
!!noteQuery.data && (
149+
<>
150+
<Heading as="h2" size={"md"}>
151+
Exam Note
152+
</Heading>
153+
<PrismFormatted
154+
text={parseMarkdown(noteQuery.data)}
155+
getCodeBlockAriaLabel={(c) => `${c} code`}
156+
/>
157+
</>
158+
)
131159
)}
132160
<Checkbox
133161
id="terms-agreement"
@@ -141,6 +169,8 @@ export function ExamLanding() {
141169
variant="primary"
142170
disabled={
143171
!hasAgreed ||
172+
noteQuery.isFetching ||
173+
noteQuery.isError ||
144174
updateMutation.isPending ||
145175
updateMutation.isError ||
146176
startExamMutation.isPending ||

src/pages/exam.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createRoute, Navigate, useNavigate } from "@tanstack/react-router";
1+
import { createRoute, Navigate } from "@tanstack/react-router";
22
import {
33
Box,
44
Center,

0 commit comments

Comments
 (0)