From 3206637e2286e2ccd300cb63145bfe0648f01bf5 Mon Sep 17 00:00:00 2001 From: Matti Nannt Date: Wed, 10 May 2023 13:31:49 +0200 Subject: [PATCH] Add Rating Question (Numbers, Stars & Smileys) (#271) Add new Star Rating Question Type with different ranges and variations. --------- Co-authored-by: moritzrengert --- .../surveys/[surveyId]/RatingResponse.tsx | 135 +++++ .../surveys/[surveyId]/edit/QuestionCard.tsx | 1 + .../[surveyId]/edit/RatingQuestionForm.tsx | 19 +- .../[surveyId]/edit/RatingTypeDropdown.tsx | 11 +- .../[surveyId]/responses/ResponseTimeline.tsx | 21 +- .../[surveyId]/responses/SingleResponse.tsx | 14 +- .../surveys/[surveyId]/summary/CTASummary.tsx | 3 +- .../summary/MultipleChoiceSummary.tsx | 3 +- .../surveys/[surveyId]/summary/NPSSummary.tsx | 3 +- .../[surveyId]/summary/OpenTextSummary.tsx | 3 +- .../[surveyId]/summary/RatingSummary.tsx | 18 +- .../[surveyId]/summary/SummaryList.tsx | 40 +- apps/web/components/Smileys.tsx | 464 +++++++++++++++++ .../web/components/preview/RatingQuestion.tsx | 117 ++++- packages/js/src/components/RatingQuestion.tsx | 133 ++++- packages/js/src/components/Smileys.tsx | 471 ++++++++++++++++++ packages/types/responses.ts | 6 +- 17 files changed, 1395 insertions(+), 67 deletions(-) create mode 100644 apps/web/app/environments/[environmentId]/surveys/[surveyId]/RatingResponse.tsx create mode 100644 apps/web/components/Smileys.tsx create mode 100644 packages/js/src/components/Smileys.tsx diff --git a/apps/web/app/environments/[environmentId]/surveys/[surveyId]/RatingResponse.tsx b/apps/web/app/environments/[environmentId]/surveys/[surveyId]/RatingResponse.tsx new file mode 100644 index 0000000000..66afa8398f --- /dev/null +++ b/apps/web/app/environments/[environmentId]/surveys/[surveyId]/RatingResponse.tsx @@ -0,0 +1,135 @@ +import { + ConfusedFace, + FrowningFace, + GrinningFaceWithSmilingEyes, + GrinningSquintingFace, + NeutralFace, + PerseveringFace, + SlightlySmilingFace, + SmilingFaceWithSmilingEyes, + TiredFace, + WearyFace, +} from "@/components/Smileys"; + +import { StarIcon } from "@heroicons/react/24/solid"; + +interface RatingResponseProps { + scale?: "number" | "star" | "smiley"; + range?: number; + answer: string; +} + +export const RatingResponse: React.FC = ({ scale, range, answer }) => { + if (typeof answer !== "number") return null; + if (typeof scale === "undefined" || typeof range === "undefined") return answer; + + if (scale === "star") { + // show number of stars according to answer value + const stars: any = []; + for (let i = 0; i < range; i++) { + if (i < parseInt(answer)) { + stars.push(); + } else { + stars.push(); + } + } + return
{stars}
; + } + + if (scale === "smiley") { + if (range === 10 && answer === 1) { + return ( +
+ +
+ ); + } + if ((range === 10 && answer === 2) || (range === 7 && answer === 1)) { + return ( +
+ +
+ ); + } + if (range === 10 && answer === 3) { + return ( +
+ +
+ ); + } + if ((range === 10 && answer === 4) || (range === 7 && answer === 2) || (range === 5 && answer === 1)) { + return ( +
+ +
+ ); + } + if ( + (range === 10 && answer === 5) || + (range === 7 && answer === 3) || + (range === 5 && answer === 2) || + (range === 4 && answer === 1) || + (range === 3 && answer === 1) + ) { + return ( +
+ +
+ ); + } + if ( + (range === 10 && answer === 6) || + (range === 7 && answer === 4) || + (range === 5 && answer === 3) || + (range === 4 && answer === 2) || + (range === 3 && answer === 2) + ) { + return ( +
+ +
+ ); + } + if ( + (range === 10 && answer === 7) || + (range === 7 && answer === 5) || + (range === 5 && answer === 4) || + (range === 4 && answer === 3) + ) { + return ( +
+ +
+ ); + } + if ( + (range === 10 && answer === 8) || + (range === 5 && answer === 5) || + (range === 4 && answer === 4) || + (range === 3 && answer === 3) + ) { + return ( +
+ +
+ ); + } + if ((range === 10 && answer === 9) || (range === 7 && answer === 6)) { + return ( +
+ +
+ ); + } + if ((range === 10 && answer === 10) || (range === 7 && answer === 7)) { + return ( +
+ +
+ ); + } + } + + return answer; +}; diff --git a/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/QuestionCard.tsx b/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/QuestionCard.tsx index 2dc52a5f17..98e58d47d1 100644 --- a/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/QuestionCard.tsx +++ b/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/QuestionCard.tsx @@ -176,6 +176,7 @@ export default function QuestionCard({ questionIdx={questionIdx} updateQuestion={updateQuestion} lastQuestion={lastQuestion} + survey={localSurvey} /> ) : null}
diff --git a/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/RatingQuestionForm.tsx b/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/RatingQuestionForm.tsx index edb14a40bc..dca2809308 100644 --- a/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/RatingQuestionForm.tsx +++ b/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/RatingQuestionForm.tsx @@ -2,9 +2,11 @@ import type { RatingQuestion } from "@formbricks/types/questions"; import { Input, Label } from "@formbricks/ui"; import { FaceSmileIcon, HashtagIcon, StarIcon } from "@heroicons/react/24/outline"; +import type { Survey } from "@formbricks/types/surveys"; import Dropdown from "./RatingTypeDropdown"; interface RatingQuestionFormProps { + survey: Survey; question: RatingQuestion; questionIdx: number; updateQuestion: (questionIdx: number, updatedAttributes: any) => void; @@ -50,8 +52,8 @@ export default function RatingQuestionForm({ updateQuestion(questionIdx, { scale: option.value })} @@ -63,13 +65,14 @@ export default function RatingQuestionForm({
updateQuestion(questionIdx, { range: option.value })} />
diff --git a/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/RatingTypeDropdown.tsx b/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/RatingTypeDropdown.tsx index 7720ddaf63..908704738b 100644 --- a/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/RatingTypeDropdown.tsx +++ b/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/RatingTypeDropdown.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { ChevronDownIcon } from "@heroicons/react/24/solid"; import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; @@ -11,15 +11,20 @@ type Option = { type DropdownProps = { options: Option[]; + disabled?: boolean; defaultValue: string | number; onSelect: (option: Option) => any; }; -const Dropdown = ({ options, defaultValue, onSelect }: DropdownProps) => { +const Dropdown = ({ options, defaultValue, onSelect, disabled = false }: DropdownProps) => { const [selectedOption, setSelectedOption] = useState