-
Notifications
You must be signed in to change notification settings - Fork 69
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
Mark exercise answered based on user answers #2351
Changes from all commits
b9748af
d863896
3afde64
338b550
2cc2338
2e5e117
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ const GET_EXERCISES = gql` | |
urlCaption | ||
} | ||
exercises { | ||
id | ||
module { | ||
name | ||
lesson { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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>>({}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We store the user's answers on the frontend for now. They go away when you refresh the page. This is good for testing. In the next pull request, we'll get the user's answers from the backend. |
||
|
||
if (!router.isReady) return <LoadingSpinner /> | ||
|
||
const slug = router.query.lessonSlug as string | ||
|
@@ -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, | ||
|
@@ -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 }) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we add the user's answer to our userAnswers object which stores all the user's answers by exercise ID. |
||
} | ||
/> | ||
) : ( | ||
<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} />} | ||
|
@@ -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) | ||
|
@@ -133,6 +130,7 @@ const Exercise = ({ | |
setAnswerShown={setAnswerShown} | ||
message={message} | ||
setMessage={setMessage} | ||
submitUserAnswer={submitUserAnswer} | ||
/> | ||
<div className="d-flex justify-content-between mt-4"> | ||
{hasPrevious ? ( | ||
|
@@ -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 ( | ||
<> | ||
|
@@ -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'} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now there are only 2 states, but I think there should be a third state in the future called "ANSWERED INCORRECTLY" or something similar. Maybe we can make "ANSWERED INCORRECTLY" red and then "NOT ANSWERED" can be gray or some neutral color. |
||
problem={exercise.problem} | ||
/> | ||
))} | ||
<div /> | ||
<div /> | ||
</div> | ||
</> | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the mock exercise previews, we're now using the backend exercises for the previews.