diff --git a/src/components/quiz.tsx b/src/components/quiz.tsx index c723b1a..66b73b5 100644 --- a/src/components/quiz.tsx +++ b/src/components/quiz.tsx @@ -7,7 +7,7 @@ import { CheckIcon, CircleCheck } from "lucide-react"; type Option = { display: string; - value: string; + value: string | boolean; isRejection: boolean; }; @@ -17,33 +17,75 @@ type Question = { options: Option[]; }; +type QuizQuestion = { + title: string; + options: Option[]; + response: Option | null; + status: "complete" | "current" | "upcoming"; +}; + export function Quiz() { - const [questions, setQuestions] = React.useState([]); + const [questions, setQuestions] = React.useState([]); // TODO: Perf: we may want to somehow preload the display HTML because - // we're seeing some flicker when navigating between steps + // we're seeing some flicker when navigating between questions React.useEffect(() => { fetch("/api/questions") .then((res) => res.json()) - .then((data) => setQuestions(data)); + .then((data: Question[]) => + setQuestions( + // Map the fetched data to the view model state + // Set the first question as "current" and the rest as "upcoming" + data.map((q, i) => { + if (i === 0) { + return { + title: q.question, + options: q.options, + response: null, + status: "current", + }; + } + + return { + title: q.question, + options: q.options, + response: null, + status: "upcoming", + }; + }), + ), + ); }, []); const [currentIndex, setCurrentIndex] = React.useState(0); const currentQuestion = questions[currentIndex]; - // TODO: we may want to consolidate these state values into - // an object we can use to read the overall quiz state - // make this take account of any amount of questions - // for now, we'll hard code the amount of questions - const [chosenOptions, setChosenOptions] = React.useState< - Record - >({ - 0: null, - 1: null, - 2: null, - }); + const visitorIsRejected = questions.some((q) => q.response?.isRejection); + + function handleOptionClick(option: Option) { + setQuestions((currentQuestions) => { + // Update the current question with its response and "complete" status + // and set the next question as "upcoming" + const updatedQuestions: QuizQuestion[] = currentQuestions.map((q, i) => { + if (i === currentIndex) { + return { + ...q, + response: option, + status: "complete", + }; + } else if (i === currentIndex + 1) { + return { + ...q, + status: "current", + }; + } + return q; + }); - const visitorIsRejected = Object.values(chosenOptions).some((o) => o === -1); + return updatedQuestions; + }); + setCurrentIndex(currentIndex + 1); + } return (
@@ -53,48 +95,36 @@ export function Quiz() {

You're eligible for treatment

) : currentQuestion ? (
- -
- {questions.map((_q, i) => ( - - ))} -
+ { + setCurrentIndex(questionIndex); + }} + />

- {currentQuestion.question} + {currentQuestion.title}

- {currentQuestion.options.map((o, i) => ( - - ))} + {currentQuestion.options.map((o, i) => { + const isOptionSelected = currentQuestion.response === o; + + return ( + + ); + })}
) : null} @@ -102,33 +132,30 @@ export function Quiz() { ); } -// const steps = [ -// { name: "Step 1", href: "#", status: "complete" }, -// { name: "Step 2", href: "#", status: "complete" }, -// { name: "Step 3", href: "#", status: "current" }, -// { name: "Step 4", href: "#", status: "upcoming" }, -// { name: "Step 5", href: "#", status: "upcoming" }, -// ]; - -const steps = [ - { name: "Step 1", href: "#", status: "complete" }, - { name: "Step 2", href: "#", status: "current" }, - { name: "Step 3", href: "#", status: "upcoming" }, -]; +type QuizNavigationProps = { + questions: QuizQuestion[]; + onButtonClick: (questionIndex: number) => void; +}; -export function QuizNavigation() { +export function QuizNavigation({ + questions, + // This prop raises a warning from Next.js in tsc. + // We can safely ignore it for now as we're not trying to use a server component in this file. + // @see https://github.com/vercel/next.js/discussions/46795 + onButtonClick, +}: QuizNavigationProps) { return ( -