Skip to content

Commit

Permalink
basic logic working, requires refactoring for clarity
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronmcadam committed Aug 1, 2024
1 parent c80db9e commit 535d002
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 36 deletions.
80 changes: 80 additions & 0 deletions src/app/api/questions/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
export async function GET() {
return Response.json([
{
question: "Which image best matches your hair loss?",
type: "ChoiceType",
options: [
{
display:
'<img alt="Temples" src="https://s3-eu-west-1.amazonaws.com/manualco/questions/temples-hairloss.png" srcset="https://s3-eu-west-1.amazonaws.com/manualco/questions/temples-hairloss%402x.png 2x" />',
value: "Temples",
isRejection: false,
},
{
display:
'<img alt="Temples & Crown" src="https://s3-eu-west-1.amazonaws.com/manualco/questions/templescrown-hairloss.png" srcset="https://s3-eu-west-1.amazonaws.com/manualco/questions/templescrown-hairloss%402 x.png 2x"/>',
value: "Temples & Crown",
isRejection: false,
},
{
display:
'<img alt="Patchy" src="https://s3-eu-west-1.amazonaws.com/manualco/questions/patchy-hairloss.png" srcset="https://s3-eu-west-1.amazonaws.com/manualco/questions/patchy-hairloss%402x.png 2x"/>',
value: "Patchy",
isRejection: true,
},
{
display:
'<img alt="Moderate" src="https://s3-eu-west-1.amazonaws.com/manualco/questions/moderate-hairloss.png" srcset="https://s3-eu-west-1.amazonaws.com/manualco/questions/moderate-hairloss%402x.pn g 2x" />',
value: "Moderate",
isRejection: false,
},
{
display:
'<img alt="Extensive" src="https://s3-eu-west-1.amazonaws.com/manualco/questions/extensive-hairloss.png" srcset="https://s3-eu-west-1.amazonaws.com/manualco/questions/extensive-hairloss%402x.pn g 2x"/>',
value: "Extensive",
isRejection: true,
},
{
display:
'<img alt="Complete" src="https://s3-eu-west-1.amazonaws.com/manualco/questions/complete-hairloss.png" srcset="https://s3-eu-west-1.amazonaws.com/manualco/questions/complete-hairloss%402x.pn g 2x" />',
value: "Complete",
isRejection: true,
},
],
},
{
question:
"Have you ever been diagnosed with prostate cancer, or are you currently undergoing PSA/Prostate monitoring?",
type: "ChoiceType",
options: [
{
display: "Yes",
value: true,
isRejection: true,
},
{
display: "No",
value: false,
isRejection: false,
},
],
},
{
question:
"Have you ever been diagnosed with breast cancer or noticed any changes in your breast tissue such as lumps, pain, nipple discharge or swelling?",
type: "ChoiceType",
options: [
{
display: "Yes",
value: true,
isRejection: true,
},
{
display: "No",
value: false,
isRejection: false,
},
],
},
]);
}
37 changes: 1 addition & 36 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
import { Button } from "@/components/ui/button";
import { QuizButton } from "@/components/quiz-button";
import { FacebookLogo } from "@/components/ui/logos/facebook-logo";
import { GoogleLogo } from "@/components/ui/logos/google-logo";
import { ManualLogo } from "@/components/ui/logos/manual-logo";
import { TwitterLogo } from "@/components/ui/logos/twitter-logo";
import Image from "next/image";

import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";

export default function Home() {
return (
<main>
Expand Down Expand Up @@ -232,28 +222,3 @@ function Footer() {
</footer>
);
}

function QuizButton() {
return (
<Dialog>
<DialogTrigger asChild>
<Button size="lg" className="mt-9">
Take the quiz
</Button>
</DialogTrigger>
<DialogContent className="max-w-full h-full">
<DialogHeader>
<DialogTitle>Is Manual Right For You?</DialogTitle>
<DialogDescription>
Help us provide you with the best possible care by answering a few
quick questions.
</DialogDescription>
</DialogHeader>
<div className="py-4">Dialog contents</div>
<DialogFooter>
<Button variant="outline">Close</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
Empty file.
125 changes: 125 additions & 0 deletions src/components/quiz-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"use client";

import * as React from "react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { cn } from "@/lib/utils";

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

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

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>
<Button size="lg" className="mt-9">
Take the quiz
</Button>
</DialogTrigger>
<DialogContent className="max-w-full h-full">
<DialogHeader>
<DialogTitle>Is Manual Right For You?</DialogTitle>
<DialogDescription>
Help us provide you with the best possible care by answering a few
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> */}
</DialogFooter>
</DialogContent>
</Dialog>
);
}
45 changes: 45 additions & 0 deletions tests/visitor-completes-quiz.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,48 @@ test("smoke test", async ({ page }) => {
}),
).toBeVisible();
});

test("visitor accepted for treatment", async ({ page }) => {
await page.goto("/");

await page.getByRole("button", { name: /take the quiz/i }).click();

await expect(
page.getByRole("heading", {
name: /which image best matches your hair loss/i,
}),
).toBeVisible();

await page
.getByRole("button", { name: /temples/i })
.first()
.click();
await page.getByRole("button", { name: /no/i }).click();
await page.getByRole("button", { name: /no/i }).click();

await expect(
page.getByRole("heading", { name: /eligible for treatment/i }),
).toBeVisible();
});

test("visitor rejected for treatment", async ({ page }) => {
await page.goto("/");

await page.getByRole("button", { name: /take the quiz/i }).click();

await expect(
page.getByRole("heading", {
name: /which image best matches your hair loss/i,
}),
).toBeVisible();

await page
.getByRole("button", { name: /temples/i })
.first()
.click();
await page.getByRole("button", { name: /yes/i }).click();

await expect(
page.getByRole("heading", { name: /not eligible for treatment/i }),
).toBeVisible();
});

0 comments on commit 535d002

Please sign in to comment.