feat: adds image support in inputCombobox

This commit is contained in:
Piyush Gupta
2024-09-11 16:48:23 +05:30
parent af4ae38564
commit 887c5c0eef
8 changed files with 202 additions and 147 deletions
@@ -1,6 +1,7 @@
import {
getConditionOperatorOptions,
getConditionValueOptions,
getDefaultOperatorForQuestion,
getMatchValueProps,
} from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/util";
import { createId } from "@paralleldrive/cuid2";
@@ -20,7 +21,7 @@ import {
TDyanmicLogicField,
TRightOperand,
TSingleCondition,
TSurveyLogicCondition,
TSurveyLogicConditionsOperator,
} from "@formbricks/types/surveys/logic";
import { TSurvey, TSurveyQuestion } from "@formbricks/types/surveys/types";
import {
@@ -50,7 +51,18 @@ export function AdvancedLogicEditorConditions({
updateQuestion,
depth = 0,
}: AdvancedLogicEditorConditions) {
const handleAddConditionBelow = (resourceId: string, condition: TSingleCondition) => {
const handleAddConditionBelow = (resourceId: string) => {
const operator = getDefaultOperatorForQuestion(question);
const condition: TSingleCondition = {
id: createId(),
leftOperand: {
value: question.id,
type: "question",
},
operator,
};
const logicCopy = structuredClone(question.logic) || [];
const logicItem = logicCopy[logicIdx];
addConditionBelow(logicItem.conditions, resourceId, condition);
@@ -126,7 +138,7 @@ export function AdvancedLogicEditorConditions({
});
};
const handleOperatorChange = (condition: TSingleCondition, value: TSurveyLogicCondition) => {
const handleOperatorChange = (condition: TSingleCondition, value: TSurveyLogicConditionsOperator) => {
if (value !== condition.operator) {
handleUpdateCondition(condition.id, {
operator: value,
@@ -204,14 +216,7 @@ export function AdvancedLogicEditorConditions({
<DropdownMenuItem
className="flex items-center gap-2"
onClick={() => {
handleAddConditionBelow(condition.id, {
id: createId(),
leftOperand: {
value: localSurvey.questions[questionIdx].id,
type: "question",
},
operator: "equals",
});
handleAddConditionBelow(condition.id);
}}>
<PlusIcon className="h-4 w-4" />
Add condition below
@@ -265,7 +270,7 @@ export function AdvancedLogicEditorConditions({
showSearch={false}
options={conditionOperatorOptions}
value={condition.operator}
onChangeValue={(val: TSurveyLogicCondition) => {
onChangeValue={(val: TSurveyLogicConditionsOperator) => {
handleOperatorChange(condition, val);
}}
comboboxClasses="grow min-w-[150px]"
@@ -297,14 +302,7 @@ export function AdvancedLogicEditorConditions({
<DropdownMenuItem
className="flex items-center gap-2"
onClick={() => {
handleAddConditionBelow(condition.id, {
id: createId(),
leftOperand: {
value: localSurvey.questions[questionIdx].id,
type: "question",
},
operator: "equals",
});
handleAddConditionBelow(condition.id);
}}>
<PlusIcon className="h-4 w-4" />
Add condition below
@@ -1,4 +1,5 @@
import { AdvancedLogicEditor } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/AdvancedLogicEditor";
import { getDefaultOperatorForQuestion } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/util";
import { createId } from "@paralleldrive/cuid2";
import {
ArrowDownIcon,
@@ -44,6 +45,8 @@ export function ConditionalLogic({
}, [localSurvey, attributeClasses]);
const addLogic = () => {
const operator = getDefaultOperatorForQuestion(question);
const initialCondition: TSurveyAdvancedLogic = {
id: createId(),
conditions: {
@@ -53,10 +56,10 @@ export function ConditionalLogic({
{
id: createId(),
leftOperand: {
value: localSurvey.questions[questionIdx].id,
value: question.id,
type: "question",
},
operator: "isSkipped",
operator,
},
],
},
@@ -1,4 +1,4 @@
import { ZSurveyLogicCondition } from "@formbricks/types/surveys/logic";
import { ZSurveyLogicConditionsOperator } from "@formbricks/types/surveys/logic";
import { TSurveyQuestionTypeEnum } from "@formbricks/types/surveys/types";
export const ruleEngine = {
@@ -8,43 +8,43 @@ export const ruleEngine = {
options: [
{
label: "equals",
value: ZSurveyLogicCondition.Enum.equals,
value: ZSurveyLogicConditionsOperator.Enum.equals,
},
{
label: "does not equal",
value: ZSurveyLogicCondition.Enum.doesNotEqual,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
},
{
label: "contains",
value: ZSurveyLogicCondition.Enum.contains,
value: ZSurveyLogicConditionsOperator.Enum.contains,
},
{
label: "does not contain",
value: ZSurveyLogicCondition.Enum.doesNotContain,
value: ZSurveyLogicConditionsOperator.Enum.doesNotContain,
},
{
label: "starts with",
value: ZSurveyLogicCondition.Enum.startsWith,
value: ZSurveyLogicConditionsOperator.Enum.startsWith,
},
{
label: "does not start with",
value: ZSurveyLogicCondition.Enum.doesNotStartWith,
value: ZSurveyLogicConditionsOperator.Enum.doesNotStartWith,
},
{
label: "ends with",
value: ZSurveyLogicCondition.Enum.endsWith,
value: ZSurveyLogicConditionsOperator.Enum.endsWith,
},
{
label: "does not end with",
value: ZSurveyLogicCondition.Enum.doesNotEndWith,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEndWith,
},
{
label: "is submitted",
value: ZSurveyLogicCondition.Enum.isSubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -52,35 +52,35 @@ export const ruleEngine = {
options: [
{
label: "=",
value: ZSurveyLogicCondition.Enum.equals,
value: ZSurveyLogicConditionsOperator.Enum.equals,
},
{
label: "!=",
value: ZSurveyLogicCondition.Enum.doesNotEqual,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
},
{
label: ">",
value: ZSurveyLogicCondition.Enum.isGreaterThan,
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan,
},
{
label: "<",
value: ZSurveyLogicCondition.Enum.isLessThan,
value: ZSurveyLogicConditionsOperator.Enum.isLessThan,
},
{
label: ">=",
value: ZSurveyLogicCondition.Enum.isGreaterThanOrEqual,
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual,
},
{
label: "<=",
value: ZSurveyLogicCondition.Enum.isLessThanOrEqual,
value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual,
},
{
label: "is submitted",
value: ZSurveyLogicCondition.Enum.isSubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -89,23 +89,23 @@ export const ruleEngine = {
options: [
{
label: "equals",
value: ZSurveyLogicCondition.Enum.equals,
value: ZSurveyLogicConditionsOperator.Enum.equals,
},
{
label: "does not equal",
value: ZSurveyLogicCondition.Enum.doesNotEqual,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
},
{
label: "equals one of",
value: ZSurveyLogicCondition.Enum.equalsOneOf,
value: ZSurveyLogicConditionsOperator.Enum.equalsOneOf,
},
{
label: "is submitted",
value: ZSurveyLogicCondition.Enum.isSubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -113,27 +113,27 @@ export const ruleEngine = {
options: [
{
label: "equals",
value: ZSurveyLogicCondition.Enum.equals,
value: ZSurveyLogicConditionsOperator.Enum.equals,
},
{
label: "does not equal",
value: ZSurveyLogicCondition.Enum.doesNotEqual,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
},
{
label: "includes all of",
value: ZSurveyLogicCondition.Enum.includesAllOf,
value: ZSurveyLogicConditionsOperator.Enum.includesAllOf,
},
{
label: "includes one of",
value: ZSurveyLogicCondition.Enum.includesOneOf,
value: ZSurveyLogicConditionsOperator.Enum.includesOneOf,
},
{
label: "is submitted",
value: ZSurveyLogicCondition.Enum.isSubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -141,27 +141,27 @@ export const ruleEngine = {
options: [
{
label: "equals",
value: ZSurveyLogicCondition.Enum.equals,
value: ZSurveyLogicConditionsOperator.Enum.equals,
},
{
label: "does not equal",
value: ZSurveyLogicCondition.Enum.doesNotEqual,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
},
{
label: "includes all of",
value: ZSurveyLogicCondition.Enum.includesAllOf,
value: ZSurveyLogicConditionsOperator.Enum.includesAllOf,
},
{
label: "includes one of",
value: ZSurveyLogicCondition.Enum.includesOneOf,
value: ZSurveyLogicConditionsOperator.Enum.includesOneOf,
},
{
label: "is submitted",
value: ZSurveyLogicCondition.Enum.isSubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -169,35 +169,35 @@ export const ruleEngine = {
options: [
{
label: "=",
value: ZSurveyLogicCondition.Enum.equals,
value: ZSurveyLogicConditionsOperator.Enum.equals,
},
{
label: "!=",
value: ZSurveyLogicCondition.Enum.doesNotEqual,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
},
{
label: ">",
value: ZSurveyLogicCondition.Enum.isGreaterThan,
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan,
},
{
label: "<",
value: ZSurveyLogicCondition.Enum.isLessThan,
value: ZSurveyLogicConditionsOperator.Enum.isLessThan,
},
{
label: ">=",
value: ZSurveyLogicCondition.Enum.isGreaterThanOrEqual,
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual,
},
{
label: "<=",
value: ZSurveyLogicCondition.Enum.isLessThanOrEqual,
value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual,
},
{
label: "is submitted",
value: ZSurveyLogicCondition.Enum.isSubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -205,35 +205,35 @@ export const ruleEngine = {
options: [
{
label: "=",
value: ZSurveyLogicCondition.Enum.equals,
value: ZSurveyLogicConditionsOperator.Enum.equals,
},
{
label: "!=",
value: ZSurveyLogicCondition.Enum.doesNotEqual,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
},
{
label: ">",
value: ZSurveyLogicCondition.Enum.isGreaterThan,
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan,
},
{
label: "<",
value: ZSurveyLogicCondition.Enum.isLessThan,
value: ZSurveyLogicConditionsOperator.Enum.isLessThan,
},
{
label: ">=",
value: ZSurveyLogicCondition.Enum.isGreaterThanOrEqual,
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual,
},
{
label: "<=",
value: ZSurveyLogicCondition.Enum.isLessThanOrEqual,
value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual,
},
{
label: "is submitted",
value: ZSurveyLogicCondition.Enum.isSubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -241,11 +241,11 @@ export const ruleEngine = {
options: [
{
label: "is clicked",
value: ZSurveyLogicCondition.Enum.isClicked,
value: ZSurveyLogicConditionsOperator.Enum.isClicked,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -253,11 +253,11 @@ export const ruleEngine = {
options: [
{
label: "is accepted",
value: ZSurveyLogicCondition.Enum.isAccepted,
value: ZSurveyLogicConditionsOperator.Enum.isAccepted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -265,27 +265,27 @@ export const ruleEngine = {
options: [
{
label: "equals",
value: ZSurveyLogicCondition.Enum.equals,
value: ZSurveyLogicConditionsOperator.Enum.equals,
},
{
label: "does not equal",
value: ZSurveyLogicCondition.Enum.doesNotEqual,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
},
{
label: "is before",
value: ZSurveyLogicCondition.Enum.isBefore,
value: ZSurveyLogicConditionsOperator.Enum.isBefore,
},
{
label: "is after",
value: ZSurveyLogicCondition.Enum.isAfter,
value: ZSurveyLogicConditionsOperator.Enum.isAfter,
},
{
label: "is submitted",
value: ZSurveyLogicCondition.Enum.isSubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -293,11 +293,11 @@ export const ruleEngine = {
options: [
{
label: "is submitted",
value: ZSurveyLogicCondition.Enum.isSubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -305,11 +305,11 @@ export const ruleEngine = {
options: [
{
label: "is submitted",
value: ZSurveyLogicCondition.Enum.isSubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -317,11 +317,11 @@ export const ruleEngine = {
options: [
{
label: "is booked",
value: ZSurveyLogicCondition.Enum.isBooked,
value: ZSurveyLogicConditionsOperator.Enum.isBooked,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -329,15 +329,15 @@ export const ruleEngine = {
options: [
{
label: "is partially submitted",
value: ZSurveyLogicCondition.Enum.isPartiallySubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isPartiallySubmitted,
},
{
label: "is completely submitted",
value: ZSurveyLogicCondition.Enum.isCompletelySubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isCompletelySubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -345,11 +345,11 @@ export const ruleEngine = {
options: [
{
label: "is submitted",
value: ZSurveyLogicCondition.Enum.isSubmitted,
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "is skipped",
value: ZSurveyLogicCondition.Enum.isSkipped,
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
@@ -359,35 +359,35 @@ export const ruleEngine = {
options: [
{
label: "equals",
value: ZSurveyLogicCondition.Enum.equals,
value: ZSurveyLogicConditionsOperator.Enum.equals,
},
{
label: "does not equal",
value: ZSurveyLogicCondition.Enum.doesNotEqual,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
},
{
label: "contains",
value: ZSurveyLogicCondition.Enum.contains,
value: ZSurveyLogicConditionsOperator.Enum.contains,
},
{
label: "does not contain",
value: ZSurveyLogicCondition.Enum.doesNotContain,
value: ZSurveyLogicConditionsOperator.Enum.doesNotContain,
},
{
label: "starts with",
value: ZSurveyLogicCondition.Enum.startsWith,
value: ZSurveyLogicConditionsOperator.Enum.startsWith,
},
{
label: "does not start with",
value: ZSurveyLogicCondition.Enum.doesNotStartWith,
value: ZSurveyLogicConditionsOperator.Enum.doesNotStartWith,
},
{
label: "ends with",
value: ZSurveyLogicCondition.Enum.endsWith,
value: ZSurveyLogicConditionsOperator.Enum.endsWith,
},
{
label: "does not end with",
value: ZSurveyLogicCondition.Enum.doesNotEndWith,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEndWith,
},
],
},
@@ -395,27 +395,27 @@ export const ruleEngine = {
options: [
{
label: "=",
value: ZSurveyLogicCondition.Enum.equals,
value: ZSurveyLogicConditionsOperator.Enum.equals,
},
{
label: "!=",
value: ZSurveyLogicCondition.Enum.doesNotEqual,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
},
{
label: ">",
value: ZSurveyLogicCondition.Enum.isGreaterThan,
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan,
},
{
label: "<",
value: ZSurveyLogicCondition.Enum.isLessThan,
value: ZSurveyLogicConditionsOperator.Enum.isLessThan,
},
{
label: ">=",
value: ZSurveyLogicCondition.Enum.isGreaterThanOrEqual,
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual,
},
{
label: "<=",
value: ZSurveyLogicCondition.Enum.isLessThanOrEqual,
value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual,
},
],
},
@@ -424,35 +424,35 @@ export const ruleEngine = {
options: [
{
label: "equals",
value: ZSurveyLogicCondition.Enum.equals,
value: ZSurveyLogicConditionsOperator.Enum.equals,
},
{
label: "does not equal",
value: ZSurveyLogicCondition.Enum.doesNotEqual,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
},
{
label: "contains",
value: ZSurveyLogicCondition.Enum.contains,
value: ZSurveyLogicConditionsOperator.Enum.contains,
},
{
label: "does not contain",
value: ZSurveyLogicCondition.Enum.doesNotContain,
value: ZSurveyLogicConditionsOperator.Enum.doesNotContain,
},
{
label: "starts with",
value: ZSurveyLogicCondition.Enum.startsWith,
value: ZSurveyLogicConditionsOperator.Enum.startsWith,
},
{
label: "does not start with",
value: ZSurveyLogicCondition.Enum.doesNotStartWith,
value: ZSurveyLogicConditionsOperator.Enum.doesNotStartWith,
},
{
label: "ends with",
value: ZSurveyLogicCondition.Enum.endsWith,
value: ZSurveyLogicConditionsOperator.Enum.endsWith,
},
{
label: "does not end with",
value: ZSurveyLogicCondition.Enum.doesNotEndWith,
value: ZSurveyLogicConditionsOperator.Enum.doesNotEndWith,
},
],
},
@@ -28,8 +28,14 @@ import {
TRightOperand,
TSingleCondition,
TSurveyAdvancedLogic,
TSurveyLogicConditionsOperator,
} from "@formbricks/types/surveys/logic";
import { TSurvey, TSurveyQuestionTypeEnum, TSurveyVariable } from "@formbricks/types/surveys/types";
import {
TSurvey,
TSurveyQuestion,
TSurveyQuestionTypeEnum,
TSurveyVariable,
} from "@formbricks/types/surveys/types";
import { TComboboxGroupedOption, TComboboxOption } from "@formbricks/ui/InputCombobox";
// formats the text to highlight specific parts of the text with slashes
@@ -145,6 +151,29 @@ export const actionObjectiveOptions: TComboboxOption[] = [
{ label: "Jump to question", value: "jumpToQuestion" },
];
const getQuestionOperatorOptions = (question: TSurveyQuestion): TComboboxOption[] => {
let options;
if (question.type === "openText") {
const inputType = question.inputType === "number" ? "number" : "text";
options = ruleEngine.question.openText[inputType].options;
} else {
options = ruleEngine.question[question.type].options;
}
if (question.required) {
options = options.filter((option) => option.value !== "isSkipped");
}
return options;
};
export const getDefaultOperatorForQuestion = (question: TSurveyQuestion): TSurveyLogicConditionsOperator => {
const options = getQuestionOperatorOptions(question);
return options[0].value.toString() as TSurveyLogicConditionsOperator;
};
export const getConditionOperatorOptions = (
condition: TSingleCondition,
localSurvey: TSurvey
@@ -158,13 +187,11 @@ export const getConditionOperatorOptions = (
return ruleEngine.hiddenField.options;
} else if (condition.leftOperand.type === "question") {
const questions = localSurvey.questions || [];
const question =
questions.find((question) => question.id === condition.leftOperand.value) || questions[0];
if (question.type === "openText") {
const inputType = question.inputType === "number" ? "number" : "text";
return ruleEngine.question.openText[inputType].options;
}
return ruleEngine.question[question.type].options;
const question = questions.find((question) => question.id === condition.leftOperand.value);
if (!question) return [];
return getQuestionOperatorOptions(question);
}
return [];
};
@@ -318,7 +345,8 @@ export const getMatchValueProps = (
} else if (selectedQuestion?.type === TSurveyQuestionTypeEnum.PictureSelection) {
const choices = selectedQuestion.choices.map((choice, idx) => {
return {
label: choice.imageUrl.split("/").pop() || `Image ${idx + 1}`,
imgSrc: choice.imageUrl,
label: `Picture ${idx + 1}`,
value: choice.id,
meta: {
type: "static",
@@ -1006,9 +1034,9 @@ export const findQuestionUsedInLogic = (survey: TSurvey, questionId: string): nu
return isUsedInCondition(logicRule.conditions) || logicRule.actions.some(isUsedInAction);
};
return survey.questions
.filter((question) => question.id !== questionId)
.findIndex((question) => question.logic && question.logic.some(isUsedInLogicRule));
return survey.questions.findIndex(
(question) => question.logic && question.id !== questionId && question.logic.some(isUsedInLogicRule)
);
};
export const findOptionUsedInLogic = (survey: TSurvey, questionId: string, optionId: string): number => {
@@ -8,7 +8,7 @@ import type {
TRightOperand,
TSingleCondition,
TSurveyAdvancedLogic,
TSurveyLogicCondition,
TSurveyLogicConditionsOperator,
} from "@formbricks/types/surveys/logic";
import {
type TSurveyEndings,
@@ -29,7 +29,7 @@ const isOldLogic = (logic: TOldLogic | TSurveyAdvancedLogic): logic is TOldLogic
return Object.keys(logic).some((key) => ["condition", "destination", "value"].includes(key));
};
const doesRightOperandExist = (operator: TSurveyLogicCondition): boolean => {
const doesRightOperandExist = (operator: TSurveyLogicConditionsOperator): boolean => {
return ![
"isAccepted",
"isBooked",
@@ -166,8 +166,8 @@ function convertLogicCondition(
function mapOldOperatorToNew(
oldCondition: string,
questionType: TSurveyQuestionTypeEnum
): TSurveyLogicCondition {
const conditionMap: Record<string, TSurveyLogicCondition> = {
): TSurveyLogicConditionsOperator {
const conditionMap: Record<string, TSurveyLogicConditionsOperator> = {
accepted: "isAccepted",
clicked: "isClicked",
submitted: "isSubmitted",
+10 -10
View File
@@ -1,6 +1,6 @@
import { z } from "zod";
export const ZSurveyLogicCondition = z.enum([
export const ZSurveyLogicConditionsOperator = z.enum([
"equals",
"doesNotEqual",
"contains",
@@ -28,13 +28,13 @@ export const ZSurveyLogicCondition = z.enum([
]);
const operatorsWithoutRightOperand = [
ZSurveyLogicCondition.Enum.isSubmitted,
ZSurveyLogicCondition.Enum.isSkipped,
ZSurveyLogicCondition.Enum.isClicked,
ZSurveyLogicCondition.Enum.isAccepted,
ZSurveyLogicCondition.Enum.isBooked,
ZSurveyLogicCondition.Enum.isPartiallySubmitted,
ZSurveyLogicCondition.Enum.isCompletelySubmitted,
ZSurveyLogicConditionsOperator.Enum.isSubmitted,
ZSurveyLogicConditionsOperator.Enum.isSkipped,
ZSurveyLogicConditionsOperator.Enum.isClicked,
ZSurveyLogicConditionsOperator.Enum.isAccepted,
ZSurveyLogicConditionsOperator.Enum.isBooked,
ZSurveyLogicConditionsOperator.Enum.isPartiallySubmitted,
ZSurveyLogicConditionsOperator.Enum.isCompletelySubmitted,
] as const;
export const ZDyanmicLogicField = z.enum(["question", "variable", "hiddenField"]);
@@ -69,7 +69,7 @@ const ZDynamicLogicFieldValue = z.union([ZDynamicQuestion, ZDynamicVariable, ZDy
message: "Conditional Logic: Invalid dynamic field value",
});
export type TSurveyLogicCondition = z.infer<typeof ZSurveyLogicCondition>;
export type TSurveyLogicConditionsOperator = z.infer<typeof ZSurveyLogicConditionsOperator>;
export type TDyanmicLogicField = z.infer<typeof ZDyanmicLogicField>;
export type TActionObjective = z.infer<typeof ZActionObjective>;
export type TActionTextVariableCalculateOperator = z.infer<typeof ZActionTextVariableCalculateOperator>;
@@ -91,7 +91,7 @@ export const ZSingleCondition = z
.object({
id: z.string().cuid2(),
leftOperand: ZLeftOperand,
operator: ZSurveyLogicCondition,
operator: ZSurveyLogicConditionsOperator,
rightOperand: ZRightOperand.optional(),
})
.and(
+6 -4
View File
@@ -10,7 +10,7 @@ import {
type TConditionGroup,
type TSingleCondition,
type TSurveyAdvancedLogic,
type TSurveyLogicCondition,
type TSurveyLogicConditionsOperator,
ZActionCalculateNumber,
ZActionCalculateText,
ZSurveyAdvancedLogic,
@@ -898,12 +898,14 @@ export const ZSurvey = z
const isInvalidOperatorsForQuestionType = (
question: TSurveyQuestion,
operator: TSurveyLogicCondition
operator: TSurveyLogicConditionsOperator
): boolean => {
let isInvalidOperator = false;
const questionType = question.type;
if (question.required && operator === "isSkipped") return true;
switch (questionType) {
case TSurveyQuestionTypeEnum.OpenText:
switch (question.inputType) {
@@ -1018,7 +1020,7 @@ const isInvalidOperatorsForQuestionType = (
const isInvalidOperatorsForVariableType = (
variableType: "text" | "number",
operator: TSurveyLogicCondition
operator: TSurveyLogicConditionsOperator
): boolean => {
let isInvalidOperator = false;
@@ -1058,7 +1060,7 @@ const isInvalidOperatorsForVariableType = (
return isInvalidOperator;
};
const isInvalidOperatorsForHiddenFieldType = (operator: TSurveyLogicCondition): boolean => {
const isInvalidOperatorsForHiddenFieldType = (operator: TSurveyLogicConditionsOperator): boolean => {
let isInvalidOperator = false;
if (
+24
View File
@@ -1,4 +1,5 @@
import { CheckIcon, ChevronDownIcon, LucideProps, XIcon } from "lucide-react";
import Image from "next/image";
import React, { useEffect, useMemo } from "react";
import { ForwardRefExoticComponent, RefAttributes } from "react";
import { cn } from "@formbricks/lib/cn";
@@ -16,6 +17,7 @@ import { Popover, PopoverContent, PopoverTrigger } from "../Popover";
export interface TComboboxOption {
icon?: ForwardRefExoticComponent<Omit<LucideProps, "ref"> & RefAttributes<SVGSVGElement>>;
imgSrc?: string;
label: string;
value: string | number;
meta?: Record<string, string>;
@@ -157,6 +159,7 @@ export const InputCombobox = ({
{idx !== 0 && <span>,</span>}
<div className="flex items-center gap-2">
{item.icon && <item.icon className="h-5 w-5 shrink-0 text-slate-400" />}
{item.imgSrc && <Image src={item.imgSrc} alt={item.label} width={24} height={24} />}
<span>{item.label}</span>
</div>
</>
@@ -165,6 +168,9 @@ export const InputCombobox = ({
return (
<div className="flex items-center gap-2 truncate">
{localValue.icon && <localValue.icon className="h-5 w-5 shrink-0 text-slate-400" />}
{localValue.imgSrc && (
<Image src={localValue.imgSrc} alt={localValue.label} width={24} height={24} />
)}
<span className="truncate">{localValue.label}</span>
</div>
);
@@ -246,6 +252,15 @@ export const InputCombobox = ({
<CheckIcon className="mr-2 h-4 w-4 text-slate-300 hover:text-slate-400" />
)}
{option.icon && <option.icon className="mr-2 h-5 w-5 shrink-0 text-slate-400" />}
{option.imgSrc && (
<Image
src={option.imgSrc}
alt={option.label}
width={24}
height={24}
className="mr-2 shrink-0"
/>
)}
<span className="truncate">{option.label}</span>
</CommandItem>
))}
@@ -272,6 +287,15 @@ export const InputCombobox = ({
<CheckIcon className="mr-2 h-4 w-4 shrink-0 text-slate-300 hover:text-slate-400" />
)}
{option.icon && <option.icon className="mr-2 h-5 w-5 shrink-0 text-slate-400" />}
{option.imgSrc && (
<Image
src={option.imgSrc}
alt={option.label}
width={24}
height={24}
className="mr-2 shrink-0"
/>
)}
<span className="truncate">{option.label}</span>
</CommandItem>
))}