Skip to content

Commit

Permalink
feat: choice single multi toggle (#2)
Browse files Browse the repository at this point in the history
* fix: use the SurveyDefinition type on useStorage

* feat: add minLength 2 on choice options

* feat: add variant in choice question

* feat: add variant selector and icons

* Update src/components/survey-generator/create-survey.tsx

Co-authored-by: balastrong-test <[email protected]>

* feat: use popover on variant selector

---------

Co-authored-by: balastrong-test <[email protected]>
  • Loading branch information
Balastrong and balastrong-test authored Apr 15, 2024
1 parent 34e8261 commit 61dc097
Show file tree
Hide file tree
Showing 12 changed files with 536 additions and 19 deletions.
89 changes: 89 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
"test": "vitest"
},
"dependencies": {
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slot": "^1.0.2",
"@tailwindcss/typography": "^0.5.12",
Expand All @@ -21,6 +23,7 @@
"@tanstack/valibot-form-adapter": "^0.13.7",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"cmdk": "^1.0.0",
"lucide-react": "^0.323.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
7 changes: 6 additions & 1 deletion src/components/survey-generator/create-survey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,13 @@ export const CreateSurvey = () => {
case "choice":
return {
type: "choice",
variant: "multiple",
question: "",
options: [] as ChoiceQuestion["options"],
options: [
{
id: generateId(),
},
] as ChoiceQuestion["options"],
} as ChoiceQuestion;
}
};
Expand Down
109 changes: 102 additions & 7 deletions src/components/survey-generator/question-blocks/choice.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
import { Button } from "@/components/ui/button";
import {
Command,
CommandGroup,
CommandItem,
CommandList,
} from "@/components/ui/command";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { generateId } from "@/lib/utils";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { cn, generateId } from "@/lib/utils";
import { ChoiceQuestion, SurveyDefinition } from "@/types/survey";
import { FormApi } from "@tanstack/react-form";
import { FormApi, useField } from "@tanstack/react-form";
import { valibotValidator } from "@tanstack/valibot-form-adapter";
import { X } from "lucide-react";
import {
CheckCircle2,
CheckSquare2,
ChevronDown,
CircleDot,
LucideIcon,
X,
} from "lucide-react";
import { useState } from "react";
import {
QuestionCard,
QuestionCardDeleteButton,
QuestionCardHeader,
QuestionCardItem,
QuestionCardTitle,
} from "../question-card";
Expand All @@ -18,17 +38,83 @@ type Props = {
form: FormApi<SurveyDefinition, typeof valibotValidator>;
};

/*
[ ] Toggle Single/Multiple
*/
const variants: {
[key in ChoiceQuestion["variant"]]: {
label: string;
icon: LucideIcon;
};
} = {
single: {
label: "Single Choice",
icon: CheckCircle2,
},
multiple: {
label: "Multiple Choice",
icon: CheckSquare2,
},
dropdown: {
label: "Dropdown",
icon: ChevronDown,
},
};

const iconClassName = "text-muted-foreground";

export const ChoiceFormField = ({ questionIndex, form }: Props) => {
const [isVariantSelectorOpen, setIsVarianSelectorOpen] = useState(false);

const variantField = useField({
name: `questions[${questionIndex}].variant`,
form,
});

const variantValue = variantField.getValue() as ChoiceQuestion["variant"];
const selectedVariant = variants[variantValue];

return (
<QuestionCard key={questionIndex}>
<QuestionCardDeleteButton
onClick={() => form.removeFieldValue(`questions`, questionIndex)}
/>
<QuestionCardTitle>Choice Question</QuestionCardTitle>
<QuestionCardHeader>
<Popover
open={isVariantSelectorOpen}
onOpenChange={setIsVarianSelectorOpen}
>
<PopoverTrigger asChild>
<Button
variant="outline"
size="sm"
className="w-[150px] justify-start"
>
<selectedVariant.icon className="mr-2 h-4 w-4 shrink-0" />
{selectedVariant.label}
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" align="start">
<Command>
<CommandList>
<CommandGroup>
{Object.entries(variants).map(([value, variant]) => (
<CommandItem
key={value}
value={value}
onSelect={() => {
variantField.setValue(value);
setIsVarianSelectorOpen(false);
}}
>
<variant.icon className={cn("mr-2 h-4 w-4")} />
<span>{variant.label}</span>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
<QuestionCardTitle>Choice Question</QuestionCardTitle>
</QuestionCardHeader>
<form.Field
name={`questions[${questionIndex}].question`}
children={(field) => (
Expand Down Expand Up @@ -62,6 +148,15 @@ export const ChoiceFormField = ({ questionIndex, form }: Props) => {
children={(subField) => {
return (
<div className="flex gap-2 items-center">
{variantValue === "single" && (
<CircleDot className={iconClassName} />
)}
{variantValue === "multiple" && (
<CheckSquare2 className={iconClassName} />
)}
{variantValue === "dropdown" && (
<ChevronDown className={iconClassName} />
)}
<Input
type="text"
placeholder="Option"
Expand Down
22 changes: 19 additions & 3 deletions src/components/survey-generator/question-card.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from "react";
import { Card } from "../ui/card";
import { cn } from "@/lib/utils";
import { X } from "lucide-react";
import React, { Children } from "react";
import { Button } from "../ui/button";
import { Card } from "../ui/card";

const QuestionCard = React.forwardRef<
HTMLDivElement,
Expand All @@ -23,6 +23,21 @@ const QuestionCardItem = React.forwardRef<
<div ref={ref} className={cn("flex flex-col gap-2 ", className)} {...props} />
));

const QuestionCardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"grid grid-flow-col justify-center items-center w-full",
Children.count(props.children) === 1 ? "grid-cols-1" : "grid-cols-3",
className
)}
{...props}
/>
));

const QuestionCardTitle = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
Expand Down Expand Up @@ -54,7 +69,8 @@ const QuestionCardDeleteButton = React.forwardRef<

export {
QuestionCard,
QuestionCardDeleteButton,
QuestionCardHeader,
QuestionCardItem,
QuestionCardTitle,
QuestionCardDeleteButton,
};
Loading

0 comments on commit 61dc097

Please sign in to comment.