diff --git a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditorActions.tsx b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditorActions.tsx index 876281b45e..5705cf2144 100644 --- a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditorActions.tsx +++ b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditorActions.tsx @@ -4,6 +4,7 @@ import { getActionTargetOptions, getActionValueOptions, getActionVariableOptions, + hasJumpToQuestionAction, } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils"; import { createId } from "@paralleldrive/cuid2"; import { CopyIcon, CornerDownRightIcon, EllipsisVerticalIcon, PlusIcon, TrashIcon } from "lucide-react"; @@ -60,7 +61,11 @@ export function LogicEditorActions({ actionsClone.splice(actionIdx, 1); break; case "addBelow": - actionsClone.splice(actionIdx + 1, 0, { id: createId(), objective: "jumpToQuestion", target: "" }); + actionsClone.splice(actionIdx + 1, 0, { + id: createId(), + objective: hasJumpToQuestionAction(logicItem.actions) ? "requireAnswer" : "jumpToQuestion", + target: "", + }); break; case "duplicate": actionsClone.splice(actionIdx + 1, 0, { ...actionsClone[actionIdx], id: createId() }); @@ -88,6 +93,11 @@ export function LogicEditorActions({ handleActionsChange("update", actionIdx, actionBody); }; + const filteredObjectiveOptions = actionObjectiveOptions.filter( + (option) => option.value !== "jumpToQuestion" + ); + const jumpToQuestionActionIdx = actions.findIndex((action) => action.objective === "jumpToQuestion"); + return (
@@ -102,7 +112,11 @@ export function LogicEditorActions({ id={`action-${idx}-objective`} key={`objective-${action.id}`} showSearch={false} - options={actionObjectiveOptions} + options={ + jumpToQuestionActionIdx === -1 || idx === jumpToQuestionActionIdx + ? actionObjectiveOptions + : filteredObjectiveOptions + } value={action.objective} onChangeValue={(val: TActionObjective) => { handleObjectiveChange(idx, val); diff --git a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx index 3b66577942..639d4cb349 100644 --- a/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx +++ b/apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx @@ -13,6 +13,7 @@ import { TSurvey, TSurveyLogic, TSurveyLogicAction, + TSurveyLogicActions, TSurveyLogicConditionsOperator, TSurveyQuestion, TSurveyQuestionId, @@ -147,6 +148,10 @@ export const actionObjectiveOptions: TComboboxOption[] = [ { label: "environments.surveys.edit.jump_to_question", value: "jumpToQuestion" }, ]; +export const hasJumpToQuestionAction = (actions: TSurveyLogicActions): boolean => { + return actions.some((action) => action.objective === "jumpToQuestion"); +}; + const getQuestionOperatorOptions = (question: TSurveyQuestion): TComboboxOption[] => { let options: TLogicRuleOption; diff --git a/packages/types/surveys/types.ts b/packages/types/surveys/types.ts index c1fefbc5a5..bec8f0c2cf 100644 --- a/packages/types/surveys/types.ts +++ b/packages/types/surveys/types.ts @@ -444,6 +444,8 @@ export type TSurveyLogicAction = z.infer; const ZSurveyLogicActions = z.array(ZSurveyLogicAction); +export type TSurveyLogicActions = z.infer; + export const ZSurveyLogic = z.object({ id: ZId, conditions: ZConditionGroup, @@ -2025,6 +2027,15 @@ const validateActions = ( return undefined; }); + const jumpToQuestionActions = actions.filter((action) => action.objective === "jumpToQuestion"); + if (jumpToQuestionActions.length > 1) { + actionIssues.push({ + code: z.ZodIssueCode.custom, + message: `Conditional Logic: Multiple jump actions are not allowed in logic no: ${String(logicIndex + 1)} of question ${String(questionIndex + 1)}`, + path: ["questions", questionIndex, "logic"], + }); + } + const filteredActionIssues = actionIssues.filter((issue): issue is ZodIssue => issue !== undefined); return filteredActionIssues; };