mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-26 03:35:38 -05:00
feat: adds image support in inputCombobox
This commit is contained in:
+18
-20
@@ -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
|
||||
|
||||
+5
-2
@@ -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,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+95
-95
@@ -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,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+40
-12
@@ -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 => {
|
||||
|
||||
+4
-4
@@ -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",
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user