diff --git a/__dummy__/getExercisesData.ts b/__dummy__/getExercisesData.ts index 5f9c24e9c..b3ee44d86 100644 --- a/__dummy__/getExercisesData.ts +++ b/__dummy__/getExercisesData.ts @@ -57,6 +57,7 @@ const getExercisesData: GetExercisesQuery = { alerts: [], exercises: [ { + id: 1, module: { name: 'Numbers', lesson: { @@ -68,6 +69,7 @@ const getExercisesData: GetExercisesQuery = { explanation: 'You can reassign variables that were created with "let".' }, { + id: 2, module: { name: 'Numbers', lesson: { @@ -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: { diff --git a/components/ExerciseCard/ExerciseCard.test.tsx b/components/ExerciseCard/ExerciseCard.test.tsx index 6a3b91926..86a5e9886 100644 --- a/components/ExerciseCard/ExerciseCard.test.tsx +++ b/components/ExerciseCard/ExerciseCard.test.tsx @@ -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( { setAnswerShown={setAnswerShown} message={Message.EMPTY} setMessage={setMessage} + submitUserAnswer={submitUserAnswer} /> ) @@ -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( { setAnswerShown={setAnswerShown} message={Message.ERROR} setMessage={setMessage} + submitUserAnswer={submitUserAnswer} /> ) @@ -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( { setAnswerShown={setAnswerShown} message={Message.SUCCESS} setMessage={setMessage} + submitUserAnswer={submitUserAnswer} /> ) @@ -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( { setAnswerShown={setAnswerShown} message={Message.SUCCESS} setMessage={setMessage} + submitUserAnswer={submitUserAnswer} /> ) @@ -129,5 +142,6 @@ describe('ExerciseCard component', () => { expect(setAnswerShown).toBeCalledWith(true) expect(setAnswerShown).toBeCalledTimes(1) expect(setMessage).toBeCalledTimes(0) + expect(submitUserAnswer).toBeCalledTimes(0) }) }) diff --git a/components/ExerciseCard/ExerciseCard.tsx b/components/ExerciseCard/ExerciseCard.tsx index 7cd61a8d4..f2faffe9e 100644 --- a/components/ExerciseCard/ExerciseCard.tsx +++ b/components/ExerciseCard/ExerciseCard.tsx @@ -11,6 +11,7 @@ export type ExerciseCardProps = { setAnswerShown: (answerShown: boolean) => void message: Message setMessage: (message: Message) => void + submitUserAnswer: (userAnswer: string) => void } export enum Message { @@ -26,7 +27,8 @@ const ExerciseCard = ({ answerShown, setAnswerShown, message, - setMessage + setMessage, + submitUserAnswer }: ExerciseCardProps) => { const [studentAnswer, setStudentAnswer] = useState('') @@ -65,6 +67,7 @@ const ExerciseCard = ({ } else { setMessage(Message.ERROR) } + submitUserAnswer(studentAnswer.trim()) }} > SUBMIT diff --git a/graphql/index.tsx b/graphql/index.tsx index 6c1436690..4225add71 100644 --- a/graphql/index.tsx +++ b/graphql/index.tsx @@ -830,6 +830,7 @@ export type GetExercisesQuery = { }> exercises: Array<{ __typename?: 'Exercise' + id: number description: string answer: string explanation?: string | null @@ -3531,6 +3532,7 @@ export const GetExercisesDocument = gql` urlCaption } exercises { + id module { name lesson { diff --git a/graphql/queries/getExercises.ts b/graphql/queries/getExercises.ts index ff977dc81..a7d34a9c2 100644 --- a/graphql/queries/getExercises.ts +++ b/graphql/queries/getExercises.ts @@ -15,6 +15,7 @@ const GET_EXERCISES = gql` urlCaption } exercises { + id module { name lesson { diff --git a/pages/exercises/[lessonSlug].tsx b/pages/exercises/[lessonSlug].tsx index eba05da37..14ce91dba 100644 --- a/pages/exercises/[lessonSlug].tsx +++ b/pages/exercises/[lessonSlug].tsx @@ -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> = ({ queryData }) => { const { lessons, alerts, exercises } = queryData const router = useRouter() const [exerciseIndex, setExerciseIndex] = useState(-1) + const [userAnswers, setUserAnswers] = useState>({}) + if (!router.isReady) return const slug = router.query.lessonSlug as string @@ -60,6 +45,7 @@ const Exercises: React.FC> = ({ 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, @@ -78,12 +64,21 @@ const Exercises: React.FC> = ({ lessonTitle={currentLesson.title} hasPrevious={exerciseIndex > 0} hasNext={exerciseIndex < currentExercises.length - 1} + submitUserAnswer={(userAnswer: string) => + setUserAnswers({ ...userAnswers, [exercise.id]: userAnswer }) + } /> ) : ( ({ + problem: exercise.description, + answer: exercise.answer, + moduleName: exercise.module.name, + userAnswer: userAnswers[exercise.id] ?? null + }))} /> )} {alerts && } @@ -103,6 +98,7 @@ type ExerciseProps = { lessonTitle: string hasPrevious: boolean hasNext: boolean + submitUserAnswer: (userAnswer: string) => void } const Exercise = ({ @@ -110,7 +106,8 @@ const Exercise = ({ setExerciseIndex, lessonTitle, hasPrevious, - hasNext + hasNext, + submitUserAnswer }: ExerciseProps) => { const [answerShown, setAnswerShown] = useState(false) const [message, setMessage] = useState(Message.EMPTY) @@ -133,6 +130,7 @@ const Exercise = ({ setAnswerShown={setAnswerShown} message={message} setMessage={setMessage} + submitUserAnswer={submitUserAnswer} />
{hasPrevious ? ( @@ -170,12 +168,19 @@ type ExerciseListProps = { tabs: { text: string; url: string }[] setExerciseIndex: React.Dispatch> lessonTitle: string + exercises: { + moduleName: string + problem: string + answer: string + userAnswer: string | null + }[] } const ExerciseList = ({ tabs, setExerciseIndex, - lessonTitle + lessonTitle, + exercises }: ExerciseListProps) => { return ( <> @@ -199,14 +204,16 @@ const ExerciseList = ({
- {mockExercisePreviews.map((exercisePreview, i) => ( + {exercises.map((exercise, i) => ( ))} +
+
) diff --git a/stories/components/ExerciseCard.stories.tsx b/stories/components/ExerciseCard.stories.tsx index e0599abbe..bef6dcf68 100644 --- a/stories/components/ExerciseCard.stories.tsx +++ b/stories/components/ExerciseCard.stories.tsx @@ -27,6 +27,9 @@ export const Basic = () => { setAnswerShown={setAnswerShown} message={message} setMessage={setMessage} + submitUserAnswer={userAnswer => { + console.log(`User answer submitted: ${userAnswer}`) + }} /> ) }