Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Learn quizzes #8094

Merged
merged 58 commits into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
fa9d865
base start to quiz component
corwintines Sep 17, 2022
f8bcc47
resolve quiz based on url, or with quizKey
corwintines Sep 17, 2022
7a711ba
temp
corwintines Sep 22, 2022
e1cf364
Merge branch 'dev' into learnQuizzes
wackerow Oct 8, 2022
4880b35
Add quiz data types
wackerow Oct 8, 2022
2792437
refactor quiz-data data structure
wackerow Oct 8, 2022
815ea35
update QuizQuestion to accept callback function
wackerow Oct 8, 2022
0a22340
set up action handlers for Quiz, clean up useState
wackerow Oct 8, 2022
386c6fd
update types
wackerow Oct 10, 2022
179d540
update QuizWidget logic
wackerow Oct 10, 2022
fe4ddc5
update QuizQuestion
wackerow Oct 10, 2022
4dbb1e6
feat: QuizWidget mvp
wackerow Oct 10, 2022
a2251f9
add trophy/status svg indicators
wackerow Oct 11, 2022
0393f71
update question bank and quizzes
wackerow Oct 11, 2022
69b0219
add QuizWidget to eth and wallets pages
wackerow Oct 11, 2022
5802edd
fix quiz svg colors
wackerow Oct 11, 2022
343c1df
quis adjustments
wackerow Oct 12, 2022
219004f
add QuizWidget to nft/web3/security pages
wackerow Oct 12, 2022
72a786a
fix genesis year
wackerow Oct 12, 2022
1ca0ff5
Update QuizQuestion styling
wackerow Oct 18, 2022
cb47e81
styling adjustments
wackerow Oct 20, 2022
fc18ef7
add Spinner loading indicator
wackerow Oct 20, 2022
d1c384d
Create QuizRadioGroup.tsx
wackerow Oct 20, 2022
fb9c5bc
update QuizWidget with QuizRadioGroup
wackerow Oct 20, 2022
0fec992
update QuizWidget with share tweet functionality
wackerow Oct 20, 2022
840d399
internationalize percentages
wackerow Oct 20, 2022
0dd51c2
deprecate QuizQuestion component
wackerow Oct 20, 2022
1dfb514
feat: custom matomo tracking for quiz widget
wackerow Oct 22, 2022
e9e54d1
apply suggestions from code review
wackerow Oct 24, 2022
44a1c97
remove "quizButton" theming
wackerow Oct 25, 2022
45c5074
update theming variables
wackerow Oct 25, 2022
69adef7
update constants, add numberToPercent util
wackerow Oct 25, 2022
810e8be
update logic for Quiz components
wackerow Oct 25, 2022
fa61dbd
add explicit quizKey prop
wackerow Oct 25, 2022
22f4b0a
clean up magic numbers and progress bar logic
wackerow Oct 25, 2022
ce9805e
small layout adjustments
wackerow Oct 25, 2022
13a08d3
getLocaleForNumberFormat with numberToPercent
wackerow Oct 26, 2022
7628ecb
chore: code clean up
wackerow Oct 26, 2022
2cc1e87
feat: improve progress bar responsiveness
wackerow Oct 26, 2022
7f7fe11
Merge branch 'dev' into learnQuizzes
wackerow Oct 26, 2022
532b041
fix: hover outline coloring
wackerow Oct 26, 2022
7a8e293
update prop typing for numberToPercent util
wackerow Oct 26, 2022
dc447fd
fix: confetti z-index below copy and trophy
wackerow Oct 26, 2022
4cb155c
fix: button layout
wackerow Oct 26, 2022
d08bb9a
conditionally hide "Try again" on 100%
wackerow Oct 26, 2022
485c1cc
mobile responsiveness for QuizSummary
wackerow Oct 26, 2022
594352b
chore: improve DRY code
wackerow Oct 26, 2022
d58cb8e
chore: remove comments
wackerow Oct 26, 2022
e7cc5e0
clean up duplicate function
corwintines Oct 27, 2022
4c79ace
remove unused function
corwintines Oct 27, 2022
9711871
remove duplicate function
corwintines Oct 27, 2022
d52fa01
import: layer 2 questions
wackerow Oct 27, 2022
6694807
import: merge quiz questions
wackerow Oct 27, 2022
f29fc4f
adjust padding
wackerow Oct 27, 2022
6b9a841
Update content
minimalsm Oct 27, 2022
e824f84
Update Twitter hashtag for quiz share function
minimalsm Oct 27, 2022
afb076b
fix: add hashlink to #quiz for twitter share
wackerow Oct 27, 2022
c094343
fix: padding adjustments
wackerow Oct 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/@chakra-ui/gatsby-plugin/foundations/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ const colors = {
800: "#451900",
},
red: {
100: "#F7C8C8",
500: "#b80000",
900: "#1B0C0C",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do find this red hard to see in dark mode

},
green: {
100: "#C8F7D8",
400: "#48BB78",
wackerow marked this conversation as resolved.
Show resolved Hide resolved
500: "#109e62",
900: "#0A160E",
wackerow marked this conversation as resolved.
Show resolved Hide resolved
},
yellow: {
200: "#fff8df",
Expand Down
1 change: 1 addition & 0 deletions src/@chakra-ui/gatsby-plugin/foundations/shadows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const shadows = {
outline: "0 0 0 4px var(--eth-colors-primaryHover)",
table:
"0 14px 66px rgba(0,0,0,.07), 0 10px 17px rgba(0,0,0,.03), 0 4px 7px rgba(0,0,0,.05)",
drop: "0 4px 17px 0 var(--eth-colors-blackAlpha-200)",
tableBox: {
light:
"0 14px 66px rgba(0,0,0,.07), 0 10px 17px rgba(0,0,0,.03), 0 4px 7px rgba(0,0,0,.05)",
Expand Down
7 changes: 6 additions & 1 deletion src/@chakra-ui/gatsby-plugin/semanticTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,17 @@ const semanticTokens = {
primaryLight: { _light: "blue.100", _dark: "orange.100" },
primaryDark: { _light: "blue.700", _dark: "orange.800" },
primaryHover: { _light: "blue.300", _dark: "orange.300" },
primaryPressed: { _light: "blue.300", _dark: "orange.800" },
body: { _light: "gray.700", _dark: "gray.100" },
bodyInverted: { _light: "gray.100", _dark: "gray.700" },
bodyLight: { _light: "gray.500", _dark: "gray.100" },
disabled: { _light: "gray.400", _dark: "gray.500" },
background: { _light: "white", _dark: "gray.700" },
success: "green.500",
neutral: { _light: "white", _dark: "gray.900" },
success: { _light: "green.500", _dark: "green.400" },
successNeutral: { _light: "green.100", _dark: "green.900" },
error: "red.500",
errorNeutral: { _light: "red.100", _dark: "red.900" },
Comment on lines +37 to +47
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc: @nloureiro @konopkja
Take a look and let me know if you disagree with anything here, or if you have suggestions on any naming improvements. If we keep these we may want to update the DS with the ones that are missing.

attention: "yellow.200",
},
}
Expand Down
3 changes: 3 additions & 0 deletions src/assets/quiz/correct.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/quiz/incorrect.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions src/assets/quiz/star-confetti.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/assets/quiz/trophy.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/CopyToClipboard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef } from "react"
import ClipboardJS from "clipboard"
import { Box } from '@chakra-ui/react'
import { Box } from "@chakra-ui/react"

export interface IProps {
text: string
Expand Down
7 changes: 1 addition & 6 deletions src/components/EventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,7 @@ const EventCard: React.FC<IProps> = ({
</Text>
<Emoji text=":round_pushpin:" fontSize="md" marginLeft={2} />
</Text>
<Heading
as="h3"
marginTop={0}
fontWeight="semibold"
lineHeight={1.4}
>
<Heading as="h3" marginTop={0} fontWeight="semibold" lineHeight={1.4}>
{title}
</Heading>
<Text opacity={0.8}>{description}</Text>
Expand Down
153 changes: 153 additions & 0 deletions src/components/Quiz/QuizRadioGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// Import libraries
import React, { useMemo } from "react"
import {
Box,
chakra,
Circle,
Flex,
RadioProps,
Text,
useRadio,
useRadioGroup,
} from "@chakra-ui/react"

// Import types
import { Question } from "../../types"

// Interfaces
export interface CustomRadioProps extends RadioProps {
index: number
label: string
}
export interface IProps {
questionData: Question
showAnswer: boolean
handleSelection: (answerId: string) => void
selectedAnswer: string | null
}

// Component
const QuizRadioGroup: React.FC<IProps> = ({
questionData,
showAnswer,
handleSelection,
selectedAnswer,
}) => {
const { getRadioProps, getRootProps } = useRadioGroup({
onChange: handleSelection,
})
const { prompt, answers, correctAnswerId } = questionData

// Memoized values
const explanation = useMemo<string>(() => {
if (!selectedAnswer) return ""
return answers.filter(({ id }) => id === selectedAnswer)[0].explanation
}, [selectedAnswer])

const isSelectedCorrect = useMemo<boolean>(
() => correctAnswerId === selectedAnswer,
[selectedAnswer]
)

// Custom radio button component
const CustomRadio: React.FC<CustomRadioProps> = ({
index,
label,
...radioProps
}) => {
const { state, getInputProps, getCheckboxProps, htmlProps } =
useRadio(radioProps)

// Memoized values
const buttonBg = useMemo<string>(() => {
if (!state.isChecked) return "bodyInverted"
if (!showAnswer) return "primary"
if (!isSelectedCorrect) return "error"
return "success"
}, [state.isChecked, showAnswer, isSelectedCorrect])

// Render CustomRadio component
return (
<chakra.label {...htmlProps} cursor="pointer" data-group w="100%">
<input {...getInputProps({})} hidden />
<Flex
{...getCheckboxProps()}
w="100%"
p={2}
alignItems="center"
bg={buttonBg}
color={state.isChecked ? "white" : "text"}
borderRadius="base"
_hover={{
boxShadow: showAnswer ? "none" : "primary",
outline: showAnswer
? "none"
: "1px solid var(--eth-colors-primary)",
cursor: showAnswer ? "default" : "pointer",
}}
>
<Circle
size="25px"
bg={
showAnswer
? "white"
: state.isChecked
? "primaryPressed"
: "disabled"
}
_groupHover={{
bg: showAnswer ? "white" : "primaryPressed",
}}
me={2}
>
<Text
m="0"
fontWeight="700"
fontSize="lg"
color={
!showAnswer ? "white" : isSelectedCorrect ? "success" : "error"
}
>
{String.fromCharCode(97 + index).toUpperCase()}
wackerow marked this conversation as resolved.
Show resolved Hide resolved
</Text>
</Circle>
{label}
</Flex>
</chakra.label>
)
}

// Render QuizRadioGroup
return (
<Flex {...getRootProps()} direction="column" w="100%">
<Text fontWeight="700" fontSize="2xl" mb={6}>
{prompt}
</Text>
<Flex direction="column" gap={4}>
{answers.map(({ id, label }, index) => {
const display =
!showAnswer || id === selectedAnswer ? "inline-flex" : "none"
return (
<CustomRadio
key={id}
display={display}
index={index}
label={label}
{...getRadioProps({ value: id })}
/>
)
})}
</Flex>
{showAnswer && (
<Box mt={5}>
<Text fontWeight="bold" mt={0} mb={2}>
Explanation
</Text>
<Text m={0}>{explanation}</Text>
</Box>
)}
</Flex>
)
}

export default QuizRadioGroup
wackerow marked this conversation as resolved.
Show resolved Hide resolved
87 changes: 87 additions & 0 deletions src/components/Quiz/QuizSummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Import libraries
import React, { useMemo } from "react"
import { Box, Flex, Text, useMediaQuery } from "@chakra-ui/react"
import { useIntl } from "react-intl"

// Import utilities
import { numberToPercent } from "../../utils/numberToPercent"

// Import constants
import { PASSING_QUIZ_SCORE } from "../../constants"

// Interfaces
export interface IProps {
correctCount: number
questionCount: number
}

// Component
const QuizSummary: React.FC<IProps> = ({ correctCount, questionCount }) => {
const { locale } = useIntl()
const [largerThanMobile] = useMediaQuery("(min-width: 30em)")

// Memoized values
const ratioCorrect = useMemo<number>(
() => correctCount / questionCount,
[correctCount, questionCount]
)

const score = useMemo<number>(
() => Math.floor(ratioCorrect * 100),
[ratioCorrect]
)

const isPassingScore = useMemo<boolean>(
() => score > PASSING_QUIZ_SCORE,
[score]
)

const valueStyles = { fontWeight: "700", mb: 2 }
const labelStyles = { fontSize: "sm", m: 0, color: "disabled" }

// Render QuizSummary component
return (
<Box w="full" mb={10} fontSize={["xl", "2xl"]}>
<Text fontWeight="700" textAlign="center">
{isPassingScore ? "You passed the quiz!" : "Your results"}
</Text>
<Flex
p={4}
justify="center"
boxShadow="drop"
bg="background"
mx="auto"
w="fit-content"
sx={{
"div:not(:last-of-type)": {
borderEnd: "1px",
borderColor: "disabled",
},
div: {
p: 4,
flexDirection: "column",
alignItems: "center",
},
}}
overflowX="hidden"
>
<Flex>
<Text {...valueStyles}>{numberToPercent(ratioCorrect, locale)}</Text>
<Text {...labelStyles}>Score</Text>
</Flex>
<Flex>
<Text {...valueStyles}>+{correctCount}</Text>
<Text {...labelStyles}>Correct</Text>
</Flex>
{largerThanMobile && (
<Flex>
<Text {...valueStyles}>{questionCount}</Text>
<Text {...labelStyles}>Total</Text>
</Flex>
)}
</Flex>
</Box>
)
}

export default QuizSummary
Loading