Skip to content

Commit f3c9824

Browse files
authored
Merge pull request #11992 from ethereum/quiz-types
Strongly type all Quiz data types [refactor]
2 parents acd8e2f + 73a047f commit f3c9824

File tree

13 files changed

+101
-112
lines changed

13 files changed

+101
-112
lines changed

src/components/Quiz/QuizWidget/AnswerIcon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { CorrectIcon, IncorrectIcon, TrophyIcon } from "../../icons/quiz"
77

88
import { AnswerStatus } from "./useQuizWidget"
99

10-
interface AnswerIconProps {
10+
type AnswerIconProps = {
1111
answerStatus: AnswerStatus
1212
}
1313

src/components/Quiz/QuizWidget/QuizRadioGroup.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
VisuallyHidden,
1616
} from "@chakra-ui/react"
1717

18-
import { TranslationKey } from "@/lib/types"
18+
import type { AnswerKey, TranslationKey } from "@/lib/types"
1919

2020
import { useQuizWidgetContext } from "./context"
2121

@@ -28,7 +28,7 @@ export const QuizRadioGroup = () => {
2828
} = useQuizWidgetContext()
2929
const { t } = useTranslation("learn-quizzes")
3030

31-
const handleSelection = (answerId: string) => {
31+
const handleSelection = (answerId: AnswerKey) => {
3232
const isCorrect =
3333
answerId === questions[currentQuestionIndex].correctAnswerId
3434
setCurrentQuestionAnswerChoice({ answerId, isCorrect })

src/components/Quiz/QuizWidget/context.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { createContext, Dispatch, SetStateAction, useContext } from "react"
22

3-
import { QuizStatus, UserStats } from "@/lib/types"
4-
import { AnswerChoice, Quiz } from "@/lib/interfaces"
3+
import { AnswerChoice, Quiz, QuizKey, QuizStatus, UserStats } from "@/lib/types"
54

65
import { AnswerStatus } from "./useQuizWidget"
76

@@ -12,12 +11,12 @@ type QuizWidgetContextType = Quiz & {
1211
showResults: boolean
1312
currentQuestionAnswerChoice: AnswerChoice | null
1413
quizPageProps:
15-
| {
16-
currentHandler: (nextKey: string) => void
17-
statusHandler: (status: QuizStatus) => void
18-
nextQuiz: string | undefined
19-
}
20-
| false
14+
| {
15+
currentHandler: (nextKey: QuizKey) => void
16+
statusHandler: (status: QuizStatus) => void
17+
nextQuiz: QuizKey | undefined
18+
}
19+
| false
2120
numberOfCorrectAnswers: number
2221
quizScore: number
2322
ratioCorrect: number

src/components/Quiz/QuizWidget/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
VStack,
1010
} from "@chakra-ui/react"
1111

12-
import { QuizStatus, UserStats } from "@/lib/types"
12+
import type { QuizKey, QuizStatus, UserStats } from "@/lib/types"
1313

1414
import Translation from "@/components/Translation"
1515

@@ -28,7 +28,7 @@ import { useQuizWidget } from "./useQuizWidget"
2828
import { useRtlFlip } from "@/hooks/useRtlFlip"
2929

3030
type CommonProps = {
31-
quizKey: string
31+
quizKey: QuizKey
3232
updateUserStats: Dispatch<SetStateAction<UserStats>>
3333
}
3434

@@ -39,7 +39,7 @@ type StandaloneQuizProps = CommonProps & {
3939
}
4040

4141
type QuizPageProps = CommonProps & {
42-
currentHandler: (nextKey: string) => void
42+
currentHandler: (nextKey: QuizKey) => void
4343
statusHandler: (status: QuizStatus) => void
4444
isStandaloneQuiz?: false
4545
}
@@ -76,7 +76,7 @@ const QuizWidget = ({
7676

7777
const quizPageProps = useRef<
7878
| (Required<Pick<QuizWidgetProps, "currentHandler" | "statusHandler">> & {
79-
nextQuiz: string | undefined
79+
nextQuiz: QuizKey | undefined
8080
})
8181
| false
8282
>(false)

src/components/Quiz/QuizWidget/useQuizWidget.tsx

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import { useEffect, useMemo, useRef, useState } from "react"
1+
import { useEffect, useMemo, useState } from "react"
22
import { shuffle } from "lodash"
33
import { useTranslation } from "next-i18next"
44

5-
import {
5+
import type {
66
AnswerChoice,
77
Question,
88
Quiz,
9+
QuizKey,
910
RawQuestion,
1011
RawQuiz,
11-
} from "@/lib/interfaces"
12+
} from "@/lib/types"
1213

1314
import allQuizzesData from "@/data/quizzes"
1415
import questionBank from "@/data/quizzes/questionBank"
@@ -28,11 +29,9 @@ export const useQuizWidget = ({
2829
const { t } = useTranslation()
2930

3031
const [quizData, setQuizData] = useState<Quiz | null>(null)
31-
const [nextQuiz, setNextQuiz] = useState<string | undefined>(undefined)
32-
const [userQuizProgress, setUserQuizProgress] = useState<Array<AnswerChoice>>(
33-
[]
34-
)
35-
const [showAnswer, setShowAnswer] = useState<boolean>(false)
32+
const [nextQuiz, setNextQuiz] = useState<QuizKey | undefined>(undefined)
33+
const [userQuizProgress, setUserQuizProgress] = useState<AnswerChoice[]>([])
34+
const [showAnswer, setShowAnswer] = useState(false)
3635
const [currentQuestionAnswerChoice, setCurrentQuestionAnswerChoice] =
3736
useState<AnswerChoice | null>(null)
3837

@@ -46,18 +45,9 @@ export const useQuizWidget = ({
4645
setUserQuizProgress([])
4746
setShowAnswer(false)
4847

49-
const currentQuizKey =
50-
quizKey ||
51-
Object.keys(allQuizzesData).filter((quizUri) =>
52-
window?.location.href.includes(quizUri)
53-
)[0] ||
54-
null
55-
56-
if (!currentQuizKey) return
57-
5848
// Get quiz data from key, shuffle, then truncate if necessary
59-
const rawQuiz: RawQuiz = allQuizzesData[currentQuizKey]
60-
const questions: Array<Question> = rawQuiz.questions.map((id) => {
49+
const rawQuiz: RawQuiz = allQuizzesData[quizKey]
50+
const questions: Question[] = rawQuiz.questions.map((id) => {
6151
const rawQuestion: RawQuestion = questionBank[id]
6252
return { id, ...rawQuestion }
6353
})
@@ -99,10 +89,7 @@ export const useQuizWidget = ({
9989
const quizScore = Math.floor(ratioCorrect * 100)
10090
const isPassingScore = quizScore > PASSING_QUIZ_SCORE
10191

102-
const showConfetti = useMemo<boolean>(
103-
() => !!quizData && showResults && isPassingScore,
104-
[quizData, showResults, isPassingScore]
105-
)
92+
const showConfetti = !!quizData && showResults && isPassingScore
10693

10794
useEffect(() => {
10895
if (!showResults) return

src/components/Quiz/QuizzesList.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from "react"
22
import { Heading, OrderedList, Stack, Text } from "@chakra-ui/react"
33

4-
import type { QuizzesSection, UserStats } from "@/lib/types"
4+
import type { QuizKey, QuizzesSection, UserStats } from "@/lib/types"
55

66
import { trackCustomEvent } from "@/lib/utils/matomo"
77

@@ -11,12 +11,12 @@ import Translation from "../Translation"
1111

1212
import QuizItem from "./QuizItem"
1313

14-
export interface QuizzesListProps {
14+
type QuizzesListProps = {
1515
userStats: UserStats
16-
content: Array<QuizzesSection>
16+
content: QuizzesSection[]
1717
headingId: string
1818
descriptionId: string
19-
quizHandler: (id: string) => void
19+
quizHandler: (id: QuizKey) => void
2020
modalHandler: (isModalOpen: boolean) => void
2121
}
2222

src/components/Quiz/QuizzesModal.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ type QuizzesModalProps = Omit<ModalProps, "isCentered" | "scrollBehavior"> & {
1515
quizStatus: QuizStatus
1616
}
1717

18-
const QuizzesModal = ({ children, quizStatus, ...rest }: QuizzesModalProps) => {
18+
const QuizzesModal = ({
19+
children,
20+
quizStatus,
21+
...props
22+
}: QuizzesModalProps) => {
1923
const getStatusColor = (): ModalContentProps["bg"] => {
2024
if (quizStatus === "neutral") {
2125
return "neutral"
@@ -31,7 +35,7 @@ const QuizzesModal = ({ children, quizStatus, ...rest }: QuizzesModalProps) => {
3135
isCentered
3236
size={{ base: "full", md: "xl" }}
3337
scrollBehavior="inside"
34-
{...rest}
38+
{...props}
3539
>
3640
<ModalOverlay bg="blackAlpha.700" />
3741

src/components/Quiz/useLocalQuizData.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { UserStats } from "@/lib/types"
1+
import type { CompletedQuizzes, UserStats } from "@/lib/types"
22

33
import { USER_STATS_KEY } from "@/lib/constants"
44

@@ -7,7 +7,7 @@ import { useLocalStorage } from "@/hooks/useLocalStorage"
77
export const INITIAL_USER_STATS: UserStats = {
88
score: 0,
99
average: [],
10-
completed: {},
10+
completed: {} as CompletedQuizzes,
1111
}
1212

1313
export const useLocalQuizData = () => {

src/data/quizzes/index.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
// Import data types
2-
import type { QuizzesSection } from "@/lib/types"
3-
import type { RawQuizzes } from "@/lib/interfaces"
1+
import type { QuizzesSection, RawQuizzes } from "@/lib/types"
42

53
// Declare hash-map of quizzes based on slug key
6-
const quizzes: RawQuizzes = {
4+
const quizzes = {
75
"what-is-ethereum": {
86
title: "what-is-ethereum",
97
questions: ["a001", "a002", "a003", "a004", "a005"],
@@ -48,7 +46,7 @@ const quizzes: RawQuizzes = {
4846
title: "run-a-node",
4947
questions: ["l001", "l002", "l003", "l004", "l005", "l006"],
5048
},
51-
}
49+
} satisfies RawQuizzes
5250

5351
export const ethereumBasicsQuizzes: QuizzesSection[] = [
5452
{

src/data/quizzes/questionBank.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// Import data types
2-
import type { QuestionBank } from "@/lib/interfaces"
2+
import type { QuestionBank } from "@/lib/types"
33

44
// Declare hash map of question bank
5-
const questionBank: QuestionBank = {
5+
const questionBank = {
66
// What is Ethereum?
77
a001: {
88
prompt: "a001-prompt",
@@ -1348,6 +1348,6 @@ const questionBank: QuestionBank = {
13481348
],
13491349
correctAnswerId: "l006-b",
13501350
},
1351-
}
1351+
} as const satisfies QuestionBank
13521352

13531353
export default questionBank

0 commit comments

Comments
 (0)