Skip to content

Commit

Permalink
refactor: separate dialog from the quiz itself
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronmcadam committed Aug 2, 2024
1 parent a59535d commit 741eedf
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 77 deletions.
84 changes: 7 additions & 77 deletions src/components/quiz-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
DialogTrigger,
} from "@/components/ui/dialog";
import { cn } from "@/lib/utils";
import { DialogClose } from "@radix-ui/react-dialog";
import { Quiz } from "./quiz";

type Option = {
display: string;
Expand All @@ -26,33 +28,6 @@ type Question = {
};

export function QuizButton() {
const [questions, setQuestions] = React.useState<Question[]>([]);

// TODO: Perf: we may want to somehow preload the display HTML because
// we're seeing some flicker when navigating between steps
React.useEffect(() => {
fetch("/api/questions")
.then((res) => res.json())
.then((data) => setQuestions(data));
}, []);

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<number, number | null>
>({
0: null,
1: null,
2: null,
});

const visitorIsRejected = Object.values(chosenOptions).some((o) => o === -1);

return (
<Dialog>
<DialogTrigger asChild>
Expand All @@ -68,56 +43,11 @@ export function QuizButton() {
quick questions.
</DialogDescription>
</DialogHeader>
<div className="py-4">
{visitorIsRejected ? (
<h3>You&apos;re not eligible for treatment</h3>
) : currentIndex === questions.length ? (
<h3>You&apos;re eligible for treatment</h3>
) : currentQuestion ? (
<div className="mt-8">
<div className="flex gap-4">
{questions.map((_q, i) => (
<Button
key={i}
className={currentIndex === i ? "border-primary" : ""}
onClick={() => {
setCurrentIndex(i);
}}
disabled={chosenOptions[i] === null}
variant="outline"
>{`Step ${i + 1}`}</Button>
))}
</div>
<h3>{currentQuestion.question}</h3>
<div className="flex gap-4">
{currentQuestion.options.map((o, i) => (
<Button
key={o.value}
onClick={() => {
setCurrentIndex(currentIndex + 1);
setChosenOptions((currentChosenOptions) => {
return {
...currentChosenOptions,
[currentIndex]: o.isRejection ? -1 : i,
};
});
}}
variant="outline"
className={cn(
"mt-2 h-auto",
chosenOptions[currentIndex] === i ? "border-primary" : "",
)}
>
<span dangerouslySetInnerHTML={{ __html: o.display }} />
{o.value}
</Button>
))}
</div>
</div>
) : null}
</div>
<DialogFooter>
{/* <Button variant="outline">Close</Button> */}
<Quiz />
<DialogFooter className="sm:justify-start">
<DialogClose asChild>
<Button variant="outline">Close</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
Expand Down
97 changes: 97 additions & 0 deletions src/components/quiz.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
"use client";

import * as React from "react";
import { cn } from "@/lib/utils";
import { Button } from "./ui/button";

type Option = {
display: string;
value: string;
isRejection: boolean;
};

type Question = {
question: string;
type: string;
options: Option[];
};

export function Quiz() {
const [questions, setQuestions] = React.useState<Question[]>([]);

// TODO: Perf: we may want to somehow preload the display HTML because
// we're seeing some flicker when navigating between steps
React.useEffect(() => {
fetch("/api/questions")
.then((res) => res.json())
.then((data) => setQuestions(data));
}, []);

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<number, number | null>
>({
0: null,
1: null,
2: null,
});

const visitorIsRejected = Object.values(chosenOptions).some((o) => o === -1);

return (
<div className="py-4">
{visitorIsRejected ? (
<h3>You&apos;re not eligible for treatment</h3>
) : currentIndex === questions.length ? (
<h3>You&apos;re eligible for treatment</h3>
) : currentQuestion ? (
<div className="mt-8">
<div className="flex gap-4">
{questions.map((_q, i) => (
<Button
key={i}
className={currentIndex === i ? "border-primary" : ""}
onClick={() => {
setCurrentIndex(i);
}}
disabled={chosenOptions[i] === null}
variant="outline"
>{`Step ${i + 1}`}</Button>
))}
</div>
<h3>{currentQuestion.question}</h3>
<div className="flex gap-4">
{currentQuestion.options.map((o, i) => (
<Button
key={o.value}
onClick={() => {
setCurrentIndex(currentIndex + 1);
setChosenOptions((currentChosenOptions) => {
return {
...currentChosenOptions,
[currentIndex]: o.isRejection ? -1 : i,
};
});
}}
variant="outline"
className={cn(
"mt-2 h-auto",
chosenOptions[currentIndex] === i ? "border-primary" : "",
)}
>
<span dangerouslySetInnerHTML={{ __html: o.display }} />
{o.value}
</Button>
))}
</div>
</div>
) : null}
</div>
);
}

0 comments on commit 741eedf

Please sign in to comment.