diff --git a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx
index 4b273a4657..f2d11201a3 100644
--- a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx
+++ b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx
@@ -1,5 +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 { LogicEditor } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor";
+import { getDefaultOperatorForQuestion } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils";
import { createId } from "@paralleldrive/cuid2";
import {
ArrowDownIcon,
@@ -14,8 +14,7 @@ import { useMemo } from "react";
import { duplicateLogicItem } from "@formbricks/lib/survey/logic/utils";
import { replaceHeadlineRecall } from "@formbricks/lib/utils/recall";
import { TAttributeClass } from "@formbricks/types/attribute-classes";
-import { TSurveyAdvancedLogic } from "@formbricks/types/surveys/logic";
-import { TSurvey, TSurveyQuestion } from "@formbricks/types/surveys/types";
+import { TSurvey, TSurveyLogic, TSurveyQuestion } from "@formbricks/types/surveys/types";
import { Button } from "@formbricks/ui/Button";
import {
DropdownMenu,
@@ -47,7 +46,7 @@ export function ConditionalLogic({
const addLogic = () => {
const operator = getDefaultOperatorForQuestion(question);
- const initialCondition: TSurveyAdvancedLogic = {
+ const initialCondition: TSurveyLogic = {
id: createId(),
conditions: {
id: createId(),
@@ -120,7 +119,7 @@ export function ConditionalLogic({
-
void;
question: TSurveyQuestion;
questionIdx: number;
@@ -14,7 +13,7 @@ interface AdvancedLogicEditorProps {
isLast: boolean;
}
-export function AdvancedLogicEditor({
+export function LogicEditor({
localSurvey,
logicItem,
updateQuestion,
@@ -22,10 +21,10 @@ export function AdvancedLogicEditor({
questionIdx,
logicIdx,
isLast,
-}: AdvancedLogicEditorProps) {
+}: LogicEditorProps) {
return (
-
-
void;
questionIdx: number;
}
-export function AdvancedLogicEditorActions({
+export function LogicEditorActions({
localSurvey,
logicItem,
logicIdx,
question,
updateQuestion,
questionIdx,
-}: AdvancedLogicEditorActions) {
+}: LogicEditorActions) {
const actions = logicItem.actions;
const handleActionsChange = (
operation: "remove" | "addBelow" | "duplicate" | "update",
actionIdx: number,
- action?: TSurveyAdvancedLogicAction
+ action?: TSurveyLogicAction
) => {
const logicCopy = structuredClone(question.logic) ?? [];
const logicItem = logicCopy[logicIdx];
@@ -80,9 +81,9 @@ export function AdvancedLogicEditorActions({
handleActionsChange("update", actionIdx, actionBody);
};
- const handleValuesChange = (actionIdx: number, values: Partial) => {
+ const handleValuesChange = (actionIdx: number, values: Partial) => {
const action = actions[actionIdx];
- const actionBody = { ...action, ...values } as TSurveyAdvancedLogicAction;
+ const actionBody = { ...action, ...values } as TSurveyLogicAction;
handleActionsChange("update", actionIdx, actionBody);
};
diff --git a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/AdvancedLogicEditorConditions.tsx b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditorConditions.tsx
similarity index 97%
rename from apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/AdvancedLogicEditorConditions.tsx
rename to apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditorConditions.tsx
index 49e4adc909..8b9a8d2e97 100644
--- a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/AdvancedLogicEditorConditions.tsx
+++ b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditorConditions.tsx
@@ -3,7 +3,7 @@ import {
getConditionValueOptions,
getDefaultOperatorForQuestion,
getMatchValueProps,
-} from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/util";
+} from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils";
import { createId } from "@paralleldrive/cuid2";
import { CopyIcon, MoreVerticalIcon, PlusIcon, TrashIcon, WorkflowIcon } from "lucide-react";
import { cn } from "@formbricks/lib/cn";
@@ -21,9 +21,10 @@ import {
TDyanmicLogicField,
TRightOperand,
TSingleCondition,
+ TSurvey,
TSurveyLogicConditionsOperator,
-} from "@formbricks/types/surveys/logic";
-import { TSurvey, TSurveyQuestion } from "@formbricks/types/surveys/types";
+ TSurveyQuestion,
+} from "@formbricks/types/surveys/types";
import {
DropdownMenu,
DropdownMenuContent,
@@ -32,7 +33,7 @@ import {
} from "@formbricks/ui/DropdownMenu";
import { InputCombobox, TComboboxOption } from "@formbricks/ui/InputCombobox";
-interface AdvancedLogicEditorConditionsProps {
+interface LogicEditorConditionsProps {
conditions: TConditionGroup;
updateQuestion: (questionIdx: number, updatedAttributes: any) => void;
question: TSurveyQuestion;
@@ -42,7 +43,7 @@ interface AdvancedLogicEditorConditionsProps {
depth?: number;
}
-export function AdvancedLogicEditorConditions({
+export function LogicEditorConditions({
conditions,
logicIdx,
question,
@@ -50,7 +51,7 @@ export function AdvancedLogicEditorConditions({
questionIdx,
updateQuestion,
depth = 0,
-}: AdvancedLogicEditorConditionsProps) {
+}: LogicEditorConditionsProps) {
const handleAddConditionBelow = (resourceId: string) => {
const operator = getDefaultOperatorForQuestion(question);
@@ -198,7 +199,7 @@ export function AdvancedLogicEditorConditions({
)}
-
{
+ const updateActions = (actions: TSurveyLogicAction[]): TSurveyLogicAction[] => {
return actions.map((action) => {
let updatedAction = { ...action };
@@ -145,7 +145,7 @@ export const QuestionsView = ({
// Update advanced logic
if (question.logic) {
- updatedQuestion.logic = question.logic.map((logicRule: TSurveyAdvancedLogic) => ({
+ updatedQuestion.logic = question.logic.map((logicRule: TSurveyLogic) => ({
...logicRule,
conditions: updateConditions(logicRule.conditions),
actions: updateActions(logicRule.actions),
diff --git a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/SurveyVariablesCardItem.tsx b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/SurveyVariablesCardItem.tsx
index 5f14652b01..fae5928c80 100644
--- a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/SurveyVariablesCardItem.tsx
+++ b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/SurveyVariablesCardItem.tsx
@@ -1,6 +1,6 @@
"use client";
-import { findVariableUsedInLogic } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/util";
+import { findVariableUsedInLogic } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils";
import { createId } from "@paralleldrive/cuid2";
import { TrashIcon } from "lucide-react";
import React, { useCallback, useEffect } from "react";
diff --git a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/logicRuleEngine.ts b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/logicRuleEngine.ts
index aca985f305..81b425558a 100644
--- a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/logicRuleEngine.ts
+++ b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/logicRuleEngine.ts
@@ -1,5 +1,4 @@
-import { ZSurveyLogicConditionsOperator } from "@formbricks/types/surveys/logic";
-import { TSurveyQuestionTypeEnum } from "@formbricks/types/surveys/types";
+import { TSurveyQuestionTypeEnum, ZSurveyLogicConditionsOperator } from "@formbricks/types/surveys/types";
export const logicRules = {
question: {
diff --git a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/util.tsx b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx
similarity index 95%
rename from apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/util.tsx
rename to apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx
index b5ce399650..fb1b48f75a 100644
--- a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/util.tsx
+++ b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx
@@ -1,36 +1,17 @@
-import {
- ArrowUpFromLineIcon,
- CalendarDaysIcon,
- CheckIcon,
- EyeOffIcon,
- FileDigitIcon,
- FileType2Icon,
- Grid3X3Icon,
- HomeIcon,
- ImageIcon,
- ListIcon,
- ListOrderedIcon,
- MessageSquareTextIcon,
- MousePointerClickIcon,
- PhoneIcon,
- PresentationIcon,
- Rows3Icon,
- StarIcon,
-} from "lucide-react";
+import { EyeOffIcon, FileDigitIcon, FileType2Icon } from "lucide-react";
import { HTMLInputTypeAttribute } from "react";
import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { isConditionGroup } from "@formbricks/lib/survey/logic/utils";
+import { questionTypes } from "@formbricks/lib/utils/questions";
import {
TConditionGroup,
TLeftOperand,
TRightOperand,
TSingleCondition,
- TSurveyAdvancedLogic,
- TSurveyAdvancedLogicAction,
- TSurveyLogicConditionsOperator,
-} from "@formbricks/types/surveys/logic";
-import {
TSurvey,
+ TSurveyLogic,
+ TSurveyLogicAction,
+ TSurveyLogicConditionsOperator,
TSurveyQuestion,
TSurveyQuestionTypeEnum,
TSurveyVariable,
@@ -57,22 +38,13 @@ export const formatTextWithSlashes = (text: string) => {
});
};
-const questionIconMapping = {
- openText: MessageSquareTextIcon,
- multipleChoiceSingle: Rows3Icon,
- multipleChoiceMulti: ListIcon,
- pictureSelection: ImageIcon,
- rating: StarIcon,
- nps: PresentationIcon,
- cta: MousePointerClickIcon,
- consent: CheckIcon,
- date: CalendarDaysIcon,
- fileUpload: ArrowUpFromLineIcon,
- cal: PhoneIcon,
- matrix: Grid3X3Icon,
- ranking: ListOrderedIcon,
- address: HomeIcon,
-};
+const questionIconMapping = questionTypes.reduce(
+ (prev, curr) => ({
+ ...prev,
+ [curr.id]: curr.icon,
+ }),
+ {}
+);
export const getConditionValueOptions = (
localSurvey: TSurvey,
@@ -763,7 +735,7 @@ export const getMatchValueProps = (
};
export const getActionTargetOptions = (
- action: TSurveyAdvancedLogicAction,
+ action: TSurveyLogicAction,
localSurvey: TSurvey,
currQuestionIdx: number
): TComboboxOption[] => {
@@ -1039,14 +1011,14 @@ export const findQuestionUsedInLogic = (survey: TSurvey, questionId: string): nu
}
};
- const isUsedInAction = (action: TSurveyAdvancedLogicAction): boolean => {
+ const isUsedInAction = (action: TSurveyLogicAction): boolean => {
return (
(action.objective === "jumpToQuestion" && action.target === questionId) ||
(action.objective === "requireAnswer" && action.target === questionId)
);
};
- const isUsedInLogicRule = (logicRule: TSurveyAdvancedLogic): boolean => {
+ const isUsedInLogicRule = (logicRule: TSurveyLogic): boolean => {
return isUsedInCondition(logicRule.conditions) || logicRule.actions.some(isUsedInAction);
};
@@ -1079,7 +1051,7 @@ export const findOptionUsedInLogic = (survey: TSurvey, questionId: string, optio
return false;
};
- const isUsedInLogicRule = (logicRule: TSurveyAdvancedLogic): boolean => {
+ const isUsedInLogicRule = (logicRule: TSurveyLogic): boolean => {
return isUsedInCondition(logicRule.conditions);
};
@@ -1100,11 +1072,11 @@ export const findVariableUsedInLogic = (survey: TSurvey, variableId: string): nu
}
};
- const isUsedInAction = (action: TSurveyAdvancedLogicAction): boolean => {
+ const isUsedInAction = (action: TSurveyLogicAction): boolean => {
return action.objective === "calculate" && action.variableId === variableId;
};
- const isUsedInLogicRule = (logicRule: TSurveyAdvancedLogic): boolean => {
+ const isUsedInLogicRule = (logicRule: TSurveyLogic): boolean => {
return isUsedInCondition(logicRule.conditions) || logicRule.actions.some(isUsedInAction);
};
@@ -1126,7 +1098,7 @@ export const findHiddenFieldUsedInLogic = (survey: TSurvey, hiddenFieldId: strin
}
};
- const isUsedInLogicRule = (logicRule: TSurveyAdvancedLogic): boolean => {
+ const isUsedInLogicRule = (logicRule: TSurveyLogic): boolean => {
return isUsedInCondition(logicRule.conditions);
};
diff --git a/packages/database/data-migrations/20240828122408_advanced_logic_editor/data-migration.ts b/packages/database/data-migrations/20240828122408_advanced_logic_editor/data-migration.ts
index 10e61e8c49..107e876866 100644
--- a/packages/database/data-migrations/20240828122408_advanced_logic_editor/data-migration.ts
+++ b/packages/database/data-migrations/20240828122408_advanced_logic_editor/data-migration.ts
@@ -3,15 +3,13 @@
/* eslint-disable no-console -- logging is allowed in migration scripts */
import { createId } from "@paralleldrive/cuid2";
import { PrismaClient } from "@prisma/client";
-import type {
- TRightOperand,
- TSingleCondition,
- TSurveyAdvancedLogic,
- TSurveyAdvancedLogicAction,
- TSurveyLogicConditionsOperator,
-} from "@formbricks/types/surveys/logic";
import {
+ type TRightOperand,
+ type TSingleCondition,
type TSurveyEndings,
+ type TSurveyLogic,
+ type TSurveyLogicAction,
+ type TSurveyLogicConditionsOperator,
type TSurveyMultipleChoiceQuestion,
type TSurveyQuestion,
TSurveyQuestionTypeEnum,
@@ -25,7 +23,7 @@ interface TOldLogic {
destination: string;
}
-const isOldLogic = (logic: TOldLogic | TSurveyAdvancedLogic): logic is TOldLogic => {
+const isOldLogic = (logic: TOldLogic | TSurveyLogic): logic is TOldLogic => {
return Object.keys(logic).some((key) => ["condition", "destination", "value"].includes(key));
};
@@ -202,7 +200,7 @@ function convertLogic(
surveyEndings: TSurveyEndings,
oldLogic: TOldLogic,
question: TSurveyQuestion
-): TSurveyAdvancedLogic | undefined {
+): TSurveyLogic | undefined {
if (!oldLogic.condition || !oldLogic.destination) {
return undefined;
}
@@ -223,7 +221,7 @@ function convertLogic(
}
}
- const action: TSurveyAdvancedLogicAction = {
+ const action: TSurveyLogicAction = {
id: createId(),
objective: "jumpToQuestion",
target: actionTarget,
diff --git a/packages/lib/response/utils.ts b/packages/lib/response/utils.ts
index 9620dedc19..c90fae92d4 100644
--- a/packages/lib/response/utils.ts
+++ b/packages/lib/response/utils.ts
@@ -31,7 +31,7 @@ import {
import { getLocalizedValue } from "../i18n/utils";
import { processResponseData } from "../responses";
import { getTodaysDateTimeFormatted } from "../time";
-import { evaluateAdvancedLogic, performActions } from "../utils/evaluateLogic";
+import { evaluateLogic, performActions } from "../utils/evaluateLogic";
import { sanitizeString } from "../utils/strings";
export const calculateTtcTotal = (ttc: TResponseTtc) => {
@@ -638,7 +638,7 @@ export const getSurveySummaryDropOff = (
}
});
- let localSurvey = JSON.parse(JSON.stringify(survey)) as TSurvey;
+ let localSurvey = structuredClone(survey);
let localResponseData: TResponseData = { ...response.data };
let localVariables: TResponseVariables = {
...surveyVariablesData,
@@ -742,15 +742,7 @@ const evaluateLogicAndGetNextQuestionId = (
if (currQuesTemp.logic && currQuesTemp.logic.length > 0) {
for (const logic of currQuesTemp.logic) {
- if (
- evaluateAdvancedLogic(
- localSurvey,
- data,
- localVariables,
- logic.conditions,
- selectedLanguage ?? "default"
- )
- ) {
+ if (evaluateLogic(localSurvey, data, localVariables, logic.conditions, selectedLanguage ?? "default")) {
const { jumpTarget, requiredQuestionIds, calculations } = performActions(
updatedSurvey,
logic.actions,
diff --git a/packages/lib/survey/logic/utils.ts b/packages/lib/survey/logic/utils.ts
index 9010d866be..0dc46a416c 100644
--- a/packages/lib/survey/logic/utils.ts
+++ b/packages/lib/survey/logic/utils.ts
@@ -3,9 +3,9 @@ import {
TActionObjective,
TConditionGroup,
TSingleCondition,
- TSurveyAdvancedLogic,
- TSurveyAdvancedLogicAction,
-} from "@formbricks/types/surveys/logic";
+ TSurveyLogic,
+ TSurveyLogicAction,
+} from "@formbricks/types/surveys/types";
type TCondition = TSingleCondition | TConditionGroup;
@@ -13,7 +13,7 @@ export const isConditionGroup = (condition: TCondition): condition is TCondition
return (condition as TConditionGroup).connector !== undefined;
};
-export const duplicateLogicItem = (logicItem: TSurveyAdvancedLogic): TSurveyAdvancedLogic => {
+export const duplicateLogicItem = (logicItem: TSurveyLogic): TSurveyLogic => {
const duplicateConditionGroup = (group: TConditionGroup): TConditionGroup => {
return {
...group,
@@ -35,7 +35,7 @@ export const duplicateLogicItem = (logicItem: TSurveyAdvancedLogic): TSurveyAdva
};
};
- const duplicateAction = (action: TSurveyAdvancedLogicAction): TSurveyAdvancedLogicAction => {
+ const duplicateAction = (action: TSurveyLogicAction): TSurveyLogicAction => {
return {
...action,
id: createId(),
@@ -176,9 +176,9 @@ export const updateCondition = (
};
export const getUpdatedActionBody = (
- action: TSurveyAdvancedLogicAction,
+ action: TSurveyLogicAction,
objective: TActionObjective
-): TSurveyAdvancedLogicAction => {
+): TSurveyLogicAction => {
if (objective === action.objective) return action;
switch (objective) {
case "calculate":
diff --git a/packages/lib/survey/tests/survey.test.ts b/packages/lib/survey/tests/survey.test.ts
index 07f2d7695b..9bb4d2a6af 100644
--- a/packages/lib/survey/tests/survey.test.ts
+++ b/packages/lib/survey/tests/survey.test.ts
@@ -1,7 +1,7 @@
import { prisma } from "../../__mocks__/database";
import { mockResponseNote, mockResponseWithMockPerson } from "../../response/tests/__mocks__/data.mock";
import { Prisma } from "@prisma/client";
-import { evaluateAdvancedLogic } from "utils/evaluateLogic";
+import { evaluateLogic } from "utils/evaluateLogic";
import { beforeEach, describe, expect, it } from "vitest";
import { testInputValidation } from "vitestSetup";
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
@@ -39,12 +39,12 @@ beforeEach(() => {
prisma.survey.count.mockResolvedValue(1);
});
-describe("evaluateAdvancedLogic with mockSurveyWithLogic", () => {
+describe("evaluateLogic with mockSurveyWithLogic", () => {
it("should return true when q1 answer is blue", () => {
const data = { q1: "blue" };
const variablesData = {};
- const result = evaluateAdvancedLogic(
+ const result = evaluateLogic(
mockSurveyWithLogic,
data,
variablesData,
@@ -58,7 +58,7 @@ describe("evaluateAdvancedLogic with mockSurveyWithLogic", () => {
const data = { q1: "red" };
const variablesData = {};
- const result = evaluateAdvancedLogic(
+ const result = evaluateLogic(
mockSurveyWithLogic,
data,
variablesData,
@@ -72,7 +72,7 @@ describe("evaluateAdvancedLogic with mockSurveyWithLogic", () => {
const data = { q1: "blue", q2: "pizza" };
const variablesData = {};
- const result = evaluateAdvancedLogic(
+ const result = evaluateLogic(
mockSurveyWithLogic,
data,
variablesData,
@@ -86,7 +86,7 @@ describe("evaluateAdvancedLogic with mockSurveyWithLogic", () => {
const data = { q1: "blue", q2: "burger" };
const variablesData = {};
- const result = evaluateAdvancedLogic(
+ const result = evaluateLogic(
mockSurveyWithLogic,
data,
variablesData,
@@ -100,7 +100,7 @@ describe("evaluateAdvancedLogic with mockSurveyWithLogic", () => {
const data = { q2: "pizza", q3: "Inception" };
const variablesData = {};
- const result = evaluateAdvancedLogic(
+ const result = evaluateLogic(
mockSurveyWithLogic,
data,
variablesData,
@@ -114,7 +114,7 @@ describe("evaluateAdvancedLogic with mockSurveyWithLogic", () => {
const data = { q4: "lmao" };
const variablesData = { siog1dabtpo3l0a3xoxw2922: "lmao" };
- const result = evaluateAdvancedLogic(
+ const result = evaluateLogic(
mockSurveyWithLogic,
data,
variablesData,
@@ -128,7 +128,7 @@ describe("evaluateAdvancedLogic with mockSurveyWithLogic", () => {
const data = { q4: "lol" };
const variablesData = { siog1dabtpo3l0a3xoxw2922: "damn" };
- const result = evaluateAdvancedLogic(
+ const result = evaluateLogic(
mockSurveyWithLogic,
data,
variablesData,
@@ -142,7 +142,7 @@ describe("evaluateAdvancedLogic with mockSurveyWithLogic", () => {
const data = { q5: "40" };
const variablesData = { km1srr55owtn2r7lkoh5ny1u: 35 };
- const result = evaluateAdvancedLogic(
+ const result = evaluateLogic(
mockSurveyWithLogic,
data,
variablesData,
@@ -156,7 +156,7 @@ describe("evaluateAdvancedLogic with mockSurveyWithLogic", () => {
const data = { q5: "40" };
const variablesData = { km1srr55owtn2r7lkoh5ny1u: 25 };
- const result = evaluateAdvancedLogic(
+ const result = evaluateLogic(
mockSurveyWithLogic,
data,
variablesData,
@@ -170,7 +170,7 @@ describe("evaluateAdvancedLogic with mockSurveyWithLogic", () => {
const data = { q6: ["lmao", "XD"], q1: "green", q2: "pizza", q3: "inspection", name: "pizza" };
const variablesData = { siog1dabtpo3l0a3xoxw2922: "tokyo" };
- const result = evaluateAdvancedLogic(
+ const result = evaluateLogic(
mockSurveyWithLogic,
data,
variablesData,
diff --git a/packages/lib/utils/evaluateLogic.ts b/packages/lib/utils/evaluateLogic.ts
index c8c4bf243f..f44a9b3e86 100644
--- a/packages/lib/utils/evaluateLogic.ts
+++ b/packages/lib/utils/evaluateLogic.ts
@@ -3,10 +3,8 @@ import {
TActionCalculate,
TConditionGroup,
TSingleCondition,
- TSurveyAdvancedLogicAction,
-} from "@formbricks/types/surveys/logic";
-import {
TSurvey,
+ TSurveyLogicAction,
TSurveyQuestion,
TSurveyQuestionTypeEnum,
TSurveyVariable,
@@ -14,7 +12,7 @@ import {
import { getLocalizedValue } from "../i18n/utils";
import { isConditionGroup } from "../survey/logic/utils";
-export const evaluateAdvancedLogic = (
+export const evaluateLogic = (
localSurvey: TSurvey,
data: TResponseData,
variablesData: TResponseVariables,
@@ -359,7 +357,7 @@ const getRightOperandValue = (
export const performActions = (
survey: TSurvey,
- actions: TSurveyAdvancedLogicAction[],
+ actions: TSurveyLogicAction[],
data: TResponseData,
calculationResults: TResponseVariables
): {
diff --git a/packages/surveys/src/components/general/Survey.tsx b/packages/surveys/src/components/general/Survey.tsx
index 5367947d8d..e4c0595d32 100644
--- a/packages/surveys/src/components/general/Survey.tsx
+++ b/packages/surveys/src/components/general/Survey.tsx
@@ -8,7 +8,7 @@ import { SurveyCloseButton } from "@/components/general/SurveyCloseButton";
import { WelcomeCard } from "@/components/general/WelcomeCard";
import { AutoCloseWrapper } from "@/components/wrappers/AutoCloseWrapper";
import { StackedCardsContainer } from "@/components/wrappers/StackedCardsContainer";
-import { evaluateAdvancedLogic, performActions } from "@/lib/logicEvaluator";
+import { evaluateLogic, performActions } from "@/lib/logicEvaluator";
import { parseRecallInformation } from "@/lib/recall";
import { cn } from "@/lib/utils";
import { useEffect, useMemo, useRef, useState } from "preact/hooks";
@@ -179,14 +179,18 @@ export const Survey = ({
};
const makeQuestionsRequired = (questionIds: string[]): void => {
- const localSurveyClone = structuredClone(localSurvey);
- localSurveyClone.questions.forEach((question) => {
- if (questionIds.includes(question.id)) {
- question.required = true;
- }
- });
-
- setlocalSurvey(localSurveyClone);
+ setlocalSurvey((prevSurvey) => ({
+ ...prevSurvey,
+ questions: prevSurvey.questions.map((question) => {
+ if (questionIds.includes(question.id)) {
+ return {
+ ...question,
+ required: true,
+ };
+ }
+ return question;
+ }),
+ }));
};
const pushVariableState = (questionId: string) => {
@@ -224,13 +228,7 @@ export const Survey = ({
if (currQuesTemp.logic && currQuesTemp.logic.length > 0) {
for (const logic of currQuesTemp.logic) {
if (
- evaluateAdvancedLogic(
- localSurvey,
- localResponseData,
- currentVariables,
- logic.conditions,
- selectedLanguage
- )
+ evaluateLogic(localSurvey, localResponseData, currentVariables, logic.conditions, selectedLanguage)
) {
const { jumpTarget, requiredQuestionIds, calculations } = performActions(
localSurvey,
diff --git a/packages/surveys/src/lib/logicEvaluator.ts b/packages/surveys/src/lib/logicEvaluator.ts
index f3851ec8ca..7ddfc17804 100644
--- a/packages/surveys/src/lib/logicEvaluator.ts
+++ b/packages/surveys/src/lib/logicEvaluator.ts
@@ -5,16 +5,14 @@ import {
TActionCalculate,
TConditionGroup,
TSingleCondition,
- TSurveyAdvancedLogicAction,
-} from "@formbricks/types/surveys/logic";
-import {
TSurvey,
+ TSurveyLogicAction,
TSurveyQuestion,
TSurveyQuestionTypeEnum,
TSurveyVariable,
} from "@formbricks/types/surveys/types";
-export const evaluateAdvancedLogic = (
+export const evaluateLogic = (
localSurvey: TSurvey,
data: TResponseData,
variablesData: TResponseVariables,
@@ -359,7 +357,7 @@ const getRightOperandValue = (
export const performActions = (
survey: TSurvey,
- actions: TSurveyAdvancedLogicAction[],
+ actions: TSurveyLogicAction[],
data: TResponseData,
calculationResults: TResponseVariables
): {
diff --git a/packages/surveys/src/lib/utils.ts b/packages/surveys/src/lib/utils.ts
index 9070af4024..04fec8b7d0 100644
--- a/packages/surveys/src/lib/utils.ts
+++ b/packages/surveys/src/lib/utils.ts
@@ -1,5 +1,10 @@
-import { TSurveyAdvancedLogic, TSurveyAdvancedLogicAction } from "@formbricks/types/surveys/logic";
-import { TSurvey, TSurveyQuestion, TSurveyQuestionChoice } from "@formbricks/types/surveys/types";
+import {
+ TSurvey,
+ TSurveyLogic,
+ TSurveyLogicAction,
+ TSurveyQuestion,
+ TSurveyQuestionChoice,
+} from "@formbricks/types/surveys/types";
export const cn = (...classes: string[]) => {
return classes.filter(Boolean).join(" ");
@@ -63,8 +68,8 @@ const getPossibleNextQuestions = (question: TSurveyQuestion): string[] => {
const possibleDestinations: string[] = [];
- question.logic.forEach((logic: TSurveyAdvancedLogic) => {
- logic.actions.forEach((action: TSurveyAdvancedLogicAction) => {
+ question.logic.forEach((logic: TSurveyLogic) => {
+ logic.actions.forEach((action: TSurveyLogicAction) => {
if (action.objective === "jumpToQuestion") {
possibleDestinations.push(action.target);
}
diff --git a/packages/types/surveys/logic.ts b/packages/types/surveys/logic.ts
deleted file mode 100644
index 4a7be1e672..0000000000
--- a/packages/types/surveys/logic.ts
+++ /dev/null
@@ -1,225 +0,0 @@
-import { z } from "zod";
-import { ZId } from "../common";
-
-export const ZSurveyLogicConditionsOperator = z.enum([
- "equals",
- "doesNotEqual",
- "contains",
- "doesNotContain",
- "startsWith",
- "doesNotStartWith",
- "endsWith",
- "doesNotEndWith",
- "isSubmitted",
- "isSkipped",
- "isGreaterThan",
- "isLessThan",
- "isGreaterThanOrEqual",
- "isLessThanOrEqual",
- "equalsOneOf",
- "includesAllOf",
- "includesOneOf",
- "isClicked",
- "isAccepted",
- "isBefore",
- "isAfter",
- "isBooked",
- "isPartiallySubmitted",
- "isCompletelySubmitted",
-]);
-
-const operatorsWithoutRightOperand = [
- 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"]);
-export const ZActionObjective = z.enum(["calculate", "requireAnswer", "jumpToQuestion"]);
-export const ZActionTextVariableCalculateOperator = z.enum(["assign", "concat"], {
- message: "Conditional Logic: Invalid operator for a text variable",
-});
-export const ZActionNumberVariableCalculateOperator = z.enum(
- ["add", "subtract", "multiply", "divide", "assign"],
- { message: "Conditional Logic: Invalid operator for a number variable" }
-);
-
-const ZDynamicQuestion = z.object({
- type: z.literal("question"),
- value: z.string().min(1, "Conditional Logic: Question id cannot be empty"),
-});
-
-const ZDynamicVariable = z.object({
- type: z.literal("variable"),
- value: z
- .string()
- .cuid2({ message: "Conditional Logic: Variable id must be a valid cuid" })
- .min(1, "Conditional Logic: Variable id cannot be empty"),
-});
-
-const ZDynamicHiddenField = z.object({
- type: z.literal("hiddenField"),
- value: z.string().min(1, "Conditional Logic: Hidden field id cannot be empty"),
-});
-
-const ZDynamicLogicFieldValue = z.union([ZDynamicQuestion, ZDynamicVariable, ZDynamicHiddenField], {
- message: "Conditional Logic: Invalid dynamic field value",
-});
-
-export type TSurveyLogicConditionsOperator = z.infer;
-export type TDyanmicLogicField = z.infer;
-export type TActionObjective = z.infer;
-export type TActionTextVariableCalculateOperator = z.infer;
-export type TActionNumberVariableCalculateOperator = z.infer;
-
-// Conditions
-const ZLeftOperand = ZDynamicLogicFieldValue;
-export type TLeftOperand = z.infer;
-
-export const ZRightOperandStatic = z.object({
- type: z.literal("static"),
- value: z.union([z.string(), z.number(), z.array(z.string())]),
-});
-
-export const ZRightOperand = z.union([ZRightOperandStatic, ZDynamicLogicFieldValue]);
-export type TRightOperand = z.infer;
-
-export const ZSingleCondition = z
- .object({
- id: ZId,
- leftOperand: ZLeftOperand,
- operator: ZSurveyLogicConditionsOperator,
- rightOperand: ZRightOperand.optional(),
- })
- .and(
- z.object({
- connector: z.undefined(),
- })
- )
- .superRefine((val, ctx) => {
- if (
- !operatorsWithoutRightOperand.includes(val.operator as (typeof operatorsWithoutRightOperand)[number])
- ) {
- if (val.rightOperand === undefined) {
- ctx.addIssue({
- code: z.ZodIssueCode.custom,
- message: `Conditional Logic: right operand is required for operator "${val.operator}"`,
- path: ["rightOperand"],
- });
- } else if (val.rightOperand.type === "static" && val.rightOperand.value === "") {
- ctx.addIssue({
- code: z.ZodIssueCode.custom,
- message: `Conditional Logic: right operand value cannot be empty for operator "${val.operator}"`,
- });
- }
- } else if (val.rightOperand !== undefined) {
- ctx.addIssue({
- code: z.ZodIssueCode.custom,
- message: `Conditional Logic: right operand should not be present for operator "${val.operator}"`,
- path: ["rightOperand"],
- });
- }
- });
-
-export type TSingleCondition = z.infer;
-
-export interface TConditionGroup {
- id: string;
- connector: "and" | "or";
- conditions: (TSingleCondition | TConditionGroup)[];
-}
-
-const ZConditionGroup: z.ZodType = z.lazy(() =>
- z.object({
- id: ZId,
- connector: z.enum(["and", "or"]),
- conditions: z.array(z.union([ZSingleCondition, ZConditionGroup])),
- })
-);
-
-// Actions
-export const ZActionVariableValueType = z.union([z.literal("static"), ZDyanmicLogicField]);
-export type TActionVariableValueType = z.infer;
-
-const ZActionBase = z.object({
- id: ZId,
- objective: ZActionObjective,
-});
-
-export type TActionBase = z.infer;
-
-const ZActionCalculateBase = ZActionBase.extend({
- objective: z.literal("calculate"),
- variableId: z.string(),
-});
-
-export const ZActionCalculateText = ZActionCalculateBase.extend({
- operator: ZActionTextVariableCalculateOperator,
- value: z.union([
- z.object({
- type: z.literal("static"),
- value: z
- .string({ message: "Conditional Logic: Value must be a string for text variable" })
- .min(1, "Conditional Logic: Please enter a value in logic field"),
- }),
- ZDynamicLogicFieldValue,
- ]),
-});
-
-export const ZActionCalculateNumber = ZActionCalculateBase.extend({
- operator: ZActionNumberVariableCalculateOperator,
- value: z.union([
- z.object({
- type: z.literal("static"),
- value: z.number({ message: "Conditional Logic: Value must be a number for number variable" }),
- }),
- ZDynamicLogicFieldValue,
- ]),
-}).superRefine((val, ctx) => {
- if (val.operator === "divide" && val.value.type === "static" && val.value.value === 0) {
- ctx.addIssue({
- code: z.ZodIssueCode.custom,
- message: "Conditional Logic: Cannot divide by zero",
- path: ["value", "value"],
- });
- }
-});
-
-const ZActionCalculate = z.union([ZActionCalculateText, ZActionCalculateNumber]);
-
-export type TActionCalculate = z.infer;
-
-const ZActionRequireAnswer = ZActionBase.extend({
- objective: z.literal("requireAnswer"),
- target: z.string().min(1, "Conditional Logic: Target question id cannot be empty"),
-});
-export type TActionRequireAnswer = z.infer;
-
-const ZActionJumpToQuestion = ZActionBase.extend({
- objective: z.literal("jumpToQuestion"),
- target: z.string().min(1, "Conditional Logic: Target question id cannot be empty"),
-});
-
-export type TActionJumpToQuestion = z.infer;
-
-export const ZSurveyAdvancedLogicAction = z.union([
- ZActionCalculate,
- ZActionRequireAnswer,
- ZActionJumpToQuestion,
-]);
-
-export type TSurveyAdvancedLogicAction = z.infer;
-
-const ZSurveyAdvancedLogicActions = z.array(ZSurveyAdvancedLogicAction);
-
-export const ZSurveyAdvancedLogic = z.object({
- id: ZId,
- conditions: ZConditionGroup,
- actions: ZSurveyAdvancedLogicActions,
-});
-
-export type TSurveyAdvancedLogic = z.infer;
diff --git a/packages/types/surveys/types.ts b/packages/types/surveys/types.ts
index 6f04f6e60c..76836c9182 100644
--- a/packages/types/surveys/types.ts
+++ b/packages/types/surveys/types.ts
@@ -5,16 +5,6 @@ import { ZAllowedFileExtension, ZColor, ZId, ZPlacement } from "../common";
import { ZLanguage } from "../product";
import { ZSegment } from "../segment";
import { ZBaseStyling } from "../styling";
-import {
- type TConditionGroup,
- type TSingleCondition,
- type TSurveyAdvancedLogic,
- type TSurveyAdvancedLogicAction,
- type TSurveyLogicConditionsOperator,
- ZActionCalculateNumber,
- ZActionCalculateText,
- ZSurveyAdvancedLogic,
-} from "./logic";
import {
FORBIDDEN_IDS,
findLanguageCodesForDuplicateLabels,
@@ -238,6 +228,226 @@ export const ZSurveyPictureChoice = z.object({
export type TSurveyQuestionChoice = z.infer;
+// Logic types
+export const ZSurveyLogicConditionsOperator = z.enum([
+ "equals",
+ "doesNotEqual",
+ "contains",
+ "doesNotContain",
+ "startsWith",
+ "doesNotStartWith",
+ "endsWith",
+ "doesNotEndWith",
+ "isSubmitted",
+ "isSkipped",
+ "isGreaterThan",
+ "isLessThan",
+ "isGreaterThanOrEqual",
+ "isLessThanOrEqual",
+ "equalsOneOf",
+ "includesAllOf",
+ "includesOneOf",
+ "isClicked",
+ "isAccepted",
+ "isBefore",
+ "isAfter",
+ "isBooked",
+ "isPartiallySubmitted",
+ "isCompletelySubmitted",
+]);
+
+const operatorsWithoutRightOperand = [
+ 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"]);
+export const ZActionObjective = z.enum(["calculate", "requireAnswer", "jumpToQuestion"]);
+export const ZActionTextVariableCalculateOperator = z.enum(["assign", "concat"], {
+ message: "Conditional Logic: Invalid operator for a text variable",
+});
+export const ZActionNumberVariableCalculateOperator = z.enum(
+ ["add", "subtract", "multiply", "divide", "assign"],
+ { message: "Conditional Logic: Invalid operator for a number variable" }
+);
+
+const ZDynamicQuestion = z.object({
+ type: z.literal("question"),
+ value: z.string().min(1, "Conditional Logic: Question id cannot be empty"),
+});
+
+const ZDynamicVariable = z.object({
+ type: z.literal("variable"),
+ value: z
+ .string()
+ .cuid2({ message: "Conditional Logic: Variable id must be a valid cuid" })
+ .min(1, "Conditional Logic: Variable id cannot be empty"),
+});
+
+const ZDynamicHiddenField = z.object({
+ type: z.literal("hiddenField"),
+ value: z.string().min(1, "Conditional Logic: Hidden field id cannot be empty"),
+});
+
+const ZDynamicLogicFieldValue = z.union([ZDynamicQuestion, ZDynamicVariable, ZDynamicHiddenField], {
+ message: "Conditional Logic: Invalid dynamic field value",
+});
+
+export type TSurveyLogicConditionsOperator = z.infer;
+export type TDyanmicLogicField = z.infer;
+export type TActionObjective = z.infer;
+export type TActionTextVariableCalculateOperator = z.infer;
+export type TActionNumberVariableCalculateOperator = z.infer;
+
+// Conditions
+const ZLeftOperand = ZDynamicLogicFieldValue;
+export type TLeftOperand = z.infer;
+
+export const ZRightOperandStatic = z.object({
+ type: z.literal("static"),
+ value: z.union([z.string(), z.number(), z.array(z.string())]),
+});
+
+export const ZRightOperand = z.union([ZRightOperandStatic, ZDynamicLogicFieldValue]);
+export type TRightOperand = z.infer;
+
+export const ZSingleCondition = z
+ .object({
+ id: ZId,
+ leftOperand: ZLeftOperand,
+ operator: ZSurveyLogicConditionsOperator,
+ rightOperand: ZRightOperand.optional(),
+ })
+ .and(
+ z.object({
+ connector: z.undefined(),
+ })
+ )
+ .superRefine((val, ctx) => {
+ if (
+ !operatorsWithoutRightOperand.includes(val.operator as (typeof operatorsWithoutRightOperand)[number])
+ ) {
+ if (val.rightOperand === undefined) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: `Conditional Logic: right operand is required for operator "${val.operator}"`,
+ path: ["rightOperand"],
+ });
+ } else if (val.rightOperand.type === "static" && val.rightOperand.value === "") {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: `Conditional Logic: right operand value cannot be empty for operator "${val.operator}"`,
+ });
+ }
+ } else if (val.rightOperand !== undefined) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: `Conditional Logic: right operand should not be present for operator "${val.operator}"`,
+ path: ["rightOperand"],
+ });
+ }
+ });
+
+export type TSingleCondition = z.infer;
+
+export interface TConditionGroup {
+ id: string;
+ connector: "and" | "or";
+ conditions: (TSingleCondition | TConditionGroup)[];
+}
+
+const ZConditionGroup: z.ZodType = z.lazy(() =>
+ z.object({
+ id: ZId,
+ connector: z.enum(["and", "or"]),
+ conditions: z.array(z.union([ZSingleCondition, ZConditionGroup])),
+ })
+);
+
+// Actions
+export const ZActionVariableValueType = z.union([z.literal("static"), ZDyanmicLogicField]);
+export type TActionVariableValueType = z.infer;
+
+const ZActionBase = z.object({
+ id: ZId,
+ objective: ZActionObjective,
+});
+
+export type TActionBase = z.infer;
+
+const ZActionCalculateBase = ZActionBase.extend({
+ objective: z.literal("calculate"),
+ variableId: z.string(),
+});
+
+export const ZActionCalculateText = ZActionCalculateBase.extend({
+ operator: ZActionTextVariableCalculateOperator,
+ value: z.union([
+ z.object({
+ type: z.literal("static"),
+ value: z
+ .string({ message: "Conditional Logic: Value must be a string for text variable" })
+ .min(1, "Conditional Logic: Please enter a value in logic field"),
+ }),
+ ZDynamicLogicFieldValue,
+ ]),
+});
+
+export const ZActionCalculateNumber = ZActionCalculateBase.extend({
+ operator: ZActionNumberVariableCalculateOperator,
+ value: z.union([
+ z.object({
+ type: z.literal("static"),
+ value: z.number({ message: "Conditional Logic: Value must be a number for number variable" }),
+ }),
+ ZDynamicLogicFieldValue,
+ ]),
+}).superRefine((val, ctx) => {
+ if (val.operator === "divide" && val.value.type === "static" && val.value.value === 0) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: "Conditional Logic: Cannot divide by zero",
+ path: ["value", "value"],
+ });
+ }
+});
+
+const ZActionCalculate = z.union([ZActionCalculateText, ZActionCalculateNumber]);
+
+export type TActionCalculate = z.infer;
+
+const ZActionRequireAnswer = ZActionBase.extend({
+ objective: z.literal("requireAnswer"),
+ target: z.string().min(1, "Conditional Logic: Target question id cannot be empty"),
+});
+export type TActionRequireAnswer = z.infer;
+
+const ZActionJumpToQuestion = ZActionBase.extend({
+ objective: z.literal("jumpToQuestion"),
+ target: z.string().min(1, "Conditional Logic: Target question id cannot be empty"),
+});
+
+export type TActionJumpToQuestion = z.infer;
+
+export const ZSurveyLogicAction = z.union([ZActionCalculate, ZActionRequireAnswer, ZActionJumpToQuestion]);
+
+export type TSurveyLogicAction = z.infer;
+
+const ZSurveyLogicActions = z.array(ZSurveyLogicAction);
+
+export const ZSurveyLogic = z.object({
+ id: ZId,
+ conditions: ZConditionGroup,
+ actions: ZSurveyLogicActions,
+});
+
+export type TSurveyLogic = z.infer;
+
export const ZSurveyQuestionBase = z.object({
id: ZSurveyQuestionId,
type: z.string(),
@@ -250,7 +460,7 @@ export const ZSurveyQuestionBase = z.object({
backButtonLabel: ZI18nString.optional(),
scale: z.enum(["number", "smiley", "star"]).optional(),
range: z.union([z.literal(5), z.literal(3), z.literal(4), z.literal(7), z.literal(10)]).optional(),
- logic: z.array(ZSurveyAdvancedLogic).optional(),
+ logic: z.array(ZSurveyLogic).optional(),
isDraft: z.boolean().optional(),
});
@@ -1628,7 +1838,7 @@ const validateActions = (
survey: TSurvey,
questionIndex: number,
logicIndex: number,
- actions: TSurveyAdvancedLogicAction[]
+ actions: TSurveyLogicAction[]
): z.ZodIssue[] => {
const questionIds = survey.questions.map((q) => q.id);
@@ -1701,11 +1911,7 @@ const validateActions = (
return actionIssues.filter((issue) => issue !== undefined);
};
-const validateLogic = (
- survey: TSurvey,
- questionIndex: number,
- logic: TSurveyAdvancedLogic[]
-): z.ZodIssue[] => {
+const validateLogic = (survey: TSurvey, questionIndex: number, logic: TSurveyLogic[]): z.ZodIssue[] => {
const logicIssues = logic.map((logicItem, logicIndex) => {
return [
...validateConditions(survey, questionIndex, logicIndex, logicItem.conditions),
diff --git a/packages/types/surveys/validation.ts b/packages/types/surveys/validation.ts
index d3eea0a7ca..a34c549b6d 100644
--- a/packages/types/surveys/validation.ts
+++ b/packages/types/surveys/validation.ts
@@ -2,10 +2,12 @@ import { z } from "zod";
import type {
TActionJumpToQuestion,
TConditionGroup,
+ TI18nString,
TSingleCondition,
- TSurveyAdvancedLogicAction,
-} from "./logic";
-import type { TI18nString, TSurveyLanguage, TSurveyQuestion } from "./types";
+ TSurveyLanguage,
+ TSurveyLogicAction,
+ TSurveyQuestion,
+} from "./types";
export const FORBIDDEN_IDS = [
"userId",
@@ -230,7 +232,7 @@ export const findQuestionsWithCyclicLogic = (questions: TSurveyQuestion[]): stri
};
// Helper function to find all "jumpToQuestion" actions in the logic
-const findJumpToQuestionActions = (actions: TSurveyAdvancedLogicAction[]): TActionJumpToQuestion[] => {
+const findJumpToQuestionActions = (actions: TSurveyLogicAction[]): TActionJumpToQuestion[] => {
return actions.filter((action) => action.objective === "jumpToQuestion");
};