Add QuestionType enum in place of strings (#420)

This commit is contained in:
Piyush Gupta
2023-06-20 20:02:03 +05:30
committed by GitHub
parent 8f1b7ae83a
commit 51e4221f33
12 changed files with 80 additions and 69 deletions
@@ -1,4 +1,4 @@
import type { Question } from "@formbricks/types/questions";
import { QuestionType, type Question } from "@formbricks/types/questions";
import OpenTextQuestion from "./OpenTextQuestion";
import MultipleChoiceSingleQuestion from "./MultipleChoiceSingleQuestion";
import MultipleChoiceMultiQuestion from "./MultipleChoiceMultiQuestion";
@@ -19,42 +19,42 @@ export default function QuestionConditional({
lastQuestion,
brandColor,
}: QuestionConditionalProps) {
return question.type === "openText" ? (
return question.type === QuestionType.OpenText ? (
<OpenTextQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "multipleChoiceSingle" ? (
) : question.type === QuestionType.MultipleChoiceSingle ? (
<MultipleChoiceSingleQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "multipleChoiceMulti" ? (
) : question.type === QuestionType.MultipleChoiceMulti ? (
<MultipleChoiceMultiQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "nps" ? (
) : question.type === QuestionType.NPS ? (
<NPSQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "cta" ? (
) : question.type === QuestionType.CTA ? (
<CTAQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "rating" ? (
) : question.type === QuestionType.Rating ? (
<RatingQuestion
question={question}
onSubmit={onSubmit}
@@ -1,4 +1,4 @@
import { Logic, LogicCondition, Question } from "@formbricks/types/questions";
import { Logic, LogicCondition, Question, QuestionType } from "@formbricks/types/questions";
import { Survey } from "@formbricks/types/surveys";
import {
Button,
@@ -49,7 +49,7 @@ export default function LogicEditor({
return question.choices.map((choice) => choice.label);
} else if ("range" in question) {
return Array.from({ length: question.range }, (_, i) => (i + 1).toString());
} else if (question.type === "nps") {
} else if (question.type === QuestionType.NPS) {
return Array.from({ length: 11 }, (_, i) => (i + 0).toString());
}
return [];
@@ -2,7 +2,7 @@
import { getQuestionTypeName } from "@/lib/questions";
import { cn } from "@formbricks/lib/cn";
import type { Question } from "@formbricks/types/questions";
import { QuestionType, type Question } from "@formbricks/types/questions";
import type { Survey } from "@formbricks/types/surveys";
import { Input, Label, Switch } from "@formbricks/ui";
import {
@@ -88,17 +88,17 @@ export default function QuestionCard({
<div>
<div className="inline-flex">
<div className="-ml-0.5 mr-3 h-6 w-6 text-slate-400">
{question.type === "openText" ? (
{question.type === QuestionType.OpenText ? (
<ChatBubbleBottomCenterTextIcon />
) : question.type === "multipleChoiceSingle" ? (
) : question.type === QuestionType.MultipleChoiceSingle ? (
<QueueListIcon />
) : question.type === "multipleChoiceMulti" ? (
) : question.type === QuestionType.MultipleChoiceMulti ? (
<ListBulletIcon />
) : question.type === "nps" ? (
) : question.type === QuestionType.NPS ? (
<PresentationChartBarIcon />
) : question.type === "cta" ? (
) : question.type === QuestionType.CTA ? (
<CursorArrowRippleIcon />
) : question.type === "rating" ? (
) : question.type === QuestionType.Rating ? (
<StarIcon />
) : null}
</div>
@@ -126,7 +126,7 @@ export default function QuestionCard({
</div>
</Collapsible.CollapsibleTrigger>
<Collapsible.CollapsibleContent className="px-4 pb-4">
{question.type === "openText" ? (
{question.type === QuestionType.OpenText ? (
<OpenQuestionForm
localSurvey={localSurvey}
question={question}
@@ -134,7 +134,7 @@ export default function QuestionCard({
updateQuestion={updateQuestion}
lastQuestion={lastQuestion}
/>
) : question.type === "multipleChoiceSingle" ? (
) : question.type === QuestionType.MultipleChoiceSingle ? (
<MultipleChoiceSingleForm
localSurvey={localSurvey}
question={question}
@@ -142,7 +142,7 @@ export default function QuestionCard({
updateQuestion={updateQuestion}
lastQuestion={lastQuestion}
/>
) : question.type === "multipleChoiceMulti" ? (
) : question.type === QuestionType.MultipleChoiceMulti ? (
<MultipleChoiceMultiForm
localSurvey={localSurvey}
question={question}
@@ -150,7 +150,7 @@ export default function QuestionCard({
updateQuestion={updateQuestion}
lastQuestion={lastQuestion}
/>
) : question.type === "nps" ? (
) : question.type === QuestionType.NPS ? (
<NPSQuestionForm
localSurvey={localSurvey}
question={question}
@@ -158,7 +158,7 @@ export default function QuestionCard({
updateQuestion={updateQuestion}
lastQuestion={lastQuestion}
/>
) : question.type === "cta" ? (
) : question.type === QuestionType.CTA ? (
<CTAQuestionForm
localSurvey={localSurvey}
question={question}
@@ -166,7 +166,7 @@ export default function QuestionCard({
updateQuestion={updateQuestion}
lastQuestion={lastQuestion}
/>
) : question.type === "rating" ? (
) : question.type === QuestionType.Rating ? (
<RatingQuestionForm
localSurvey={localSurvey}
question={question}
@@ -187,7 +187,9 @@ export default function QuestionCard({
</Collapsible.CollapsibleTrigger>
<Collapsible.CollapsibleContent className="space-y-4">
{question.type !== "nps" && question.type !== "rating" && question.type !== "cta" ? (
{question.type !== QuestionType.NPS &&
question.type !== QuestionType.Rating &&
question.type !== QuestionType.CTA ? (
<div className="mt-4">
<Label htmlFor="buttonLabel">Button Label</Label>
<div className="mt-2">
@@ -12,6 +12,7 @@ import { RatingResponse } from "../RatingResponse";
import { deleteSubmission, useResponses } from "@/lib/responses/responses";
import clsx from "clsx";
import ResponseNote from "./ResponseNote";
import { QuestionType } from "@formbricks/types/questions";
export interface OpenTextSummaryProps {
data: {
@@ -121,7 +122,7 @@ export default function SingleResponse({ data, environmentId, surveyId }: OpenTe
<div key={`${response.id}-${idx}`}>
<p className="text-sm text-slate-500">{response.question}</p>
{typeof response.answer !== "object" ? (
response.type === "rating" ? (
response.type === QuestionType.Rating ? (
<div className="h-8">
<RatingResponse scale={response.scale} answer={response.answer} range={response.range} />
</div>
@@ -1,4 +1,8 @@
import { MultipleChoiceMultiQuestion, MultipleChoiceSingleQuestion } from "@formbricks/types/questions";
import {
MultipleChoiceMultiQuestion,
MultipleChoiceSingleQuestion,
QuestionType,
} from "@formbricks/types/questions";
import type { QuestionSummary } from "@formbricks/types/responses";
import { PersonAvatar, ProgressBar } from "@formbricks/ui";
import { InboxStackIcon } from "@heroicons/react/24/solid";
@@ -32,7 +36,7 @@ export default function MultipleChoiceSummary({
environmentId,
surveyType,
}: MultipleChoiceSummaryProps) {
const isSingleChoice = questionSummary.question.type === "multipleChoiceSingle";
const isSingleChoice = questionSummary.question.type === QuestionType.MultipleChoiceSingle;
const results: ChoiceResult[] = useMemo(() => {
if (!("choices" in questionSummary.question)) return [];
@@ -3,7 +3,7 @@ import { ProgressBar } from "@formbricks/ui";
import { InboxStackIcon } from "@heroicons/react/24/solid";
import { useMemo } from "react";
import { RatingResponse } from "../RatingResponse";
import { RatingQuestion } from "@formbricks/types/questions";
import { QuestionType, RatingQuestion } from "@formbricks/types/questions";
interface RatingSummaryProps {
questionSummary: QuestionSummary<RatingQuestion>;
@@ -17,7 +17,7 @@ interface ChoiceResult {
export default function RatingSummary({ questionSummary }: RatingSummaryProps) {
const results: ChoiceResult[] = useMemo(() => {
if (questionSummary.question.type !== "rating") return [];
if (questionSummary.question.type !== QuestionType.Rating) return [];
// build a dictionary of choices
const resultsDict: { [key: string]: ChoiceResult } = {};
for (let i = 1; i <= questionSummary.question.range; i++) {
@@ -12,14 +12,15 @@ import MultipleChoiceSummary from "./MultipleChoiceSummary";
import NPSSummary from "./NPSSummary";
import OpenTextSummary from "./OpenTextSummary";
import RatingSummary from "./RatingSummary";
import type {
CTAQuestion,
MultipleChoiceMultiQuestion,
MultipleChoiceSingleQuestion,
NPSQuestion,
OpenTextQuestion,
Question,
RatingQuestion,
import {
QuestionType,
type CTAQuestion,
type MultipleChoiceMultiQuestion,
type MultipleChoiceSingleQuestion,
type NPSQuestion,
type OpenTextQuestion,
type Question,
type RatingQuestion,
} from "@formbricks/types/questions";
export default function SummaryList({ environmentId, surveyId }) {
@@ -69,7 +70,7 @@ export default function SummaryList({ environmentId, surveyId }) {
) : (
<>
{summaryData.map((questionSummary) => {
if (questionSummary.question.type === "openText") {
if (questionSummary.question.type === QuestionType.OpenText) {
return (
<OpenTextSummary
key={questionSummary.question.id}
@@ -79,8 +80,8 @@ export default function SummaryList({ environmentId, surveyId }) {
);
}
if (
questionSummary.question.type === "multipleChoiceSingle" ||
questionSummary.question.type === "multipleChoiceMulti"
questionSummary.question.type === QuestionType.MultipleChoiceSingle ||
questionSummary.question.type === QuestionType.MultipleChoiceMulti
) {
return (
<MultipleChoiceSummary
@@ -95,7 +96,7 @@ export default function SummaryList({ environmentId, surveyId }) {
/>
);
}
if (questionSummary.question.type === "nps") {
if (questionSummary.question.type === QuestionType.NPS) {
return (
<NPSSummary
key={questionSummary.question.id}
@@ -103,7 +104,7 @@ export default function SummaryList({ environmentId, surveyId }) {
/>
);
}
if (questionSummary.question.type === "cta") {
if (questionSummary.question.type === QuestionType.CTA) {
return (
<CTASummary
key={questionSummary.question.id}
@@ -111,7 +112,7 @@ export default function SummaryList({ environmentId, surveyId }) {
/>
);
}
if (questionSummary.question.type === "rating") {
if (questionSummary.question.type === QuestionType.Rating) {
return (
<RatingSummary
key={questionSummary.question.id}
@@ -1,4 +1,4 @@
import type { Question } from "@formbricks/types/questions";
import { QuestionType, type Question } from "@formbricks/types/questions";
import OpenTextQuestion from "./OpenTextQuestion";
import MultipleChoiceSingleQuestion from "./MultipleChoiceSingleQuestion";
import MultipleChoiceMultiQuestion from "./MultipleChoiceMultiQuestion";
@@ -19,42 +19,42 @@ export default function QuestionConditional({
lastQuestion,
brandColor,
}: QuestionConditionalProps) {
return question.type === "openText" ? (
return question.type === QuestionType.OpenText ? (
<OpenTextQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "multipleChoiceSingle" ? (
) : question.type === QuestionType.MultipleChoiceSingle ? (
<MultipleChoiceSingleQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "multipleChoiceMulti" ? (
) : question.type === QuestionType.MultipleChoiceMulti ? (
<MultipleChoiceMultiQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "nps" ? (
) : question.type === QuestionType.NPS ? (
<NPSQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "cta" ? (
) : question.type === QuestionType.CTA ? (
<CTAQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "rating" ? (
) : question.type === QuestionType.Rating ? (
<RatingQuestion
question={question}
onSubmit={onSubmit}
+7 -6
View File
@@ -8,6 +8,7 @@ import {
} from "@heroicons/react/24/solid";
import { createId } from "@paralleldrive/cuid2";
import { replaceQuestionPresetPlaceholders } from "./templates";
import { QuestionType as QuestionId } from "@formbricks/types/questions";
export type QuestionType = {
id: string;
@@ -19,7 +20,7 @@ export type QuestionType = {
export const questionTypes: QuestionType[] = [
{
id: "openText",
id: QuestionId.OpenText,
label: "Free text",
description: "A single line of text",
icon: ChatBubbleBottomCenterTextIcon,
@@ -30,7 +31,7 @@ export const questionTypes: QuestionType[] = [
},
},
{
id: "multipleChoiceSingle",
id: QuestionId.MultipleChoiceSingle,
label: "Single-Select",
description: "A single choice from a list of options (radio buttons)",
icon: QueueListIcon,
@@ -44,7 +45,7 @@ export const questionTypes: QuestionType[] = [
},
},
{
id: "multipleChoiceMulti",
id: QuestionId.MultipleChoiceMulti,
label: "Multi-Select",
description: "Number of choices from a list of options (checkboxes)",
icon: ListBulletIcon,
@@ -58,7 +59,7 @@ export const questionTypes: QuestionType[] = [
},
},
{
id: "nps",
id: QuestionId.NPS,
label: "Net Promoter Score® (NPS)",
description: "Rate satisfaction on a 0-10 scale",
icon: PresentationChartBarIcon,
@@ -69,7 +70,7 @@ export const questionTypes: QuestionType[] = [
},
},
{
id: "cta",
id: QuestionId.CTA,
label: "Call-to-Action",
description: "Ask your users to perform an action",
icon: CursorArrowRippleIcon,
@@ -81,7 +82,7 @@ export const questionTypes: QuestionType[] = [
},
},
{
id: "rating",
id: QuestionId.Rating,
label: "Rating",
description: "Ask your users to rate something",
icon: StarIcon,
@@ -1,5 +1,5 @@
import { h } from "preact";
import type { Question } from "../../../types/questions";
import { QuestionType, type Question } from "@formbricks/types/questions";
import OpenTextQuestion from "./OpenTextQuestion";
import MultipleChoiceSingleQuestion from "./MultipleChoiceSingleQuestion";
import MultipleChoiceMultiQuestion from "./MultipleChoiceMultiQuestion";
@@ -20,42 +20,42 @@ export default function QuestionConditional({
lastQuestion,
brandColor,
}: QuestionConditionalProps) {
return question.type === "openText" ? (
return question.type === QuestionType.OpenText ? (
<OpenTextQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "multipleChoiceSingle" ? (
) : question.type === QuestionType.MultipleChoiceSingle ? (
<MultipleChoiceSingleQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "multipleChoiceMulti" ? (
) : question.type === QuestionType.MultipleChoiceMulti ? (
<MultipleChoiceMultiQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "nps" ? (
) : question.type === QuestionType.NPS ? (
<NPSQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "cta" ? (
) : question.type === QuestionType.CTA ? (
<CTAQuestion
question={question}
onSubmit={onSubmit}
lastQuestion={lastQuestion}
brandColor={brandColor}
/>
) : question.type === "rating" ? (
) : question.type === QuestionType.Rating ? (
<RatingQuestion
question={question}
onSubmit={onSubmit}
+1
View File
@@ -10,6 +10,7 @@ export enum QuestionType {
NPS = "nps",
CTA = "cta",
Rating = "rating",
Consent = "consent",
}
export type Question =
+8 -7
View File
@@ -1,5 +1,6 @@
import { z } from "zod";
import { ZEventClass } from "./eventClasses";
import { QuestionType } from "../questions";
export const ZSurveyThankYouCard = z.object({
enabled: z.boolean(),
@@ -115,33 +116,33 @@ const ZSurveyQuestionBase = z.object({
});
export const ZSurveyOpenTextQuestion = ZSurveyQuestionBase.extend({
type: z.literal("openText"),
type: z.literal(QuestionType.OpenText),
placeholder: z.string().optional(),
});
export const ZSurveyConsentQuestion = ZSurveyQuestionBase.extend({
type: z.literal("consent"),
type: z.literal(QuestionType.Consent),
placeholder: z.string().optional(),
});
export const ZSurveyMultipleChoiceSingleQuestion = ZSurveyQuestionBase.extend({
type: z.literal("multipleChoiceSingle"),
type: z.literal(QuestionType.MultipleChoiceSingle),
choices: z.array(ZSurveyChoice),
});
export const ZSurveyMultipleChoiceMultiQuestion = ZSurveyQuestionBase.extend({
type: z.literal("multipleChoiceMulti"),
type: z.literal(QuestionType.MultipleChoiceMulti),
choices: z.array(ZSurveyChoice),
});
export const ZSurveyNPSQuestion = ZSurveyQuestionBase.extend({
type: z.literal("nps"),
type: z.literal(QuestionType.NPS),
lowerLabel: z.string(),
upperLabel: z.string(),
});
export const ZSurveyCTAQuestion = ZSurveyQuestionBase.extend({
type: z.literal("cta"),
type: z.literal(QuestionType.CTA),
html: z.string().optional(),
buttonUrl: z.string().optional(),
buttonExternal: z.boolean(),
@@ -149,7 +150,7 @@ export const ZSurveyCTAQuestion = ZSurveyQuestionBase.extend({
});
export const ZSurveyRatingQuestion = ZSurveyQuestionBase.extend({
type: z.literal("rating"),
type: z.literal(QuestionType.Rating),
scale: z.union([z.literal("number"), z.literal("smiley"), z.literal("star")]),
range: z.union([z.literal(5), z.literal(3), z.literal(4), z.literal(7), z.literal(10)]),
lowerLabel: z.string(),