mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-05 16:19:55 -06:00
fix: usability improvements survey editor (#4362)
Co-authored-by: Dhruwang Jariwala <67850763+Dhruwang@users.noreply.github.com> Co-authored-by: Dhruwang <dhruwangjariwala18@gmail.com>
This commit is contained in:
@@ -136,7 +136,7 @@ export const AddressQuestionForm = ({
|
||||
{question.subheader === undefined && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
className="mt-4"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
|
||||
@@ -87,7 +87,7 @@ export const CalQuestionForm = ({
|
||||
<Button
|
||||
size="sm"
|
||||
className="mt-3"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
updateQuestion(questionIdx, {
|
||||
@@ -99,7 +99,7 @@ export const CalQuestionForm = ({
|
||||
{t("environments.surveys.edit.add_description")}
|
||||
</Button>
|
||||
)}
|
||||
<div className="mt-3 flex flex-col gap-6">
|
||||
<div className="mt-5 flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-3">
|
||||
<Label htmlFor="calUserName">{t("environments.surveys.edit.cal_username")}</Label>
|
||||
<div>
|
||||
|
||||
@@ -186,7 +186,6 @@ export function ConditionalLogic({
|
||||
<div className="mt-2 flex items-center space-x-2">
|
||||
<Button
|
||||
id="logicJumps"
|
||||
className="bg-slate-100 hover:bg-slate-50"
|
||||
type="button"
|
||||
name="logicJumps"
|
||||
size="sm"
|
||||
|
||||
@@ -126,7 +126,7 @@ export const ContactInfoQuestionForm = ({
|
||||
{question.subheader === undefined && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
className="mt-4"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
|
||||
@@ -70,7 +70,7 @@ export const DateQuestionForm = ({
|
||||
/>
|
||||
<div ref={parent}>
|
||||
{question.subheader !== undefined && (
|
||||
<div className="mt-2 inline-flex w-full items-center">
|
||||
<div className="inline-flex w-full items-center">
|
||||
<div className="w-full">
|
||||
<QuestionFormInput
|
||||
id="subheader"
|
||||
@@ -93,7 +93,7 @@ export const DateQuestionForm = ({
|
||||
<Button
|
||||
size="sm"
|
||||
className="mt-3"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
updateQuestion(questionIdx, {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { ConfirmationModal } from "@/modules/ui/components/confirmation-modal";
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -14,7 +15,6 @@ import { createId } from "@paralleldrive/cuid2";
|
||||
import { ArrowDownIcon, ArrowUpIcon, CopyIcon, EllipsisIcon, TrashIcon } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useState } from "react";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import {
|
||||
QUESTIONS_ICON_MAP,
|
||||
getCXQuestionNameMap,
|
||||
@@ -141,52 +141,62 @@ export const EditorCardMenu = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex space-x-2">
|
||||
<ArrowUpIcon
|
||||
className={cn(
|
||||
"h-4 cursor-pointer text-slate-500",
|
||||
cardIdx === 0 ? "cursor-not-allowed opacity-50" : "hover:text-slate-600"
|
||||
)}
|
||||
<div className="flex">
|
||||
<Button
|
||||
variant="minimal"
|
||||
size="icon"
|
||||
StartIcon={ArrowUpIcon}
|
||||
tooltip={t("common.move_up")}
|
||||
disabled={cardIdx === 0}
|
||||
onClick={(e) => {
|
||||
if (cardIdx !== 0) {
|
||||
e.stopPropagation();
|
||||
moveCard(cardIdx, true);
|
||||
}
|
||||
}}
|
||||
className="disabled:border-none"
|
||||
/>
|
||||
<ArrowDownIcon
|
||||
className={cn(
|
||||
"h-4 cursor-pointer text-slate-500",
|
||||
lastCard ? "cursor-not-allowed opacity-50" : "hover:text-slate-600"
|
||||
)}
|
||||
<Button
|
||||
variant="minimal"
|
||||
size="icon"
|
||||
StartIcon={ArrowDownIcon}
|
||||
tooltip={t("common.move_down")}
|
||||
disabled={lastCard}
|
||||
onClick={(e) => {
|
||||
if (!lastCard) {
|
||||
e.stopPropagation();
|
||||
moveCard(cardIdx, false);
|
||||
}
|
||||
}}
|
||||
className="disabled:border-none"
|
||||
/>
|
||||
<CopyIcon
|
||||
className="h-4 cursor-pointer text-slate-500 hover:text-slate-600"
|
||||
<Button
|
||||
variant="minimal"
|
||||
size="icon"
|
||||
StartIcon={CopyIcon}
|
||||
tooltip={t("common.duplicate")}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
duplicateCard(cardIdx);
|
||||
}}
|
||||
className="disabled:border-none"
|
||||
/>
|
||||
<TrashIcon
|
||||
className={cn(
|
||||
"h-4 cursor-pointer text-slate-500",
|
||||
isDeleteDisabled ? "cursor-not-allowed opacity-50" : "hover:text-slate-600"
|
||||
)}
|
||||
<Button
|
||||
variant="minimal"
|
||||
size="icon"
|
||||
StartIcon={TrashIcon}
|
||||
tooltip={t("common.delete")}
|
||||
disabled={isDeleteDisabled}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (isDeleteDisabled) return;
|
||||
deleteCard(cardIdx);
|
||||
}}
|
||||
className="disabled:border-none"
|
||||
/>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<EllipsisIcon className="h-4 w-4 text-slate-500 hover:text-slate-600" />
|
||||
<DropdownMenuTrigger className="h-10 w-10 rounded-lg border border-transparent p-2 hover:border-slate-200">
|
||||
<EllipsisIcon className="mx-auto h-4 w-4 text-slate-700 hover:text-slate-600" />
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent>
|
||||
|
||||
@@ -11,8 +11,7 @@ import { useTranslations } from "next-intl";
|
||||
import Link from "next/link";
|
||||
import { type JSX, useMemo, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { extractLanguageCodes } from "@formbricks/lib/i18n/utils";
|
||||
import { createI18nString } from "@formbricks/lib/i18n/utils";
|
||||
import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/utils";
|
||||
import { TAttributeClass } from "@formbricks/types/attribute-classes";
|
||||
import { TAllowedFileExtension, ZAllowedFileExtension } from "@formbricks/types/common";
|
||||
import { TProduct } from "@formbricks/types/product";
|
||||
@@ -168,7 +167,7 @@ export const FileUploadQuestionForm = ({
|
||||
<Button
|
||||
size="sm"
|
||||
className="mt-3"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
updateQuestion(questionIdx, {
|
||||
|
||||
@@ -143,7 +143,7 @@ export const MatrixQuestionForm = ({
|
||||
{question.subheader === undefined && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
className="mt-3"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
@@ -160,11 +160,13 @@ export const MatrixQuestionForm = ({
|
||||
<div>
|
||||
{/* Rows section */}
|
||||
<Label htmlFor="rows">{t("environments.surveys.edit.rows")}</Label>
|
||||
<div ref={parent}>
|
||||
<div className="mt-2 flex flex-col gap-2" ref={parent}>
|
||||
{question.rows.map((_, index) => (
|
||||
<div className="flex items-center" onKeyDown={(e) => handleKeyDown(e, "row")}>
|
||||
<div
|
||||
className="flex items-center"
|
||||
onKeyDown={(e) => handleKeyDown(e, "row")}
|
||||
key={`row-${index}-${question.rows.length}`}>
|
||||
<QuestionFormInput
|
||||
key={`row-${index}-${question.rows.length}`}
|
||||
id={`row-${index}`}
|
||||
label={""}
|
||||
localSurvey={localSurvey}
|
||||
@@ -180,9 +182,16 @@ export const MatrixQuestionForm = ({
|
||||
locale={locale}
|
||||
/>
|
||||
{question.rows.length > 2 && (
|
||||
<TrashIcon
|
||||
className="ml-2 mt-2 h-4 w-4 cursor-pointer text-slate-400 hover:text-slate-500"
|
||||
onClick={() => handleDeleteLabel("row", index)}
|
||||
<Button
|
||||
variant="minimal"
|
||||
size="icon"
|
||||
className="ml-2"
|
||||
StartIcon={TrashIcon}
|
||||
tooltip={t("common.delete")}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleDeleteLabel("row", index);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -190,7 +199,7 @@ export const MatrixQuestionForm = ({
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
className="mt-3"
|
||||
className="w-fit"
|
||||
StartIcon={PlusIcon}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
@@ -203,11 +212,13 @@ export const MatrixQuestionForm = ({
|
||||
<div>
|
||||
{/* Columns section */}
|
||||
<Label htmlFor="columns">{t("environments.surveys.edit.columns")}</Label>
|
||||
<div ref={parent}>
|
||||
<div className="mt-2 flex flex-col gap-2" ref={parent}>
|
||||
{question.columns.map((_, index) => (
|
||||
<div className="flex items-center" onKeyDown={(e) => handleKeyDown(e, "column")}>
|
||||
<div
|
||||
className="flex items-center"
|
||||
onKeyDown={(e) => handleKeyDown(e, "column")}
|
||||
key={`column-${index}-${question.columns.length}`}>
|
||||
<QuestionFormInput
|
||||
key={`column-${index}-${question.columns.length}`}
|
||||
id={`column-${index}`}
|
||||
label={""}
|
||||
localSurvey={localSurvey}
|
||||
@@ -223,9 +234,16 @@ export const MatrixQuestionForm = ({
|
||||
locale={locale}
|
||||
/>
|
||||
{question.columns.length > 2 && (
|
||||
<TrashIcon
|
||||
className="ml-2 mt-2 h-4 w-4 cursor-pointer text-slate-400 hover:text-slate-500"
|
||||
onClick={() => handleDeleteLabel("column", index)}
|
||||
<Button
|
||||
variant="minimal"
|
||||
size="icon"
|
||||
className="ml-2"
|
||||
StartIcon={TrashIcon}
|
||||
tooltip={t("common.delete")}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleDeleteLabel("column", index);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -233,7 +251,7 @@ export const MatrixQuestionForm = ({
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
className="mt-3"
|
||||
className="w-fit"
|
||||
StartIcon={PlusIcon}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -207,7 +207,7 @@ export const MultipleChoiceQuestionForm = ({
|
||||
{question.subheader === undefined && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
className="mt-3"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
@@ -248,7 +248,7 @@ export const MultipleChoiceQuestionForm = ({
|
||||
updateQuestion(questionIdx, { choices: newChoices });
|
||||
}}>
|
||||
<SortableContext items={question.choices} strategy={verticalListSortingStrategy}>
|
||||
<div className="flex flex-col" ref={parent}>
|
||||
<div className="flex flex-col gap-2" ref={parent}>
|
||||
{question.choices &&
|
||||
question.choices.map((choice, choiceIdx) => (
|
||||
<QuestionOptionChoice
|
||||
@@ -276,13 +276,13 @@ export const MultipleChoiceQuestionForm = ({
|
||||
</DndContext>
|
||||
<div className="mt-2 flex items-center justify-between space-x-2">
|
||||
{question.choices.filter((c) => c.id === "other").length === 0 && (
|
||||
<Button size="sm" variant="minimal" type="button" onClick={() => addOther()}>
|
||||
<Button size="sm" variant="secondary" type="button" onClick={() => addOther()}>
|
||||
{t("environments.surveys.edit.add_other")}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
updateQuestion(questionIdx, {
|
||||
|
||||
@@ -60,7 +60,7 @@ export const NPSQuestionForm = ({
|
||||
|
||||
<div ref={parent}>
|
||||
{question.subheader !== undefined && (
|
||||
<div className="mt-2 inline-flex w-full items-center">
|
||||
<div className="inline-flex w-full items-center">
|
||||
<div className="w-full">
|
||||
<QuestionFormInput
|
||||
id="subheader"
|
||||
@@ -81,7 +81,7 @@ export const NPSQuestionForm = ({
|
||||
{question.subheader === undefined && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
className="mt-3"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
@@ -96,7 +96,7 @@ export const NPSQuestionForm = ({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex justify-between space-x-2">
|
||||
<div className="flex justify-between space-x-2">
|
||||
<div className="w-full">
|
||||
<QuestionFormInput
|
||||
id="lowerLabel"
|
||||
|
||||
@@ -102,7 +102,7 @@ export const OpenQuestionForm = ({
|
||||
{question.subheader === undefined && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
className="mt-3"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
|
||||
@@ -89,7 +89,7 @@ export const PictureSelectionForm = ({
|
||||
/>
|
||||
<div ref={parent}>
|
||||
{question.subheader !== undefined && (
|
||||
<div className="mt-2 inline-flex w-full items-center">
|
||||
<div className="inline-flex w-full items-center">
|
||||
<div className="w-full">
|
||||
<QuestionFormInput
|
||||
id="subheader"
|
||||
@@ -110,7 +110,7 @@ export const PictureSelectionForm = ({
|
||||
{question.subheader === undefined && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
className="mt-3"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
|
||||
@@ -189,7 +189,7 @@ export const QuestionCard = ({
|
||||
{/* <div className="-ml-0.5 mr-3 h-6 min-w-[1.5rem] text-slate-400">
|
||||
{QUESTIONS_ICON_MAP[question.type]}
|
||||
</div> */}
|
||||
<div className="grow" dir="auto">
|
||||
<div className="flex grow flex-col justify-center" dir="auto">
|
||||
<p className="text-sm font-semibold">
|
||||
{recallToHeadline(
|
||||
question.headline,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { useSortable } from "@dnd-kit/sortable";
|
||||
import { CSS } from "@dnd-kit/utilities";
|
||||
import { GripVerticalIcon, PlusIcon, TrashIcon } from "lucide-react";
|
||||
@@ -70,9 +71,9 @@ export const QuestionOptionChoice = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex w-full gap-2" ref={setNodeRef} style={style}>
|
||||
<div className="flex w-full items-center gap-2" ref={setNodeRef} style={style}>
|
||||
{/* drag handle */}
|
||||
<div className={cn("mt-6", choice.id === "other" && "invisible")} {...listeners} {...attributes}>
|
||||
<div className={cn(choice.id === "other" && "invisible")} {...listeners} {...attributes}>
|
||||
<GripVerticalIcon className="h-4 w-4 cursor-move text-slate-400" />
|
||||
</div>
|
||||
|
||||
@@ -123,21 +124,33 @@ export const QuestionOptionChoice = ({
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-6 flex gap-2">
|
||||
<div className="flex gap-2">
|
||||
{question.choices && question.choices.length > 2 && (
|
||||
<TrashIcon
|
||||
className="h-4 w-4 cursor-pointer text-slate-400 hover:text-slate-500"
|
||||
onClick={() => deleteChoice(choiceIdx)}
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
StartIcon={TrashIcon}
|
||||
tooltip="Delete choice"
|
||||
aria-label="Delete choice"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
deleteChoice(choiceIdx);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{choice.id !== "other" && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
StartIcon={PlusIcon}
|
||||
tooltip="Add choice below"
|
||||
aria-label="Add choice below"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
addChoice(choiceIdx);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="h-4 w-4">
|
||||
{choice.id !== "other" && (
|
||||
<PlusIcon
|
||||
className="h-full w-full cursor-pointer text-slate-400 hover:text-slate-500"
|
||||
onClick={() => addChoice(choiceIdx)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -158,7 +158,7 @@ export const RankingQuestionForm = ({
|
||||
{question.subheader === undefined && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
className="mt-3"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
@@ -195,7 +195,7 @@ export const RankingQuestionForm = ({
|
||||
updateQuestion(questionIdx, { choices: newChoices });
|
||||
}}>
|
||||
<SortableContext items={question.choices} strategy={verticalListSortingStrategy}>
|
||||
<div className="flex flex-col" ref={parent}>
|
||||
<div className="flex flex-col gap-2" ref={parent}>
|
||||
{question.choices &&
|
||||
question.choices.map((choice, choiceIdx) => (
|
||||
<QuestionOptionChoice
|
||||
|
||||
@@ -56,7 +56,7 @@ export const RatingQuestionForm = ({
|
||||
|
||||
<div ref={parent}>
|
||||
{question.subheader !== undefined && (
|
||||
<div className="mt-2 inline-flex w-full items-center">
|
||||
<div className="inline-flex w-full items-center">
|
||||
<div className="w-full">
|
||||
<QuestionFormInput
|
||||
id="subheader"
|
||||
@@ -77,7 +77,7 @@ export const RatingQuestionForm = ({
|
||||
{question.subheader === undefined && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="minimal"
|
||||
variant="secondary"
|
||||
className="mt-3"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
@@ -131,7 +131,7 @@ export const RatingQuestionForm = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex justify-between gap-8">
|
||||
<div className="flex justify-between gap-8">
|
||||
<div className="flex-1">
|
||||
<QuestionFormInput
|
||||
id="lowerLabel"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { LanguageIndicator } from "@/modules/ee/multi-language-surveys/components/language-indicator";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { FileInput } from "@/modules/ui/components/file-input";
|
||||
import { Input } from "@/modules/ui/components/input";
|
||||
import { Label } from "@/modules/ui/components/label";
|
||||
@@ -10,8 +11,12 @@ import { ImagePlusIcon, PencilIcon, TrashIcon } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { type JSX, RefObject, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { extractLanguageCodes, getEnabledLanguages, getLocalizedValue } from "@formbricks/lib/i18n/utils";
|
||||
import { createI18nString } from "@formbricks/lib/i18n/utils";
|
||||
import {
|
||||
createI18nString,
|
||||
extractLanguageCodes,
|
||||
getEnabledLanguages,
|
||||
getLocalizedValue,
|
||||
} from "@formbricks/lib/i18n/utils";
|
||||
import { structuredClone } from "@formbricks/lib/pollyfills/structuredClone";
|
||||
import { useSyncScroll } from "@formbricks/lib/utils/hooks/useSyncScroll";
|
||||
import {
|
||||
@@ -515,9 +520,11 @@ export const QuestionFormInput = ({
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
<div className="mb-2 mt-3">
|
||||
<Label htmlFor={id}>{label}</Label>
|
||||
</div>
|
||||
{label && (
|
||||
<div className="mb-2 mt-3">
|
||||
<Label htmlFor={id}>{label}</Label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col gap-4 bg-white" ref={animationParent}>
|
||||
{showImageUploader && id === "headline" && (
|
||||
@@ -612,16 +619,29 @@ export const QuestionFormInput = ({
|
||||
)}
|
||||
</div>
|
||||
{id === "headline" && !isWelcomeCard && (
|
||||
<ImagePlusIcon
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
StartIcon={ImagePlusIcon}
|
||||
tooltip={t("environments.surveys.edit.add_photo_or_video")}
|
||||
aria-label="Toggle image uploader"
|
||||
className="ml-2 h-4 w-4 cursor-pointer text-slate-400 hover:text-slate-500"
|
||||
onClick={() => setShowImageUploader((prev) => !prev)}
|
||||
className="ml-2"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setShowImageUploader((prev) => !prev);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{id === "subheader" && question && question.subheader !== undefined && (
|
||||
<TrashIcon
|
||||
className="ml-2 h-4 w-4 cursor-pointer text-slate-400 hover:text-slate-500"
|
||||
onClick={() => {
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
StartIcon={TrashIcon}
|
||||
tooltip="Remove description"
|
||||
aria-label="Remove description"
|
||||
className="ml-2"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
if (updateQuestion) {
|
||||
updateQuestion(questionIdx, { subheader: undefined });
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ export const Button: React.ForwardRefExoticComponent<
|
||||
variant === "secondary" &&
|
||||
(disabled
|
||||
? "text-slate-400 dark:text-slate-500 bg-slate-200 dark:bg-slate-800"
|
||||
: "text-slate-600 hover:text-slate-500 bg-slate-200 hover:bg-slate-100 dark:bg-slate-700 dark:text-slate-300 dark:hover:bg-slate-600 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:bg-slate-300 focus:ring-neutral-500"),
|
||||
: "text-slate-600 hover:text-slate-500 bg-slate-100 hover:bg-slate-200 dark:bg-slate-700 dark:text-slate-300 dark:hover:bg-slate-600 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:bg-slate-300 focus:ring-neutral-500"),
|
||||
variant === "warn" &&
|
||||
(disabled
|
||||
? "text-slate-400 bg-transparent"
|
||||
|
||||
@@ -228,7 +228,7 @@ export const FileInput = ({
|
||||
multiple ? (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{selectedFiles.map((file, idx) => (
|
||||
<>
|
||||
<div key={`${id}-${idx}`}>
|
||||
{isImage(file.name) ? (
|
||||
<div className="relative h-24 w-40 overflow-hidden rounded-lg">
|
||||
<Image
|
||||
@@ -269,7 +269,7 @@ export const FileInput = ({
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Uploader
|
||||
|
||||
@@ -518,7 +518,7 @@ test.describe("Multi Language Survey Create", async () => {
|
||||
});
|
||||
|
||||
test.describe("Testing Survey with advanced logic", async () => {
|
||||
test.setTimeout(180000);
|
||||
test.setTimeout(240000);
|
||||
let url: string | null;
|
||||
|
||||
test("Create survey and submit response", async ({ page, users }) => {
|
||||
|
||||
@@ -155,8 +155,8 @@ export const createSurvey = async (page: Page, params: CreateSurveyParams) => {
|
||||
await page.getByRole("main").getByText("What would you like to know?").click();
|
||||
|
||||
await page.getByLabel("Question*").fill(params.openTextQuestion.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.openTextQuestion.description);
|
||||
await page.getByRole("button", { name: "Add description" }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.openTextQuestion.description);
|
||||
await page.getByLabel("Placeholder").fill(params.openTextQuestion.placeholder);
|
||||
|
||||
await page.locator("p").filter({ hasText: params.openTextQuestion.question }).click();
|
||||
@@ -169,8 +169,8 @@ export const createSurvey = async (page: Page, params: CreateSurveyParams) => {
|
||||
.click();
|
||||
await page.getByRole("button", { name: "Single-Select" }).click();
|
||||
await page.getByLabel("Question*").fill(params.singleSelectQuestion.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.singleSelectQuestion.description);
|
||||
await page.getByRole("button", { name: "Add description" }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.singleSelectQuestion.description);
|
||||
await page.getByPlaceholder("Option 1").fill(params.singleSelectQuestion.options[0]);
|
||||
await page.getByPlaceholder("Option 2").fill(params.singleSelectQuestion.options[1]);
|
||||
await page.getByRole("button", { name: 'Add "Other"', exact: true }).click();
|
||||
@@ -183,8 +183,8 @@ export const createSurvey = async (page: Page, params: CreateSurveyParams) => {
|
||||
.click();
|
||||
await page.getByRole("button", { name: "Multi-Select" }).click();
|
||||
await page.getByLabel("Question*").fill(params.multiSelectQuestion.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.multiSelectQuestion.description);
|
||||
await page.getByRole("button", { name: "Add description", exact: true }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.multiSelectQuestion.description);
|
||||
await page.getByPlaceholder("Option 1").fill(params.multiSelectQuestion.options[0]);
|
||||
await page.getByPlaceholder("Option 2").fill(params.multiSelectQuestion.options[1]);
|
||||
await page.getByPlaceholder("Option 3").fill(params.multiSelectQuestion.options[2]);
|
||||
@@ -197,8 +197,8 @@ export const createSurvey = async (page: Page, params: CreateSurveyParams) => {
|
||||
.click();
|
||||
await page.getByRole("button", { name: "Rating" }).click();
|
||||
await page.getByLabel("Question*").fill(params.ratingQuestion.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.ratingQuestion.description);
|
||||
await page.getByRole("button", { name: "Add description", exact: true }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.ratingQuestion.description);
|
||||
await page.getByPlaceholder("Not good").fill(params.ratingQuestion.lowLabel);
|
||||
await page.getByPlaceholder("Very satisfied").fill(params.ratingQuestion.highLabel);
|
||||
|
||||
@@ -241,8 +241,8 @@ export const createSurvey = async (page: Page, params: CreateSurveyParams) => {
|
||||
.click();
|
||||
await page.getByRole("button", { name: "Picture Selection" }).click();
|
||||
await page.getByLabel("Question*").fill(params.pictureSelectQuestion.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.pictureSelectQuestion.description);
|
||||
await page.getByRole("button", { name: "Add description", exact: true }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.pictureSelectQuestion.description);
|
||||
|
||||
// File Upload Question
|
||||
await page
|
||||
@@ -261,8 +261,8 @@ export const createSurvey = async (page: Page, params: CreateSurveyParams) => {
|
||||
.click();
|
||||
await page.getByRole("button", { name: "Matrix" }).click();
|
||||
await page.getByLabel("Question*").fill(params.matrix.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.matrix.description);
|
||||
await page.getByRole("button", { name: "Add description", exact: true }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.matrix.description);
|
||||
await page.locator("#row-0").click();
|
||||
await page.locator("#row-0").fill(params.matrix.rows[0]);
|
||||
await page.locator("#row-1").click();
|
||||
@@ -320,7 +320,7 @@ export const createSurvey = async (page: Page, params: CreateSurveyParams) => {
|
||||
.nth(1)
|
||||
.click();
|
||||
await page.getByLabel("Note*").fill(params.thankYouCard.headline);
|
||||
await page.getByLabel("Description").fill(params.thankYouCard.description);
|
||||
await page.locator('input[name="subheader"]').fill(params.thankYouCard.description);
|
||||
};
|
||||
|
||||
export const createSurveyWithLogic = async (page: Page, params: CreateSurveyWithLogicParams) => {
|
||||
@@ -357,8 +357,8 @@ export const createSurveyWithLogic = async (page: Page, params: CreateSurveyWith
|
||||
await page.getByRole("main").getByText("What would you like to know?").click();
|
||||
|
||||
await page.getByLabel("Question*").fill(params.openTextQuestion.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.openTextQuestion.description);
|
||||
await page.getByRole("button", { name: "Add description" }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.openTextQuestion.description);
|
||||
await page.getByLabel("Placeholder").fill(params.openTextQuestion.placeholder);
|
||||
|
||||
await page.locator("p").filter({ hasText: params.openTextQuestion.question }).click();
|
||||
@@ -371,8 +371,8 @@ export const createSurveyWithLogic = async (page: Page, params: CreateSurveyWith
|
||||
.click();
|
||||
await page.getByRole("button", { name: "Single-Select" }).click();
|
||||
await page.getByLabel("Question*").fill(params.singleSelectQuestion.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.singleSelectQuestion.description);
|
||||
await page.getByRole("button", { name: "Add description" }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.singleSelectQuestion.description);
|
||||
await page.getByPlaceholder("Option 1").fill(params.singleSelectQuestion.options[0]);
|
||||
await page.getByPlaceholder("Option 2").fill(params.singleSelectQuestion.options[1]);
|
||||
await page.getByRole("button", { name: 'Add "Other"', exact: true }).click();
|
||||
@@ -386,8 +386,8 @@ export const createSurveyWithLogic = async (page: Page, params: CreateSurveyWith
|
||||
.click();
|
||||
await page.getByRole("button", { name: "Multi-Select" }).click();
|
||||
await page.getByLabel("Question*").fill(params.multiSelectQuestion.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.multiSelectQuestion.description);
|
||||
await page.getByRole("button", { name: "Add description" }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.multiSelectQuestion.description);
|
||||
await page.getByPlaceholder("Option 1").fill(params.multiSelectQuestion.options[0]);
|
||||
await page.getByPlaceholder("Option 2").fill(params.multiSelectQuestion.options[1]);
|
||||
await page.getByPlaceholder("Option 3").fill(params.multiSelectQuestion.options[2]);
|
||||
@@ -400,8 +400,8 @@ export const createSurveyWithLogic = async (page: Page, params: CreateSurveyWith
|
||||
.click();
|
||||
await page.getByRole("button", { name: "Picture Selection" }).click();
|
||||
await page.getByLabel("Question*").fill(params.pictureSelectQuestion.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.pictureSelectQuestion.description);
|
||||
await page.getByRole("button", { name: "Add description" }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.pictureSelectQuestion.description);
|
||||
await page.getByLabel("Required").click();
|
||||
|
||||
// Rating Question
|
||||
@@ -412,8 +412,8 @@ export const createSurveyWithLogic = async (page: Page, params: CreateSurveyWith
|
||||
.click();
|
||||
await page.getByRole("button", { name: "Rating" }).click();
|
||||
await page.getByLabel("Question*").fill(params.ratingQuestion.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.ratingQuestion.description);
|
||||
await page.getByRole("button", { name: "Add description" }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.ratingQuestion.description);
|
||||
await page.getByPlaceholder("Not good").fill(params.ratingQuestion.lowLabel);
|
||||
await page.getByPlaceholder("Very satisfied").fill(params.ratingQuestion.highLabel);
|
||||
|
||||
@@ -446,8 +446,8 @@ export const createSurveyWithLogic = async (page: Page, params: CreateSurveyWith
|
||||
.click();
|
||||
await page.getByRole("button", { name: "Matrix" }).click();
|
||||
await page.getByLabel("Question*").fill(params.matrix.question);
|
||||
await page.getByRole("button", { name: "Add Description", exact: true }).click();
|
||||
await page.getByLabel("Description").fill(params.matrix.description);
|
||||
await page.getByRole("button", { name: "Add description" }).click();
|
||||
await page.locator('input[name="subheader"]').fill(params.matrix.description);
|
||||
await page.locator("#row-0").click();
|
||||
await page.locator("#row-0").fill(params.matrix.rows[0]);
|
||||
await page.locator("#row-1").click();
|
||||
@@ -941,5 +941,5 @@ export const createSurveyWithLogic = async (page: Page, params: CreateSurveyWith
|
||||
.nth(1)
|
||||
.click();
|
||||
await page.getByLabel("Note*").fill(params.thankYouCard.headline);
|
||||
await page.getByLabel("Description").fill(params.thankYouCard.description);
|
||||
await page.locator('input[name="subheader"]').fill(params.thankYouCard.description);
|
||||
};
|
||||
|
||||
@@ -1247,6 +1247,7 @@
|
||||
"add_logic": "Logik hinzufügen",
|
||||
"add_option": "Option hinzufügen",
|
||||
"add_other": "Anderes hinzufügen",
|
||||
"add_photo_or_video": "Foto oder Video hinzufügen",
|
||||
"add_pin": "PIN hinzufügen",
|
||||
"add_question": "Frage hinzufügen",
|
||||
"add_question_below": "Frage unten hinzufügen",
|
||||
|
||||
@@ -1238,7 +1238,7 @@
|
||||
"add_condition_below": "Add condition below",
|
||||
"add_custom_styles": "Add custom styles",
|
||||
"add_delay_before_showing_survey": "Add delay before showing survey",
|
||||
"add_description": "Add Description",
|
||||
"add_description": "Add description",
|
||||
"add_ending": "Add ending",
|
||||
"add_ending_below": "Add ending below",
|
||||
"add_hidden_field_id": "Add hidden field ID",
|
||||
@@ -1247,6 +1247,7 @@
|
||||
"add_logic": "Add logic",
|
||||
"add_option": "Add option",
|
||||
"add_other": "Add \"Other\"",
|
||||
"add_photo_or_video": "Add photo or video",
|
||||
"add_pin": "Add PIN",
|
||||
"add_question": "Add question",
|
||||
"add_question_below": "Add question below",
|
||||
|
||||
@@ -1247,6 +1247,7 @@
|
||||
"add_logic": "Adicionar lógica",
|
||||
"add_option": "Adicionar opção",
|
||||
"add_other": "Adicionar \"Outro",
|
||||
"add_photo_or_video": "Adicionar foto ou video",
|
||||
"add_pin": "Adicionar PIN",
|
||||
"add_question": "Adicionar pergunta",
|
||||
"add_question_below": "Adicione a pergunta abaixo",
|
||||
|
||||
Reference in New Issue
Block a user