Skip to content

Commit

Permalink
Merge pull request #2351 from bryanjenningz/mark-exercise-answered-ba…
Browse files Browse the repository at this point in the history
…sed-on-user-answers

Mark exercise answered based on user answers
  • Loading branch information
bryanjenningz authored Sep 26, 2022
2 parents 8077479 + 2e5e117 commit e0863c8
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 25 deletions.
3 changes: 3 additions & 0 deletions __dummy__/getExercisesData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const getExercisesData: GetExercisesQuery = {
alerts: [],
exercises: [
{
id: 1,
module: {
name: 'Numbers',
lesson: {
Expand All @@ -68,6 +69,7 @@ const getExercisesData: GetExercisesQuery = {
explanation: 'You can reassign variables that were created with "let".'
},
{
id: 2,
module: {
name: 'Numbers',
lesson: {
Expand All @@ -79,6 +81,7 @@ const getExercisesData: GetExercisesQuery = {
explanation: '`a += 2` is a shorter way to write `a = a + 2`'
},
{
id: 3,
module: {
name: 'Numbers',
lesson: {
Expand Down
14 changes: 14 additions & 0 deletions components/ExerciseCard/ExerciseCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe('ExerciseCard component', () => {
it('Should render an exercise card', async () => {
const setAnswerShown = jest.fn()
const setMessage = jest.fn()
const submitUserAnswer = jest.fn()

const { getByRole, queryByText } = render(
<ExerciseCard
Expand All @@ -23,6 +24,7 @@ describe('ExerciseCard component', () => {
setAnswerShown={setAnswerShown}
message={Message.EMPTY}
setMessage={setMessage}
submitUserAnswer={submitUserAnswer}
/>
)

Expand All @@ -36,11 +38,14 @@ describe('ExerciseCard component', () => {
expect(setAnswerShown).toBeCalledTimes(0)
expect(setMessage).toBeCalledWith(Message.ERROR)
expect(setMessage).toBeCalledTimes(1)
expect(submitUserAnswer).toBeCalledWith('')
expect(submitUserAnswer).toBeCalledTimes(1)
})

it('Should render an error message', () => {
const setAnswerShown = jest.fn()
const setMessage = jest.fn()
const submitUserAnswer = jest.fn()

const { getByRole, queryByText, getByLabelText } = render(
<ExerciseCard
Expand All @@ -51,6 +56,7 @@ describe('ExerciseCard component', () => {
setAnswerShown={setAnswerShown}
message={Message.ERROR}
setMessage={setMessage}
submitUserAnswer={submitUserAnswer}
/>
)

Expand All @@ -71,11 +77,14 @@ describe('ExerciseCard component', () => {
expect(setAnswerShown).toBeCalledTimes(1)
expect(setMessage).toBeCalledWith(Message.SUCCESS)
expect(setMessage).toBeCalledTimes(1)
expect(submitUserAnswer).toBeCalledWith('15')
expect(submitUserAnswer).toBeCalledTimes(1)
})

it('Should render a success message', () => {
const setAnswerShown = jest.fn()
const setMessage = jest.fn()
const submitUserAnswer = jest.fn()

const { getByRole, queryByText } = render(
<ExerciseCard
Expand All @@ -86,6 +95,7 @@ describe('ExerciseCard component', () => {
setAnswerShown={setAnswerShown}
message={Message.SUCCESS}
setMessage={setMessage}
submitUserAnswer={submitUserAnswer}
/>
)

Expand All @@ -100,11 +110,13 @@ describe('ExerciseCard component', () => {
expect(setAnswerShown).toBeCalledWith(false)
expect(setAnswerShown).toBeCalledTimes(1)
expect(setMessage).toBeCalledTimes(0)
expect(submitUserAnswer).toBeCalledTimes(0)
})

it('Should hide the answer', () => {
const setAnswerShown = jest.fn()
const setMessage = jest.fn()
const submitUserAnswer = jest.fn()

const { queryByText, getByRole } = render(
<ExerciseCard
Expand All @@ -115,6 +127,7 @@ describe('ExerciseCard component', () => {
setAnswerShown={setAnswerShown}
message={Message.SUCCESS}
setMessage={setMessage}
submitUserAnswer={submitUserAnswer}
/>
)

Expand All @@ -129,5 +142,6 @@ describe('ExerciseCard component', () => {
expect(setAnswerShown).toBeCalledWith(true)
expect(setAnswerShown).toBeCalledTimes(1)
expect(setMessage).toBeCalledTimes(0)
expect(submitUserAnswer).toBeCalledTimes(0)
})
})
5 changes: 4 additions & 1 deletion components/ExerciseCard/ExerciseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type ExerciseCardProps = {
setAnswerShown: (answerShown: boolean) => void
message: Message
setMessage: (message: Message) => void
submitUserAnswer: (userAnswer: string) => void
}

export enum Message {
Expand All @@ -26,7 +27,8 @@ const ExerciseCard = ({
answerShown,
setAnswerShown,
message,
setMessage
setMessage,
submitUserAnswer
}: ExerciseCardProps) => {
const [studentAnswer, setStudentAnswer] = useState('')

Expand Down Expand Up @@ -65,6 +67,7 @@ const ExerciseCard = ({
} else {
setMessage(Message.ERROR)
}
submitUserAnswer(studentAnswer.trim())
}}
>
SUBMIT
Expand Down
2 changes: 2 additions & 0 deletions graphql/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,7 @@ export type GetExercisesQuery = {
}>
exercises: Array<{
__typename?: 'Exercise'
id: number
description: string
answer: string
explanation?: string | null
Expand Down Expand Up @@ -3531,6 +3532,7 @@ export const GetExercisesDocument = gql`
urlCaption
}
exercises {
id
module {
name
lesson {
Expand Down
1 change: 1 addition & 0 deletions graphql/queries/getExercises.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const GET_EXERCISES = gql`
urlCaption
}
exercises {
id
module {
name
lesson {
Expand Down
55 changes: 31 additions & 24 deletions pages/exercises/[lessonSlug].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,21 @@ import Error, { StatusCode } from '../../components/Error'
import LoadingSpinner from '../../components/LoadingSpinner'
import AlertsDisplay from '../../components/AlertsDisplay'
import NavCard from '../../components/NavCard'
import ExercisePreviewCard, {
ExercisePreviewCardProps
} from '../../components/ExercisePreviewCard'
import ExercisePreviewCard from '../../components/ExercisePreviewCard'
import { NewButton } from '../../components/theme/Button'
import ExerciseCard, { Message } from '../../components/ExerciseCard'
import { ArrowLeftIcon } from '@primer/octicons-react'
import GET_EXERCISES from '../../graphql/queries/getExercises'
import styles from '../../scss/exercises.module.scss'

const exampleProblem = `const a = 5
a = a + 10
// what is a?`

const mockExercisePreviews: ExercisePreviewCardProps[] = [
{ moduleName: 'Variables', state: 'ANSWERED', problem: exampleProblem },
{ moduleName: 'Variables', state: 'NOT ANSWERED', problem: exampleProblem },
{ moduleName: 'Variables', state: 'NOT ANSWERED', problem: exampleProblem },
{ moduleName: 'Variables', state: 'NOT ANSWERED', problem: exampleProblem },
{ moduleName: 'Variables', state: 'NOT ANSWERED', problem: exampleProblem },
{ moduleName: 'Variables', state: 'NOT ANSWERED', problem: exampleProblem },
{ moduleName: 'Variables', state: 'NOT ANSWERED', problem: exampleProblem },
{ moduleName: 'Variables', state: 'ANSWERED', problem: exampleProblem }
]

const Exercises: React.FC<QueryDataProps<GetExercisesQuery>> = ({
queryData
}) => {
const { lessons, alerts, exercises } = queryData
const router = useRouter()
const [exerciseIndex, setExerciseIndex] = useState(-1)
const [userAnswers, setUserAnswers] = useState<Record<number, string>>({})

if (!router.isReady) return <LoadingSpinner />

const slug = router.query.lessonSlug as string
Expand All @@ -60,6 +45,7 @@ const Exercises: React.FC<QueryDataProps<GetExercisesQuery>> = ({
const currentExercises = exercises
.filter(exercise => exercise?.module.lesson.slug === slug)
.map(exercise => ({
id: exercise.id,
challengeName: exercise.module.name,
problem: exercise.description,
answer: exercise.answer,
Expand All @@ -78,12 +64,21 @@ const Exercises: React.FC<QueryDataProps<GetExercisesQuery>> = ({
lessonTitle={currentLesson.title}
hasPrevious={exerciseIndex > 0}
hasNext={exerciseIndex < currentExercises.length - 1}
submitUserAnswer={(userAnswer: string) =>
setUserAnswers({ ...userAnswers, [exercise.id]: userAnswer })
}
/>
) : (
<ExerciseList
tabs={tabs}
setExerciseIndex={setExerciseIndex}
lessonTitle={currentLesson.title}
exercises={exercises.map(exercise => ({
problem: exercise.description,
answer: exercise.answer,
moduleName: exercise.module.name,
userAnswer: userAnswers[exercise.id] ?? null
}))}
/>
)}
{alerts && <AlertsDisplay alerts={alerts} />}
Expand All @@ -103,14 +98,16 @@ type ExerciseProps = {
lessonTitle: string
hasPrevious: boolean
hasNext: boolean
submitUserAnswer: (userAnswer: string) => void
}

const Exercise = ({
exercise,
setExerciseIndex,
lessonTitle,
hasPrevious,
hasNext
hasNext,
submitUserAnswer
}: ExerciseProps) => {
const [answerShown, setAnswerShown] = useState(false)
const [message, setMessage] = useState(Message.EMPTY)
Expand All @@ -133,6 +130,7 @@ const Exercise = ({
setAnswerShown={setAnswerShown}
message={message}
setMessage={setMessage}
submitUserAnswer={submitUserAnswer}
/>
<div className="d-flex justify-content-between mt-4">
{hasPrevious ? (
Expand Down Expand Up @@ -170,12 +168,19 @@ type ExerciseListProps = {
tabs: { text: string; url: string }[]
setExerciseIndex: React.Dispatch<React.SetStateAction<number>>
lessonTitle: string
exercises: {
moduleName: string
problem: string
answer: string
userAnswer: string | null
}[]
}

const ExerciseList = ({
tabs,
setExerciseIndex,
lessonTitle
lessonTitle,
exercises
}: ExerciseListProps) => {
return (
<>
Expand All @@ -199,14 +204,16 @@ const ExerciseList = ({
</div>
</div>
<div className={styles.exerciseList__container}>
{mockExercisePreviews.map((exercisePreview, i) => (
{exercises.map((exercise, i) => (
<ExercisePreviewCard
key={i}
moduleName={exercisePreview.moduleName}
state={exercisePreview.state}
problem={exercisePreview.problem}
moduleName={exercise.moduleName}
state={exercise.userAnswer === null ? 'NOT ANSWERED' : 'ANSWERED'}
problem={exercise.problem}
/>
))}
<div />
<div />
</div>
</>
)
Expand Down
3 changes: 3 additions & 0 deletions stories/components/ExerciseCard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export const Basic = () => {
setAnswerShown={setAnswerShown}
message={message}
setMessage={setMessage}
submitUserAnswer={userAnswer => {
console.log(`User answer submitted: ${userAnswer}`)
}}
/>
)
}

1 comment on commit e0863c8

@vercel
Copy link

@vercel vercel bot commented on e0863c8 Sep 26, 2022

Choose a reason for hiding this comment

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

Please sign in to comment.