mirror of
https://github.com/formbricks/formbricks.git
synced 2026-02-04 10:30:00 -06:00
fix: comparison fixes
This commit is contained in:
@@ -157,7 +157,7 @@ export function AdvancedLogicEditorActions({
|
||||
placeholder: "Value",
|
||||
type: localSurvey.variables.find((v) => v.id === action.variableId)?.type || "text",
|
||||
}}
|
||||
groupedOptions={getActionValueOptions(action.variableId, localSurvey, questionIdx)}
|
||||
groupedOptions={getActionValueOptions(action.variableId, localSurvey)}
|
||||
onChangeValue={(val, option, fromInput) => {
|
||||
const fieldType = option?.meta?.type as TActionVariableValueType;
|
||||
|
||||
|
||||
@@ -236,24 +236,23 @@ export const getMatchValueProps = (
|
||||
|
||||
if (condition.leftOperand.type === "question") {
|
||||
if (selectedQuestion?.type === TSurveyQuestionTypeEnum.OpenText) {
|
||||
const allowedQuestions = questions.filter((question) => {
|
||||
const allowedQuestionTypes = [
|
||||
TSurveyQuestionTypeEnum.OpenText,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
TSurveyQuestionTypeEnum.Rating,
|
||||
TSurveyQuestionTypeEnum.NPS,
|
||||
];
|
||||
const allowedQuestionTypes = [TSurveyQuestionTypeEnum.OpenText];
|
||||
|
||||
if (selectedQuestion.inputType === "number") {
|
||||
allowedQuestionTypes.push(TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS);
|
||||
}
|
||||
|
||||
if (["equals", "doesNotEqual"].includes(condition.operator)) {
|
||||
if (selectedQuestion.inputType !== "number") {
|
||||
allowedQuestionTypes.push(TSurveyQuestionTypeEnum.Date);
|
||||
allowedQuestionTypes.push(
|
||||
TSurveyQuestionTypeEnum.Date,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceMulti
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (["equals", "doesNotEqual"].includes(condition.operator)) {
|
||||
allowedQuestionTypes.push(TSurveyQuestionTypeEnum.MultipleChoiceMulti);
|
||||
}
|
||||
|
||||
return allowedQuestionTypes.includes(question.type);
|
||||
});
|
||||
const allowedQuestions = questions.filter((question) => allowedQuestionTypes.includes(question.type));
|
||||
|
||||
const questionOptions = allowedQuestions.map((question) => {
|
||||
return {
|
||||
@@ -528,15 +527,16 @@ export const getMatchValueProps = (
|
||||
}
|
||||
} else if (condition.leftOperand.type === "variable") {
|
||||
if (selectedVariable?.type === "text") {
|
||||
const allowedQuestions = questions.filter((question) =>
|
||||
[
|
||||
TSurveyQuestionTypeEnum.OpenText,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
TSurveyQuestionTypeEnum.Rating,
|
||||
TSurveyQuestionTypeEnum.NPS,
|
||||
TSurveyQuestionTypeEnum.Date,
|
||||
].includes(question.type)
|
||||
);
|
||||
const allowedQuestionTypes = [
|
||||
TSurveyQuestionTypeEnum.OpenText,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
];
|
||||
|
||||
if (["equals", "doesNotEqual"].includes(condition.operator)) {
|
||||
allowedQuestionTypes.push(TSurveyQuestionTypeEnum.MultipleChoiceMulti, TSurveyQuestionTypeEnum.Date);
|
||||
}
|
||||
|
||||
const allowedQuestions = questions.filter((question) => allowedQuestionTypes.includes(question.type));
|
||||
|
||||
const questionOptions = allowedQuestions.map((question) => {
|
||||
return {
|
||||
@@ -679,16 +679,16 @@ export const getMatchValueProps = (
|
||||
};
|
||||
}
|
||||
} else if (condition.leftOperand.type === "hiddenField") {
|
||||
const allowedQuestions = questions.filter((question) =>
|
||||
[
|
||||
TSurveyQuestionTypeEnum.OpenText,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceMulti,
|
||||
TSurveyQuestionTypeEnum.Rating,
|
||||
TSurveyQuestionTypeEnum.NPS,
|
||||
TSurveyQuestionTypeEnum.Date,
|
||||
].includes(question.type)
|
||||
);
|
||||
const allowedQuestionTypes = [
|
||||
TSurveyQuestionTypeEnum.OpenText,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
];
|
||||
|
||||
if (["equals", "doesNotEqual"].includes(condition.operator)) {
|
||||
allowedQuestionTypes.push(TSurveyQuestionTypeEnum.MultipleChoiceMulti, TSurveyQuestionTypeEnum.Date);
|
||||
}
|
||||
|
||||
const allowedQuestions = questions.filter((question) => allowedQuestionTypes.includes(question.type));
|
||||
|
||||
const questionOptions = allowedQuestions.map((question) => {
|
||||
return {
|
||||
@@ -701,16 +701,18 @@ export const getMatchValueProps = (
|
||||
};
|
||||
});
|
||||
|
||||
const variableOptions = variables.map((variable) => {
|
||||
return {
|
||||
icon: variable.type === "number" ? FileDigitIcon : FileType2Icon,
|
||||
label: variable.name,
|
||||
value: variable.id,
|
||||
meta: {
|
||||
type: "variable",
|
||||
},
|
||||
};
|
||||
});
|
||||
const variableOptions = variables
|
||||
.filter((variable) => variable.type === "text")
|
||||
.map((variable) => {
|
||||
return {
|
||||
icon: FileType2Icon,
|
||||
label: variable.name,
|
||||
value: variable.id,
|
||||
meta: {
|
||||
type: "variable",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const hiddenFieldsOptions = hiddenFields.map((field) => {
|
||||
return {
|
||||
@@ -848,11 +850,7 @@ export const getActionOpeartorOptions = (variableType?: TSurveyVariable["type"])
|
||||
return [];
|
||||
};
|
||||
|
||||
export const getActionValueOptions = (
|
||||
variableId: string,
|
||||
localSurvey: TSurvey,
|
||||
currQuestionIdx: number
|
||||
): TComboboxGroupedOption[] => {
|
||||
export const getActionValueOptions = (variableId: string, localSurvey: TSurvey): TComboboxGroupedOption[] => {
|
||||
const hiddenFields = localSurvey.hiddenFields?.fieldIds || [];
|
||||
let variables = localSurvey.variables || [];
|
||||
const questions = localSurvey.questions;
|
||||
@@ -875,16 +873,14 @@ export const getActionValueOptions = (
|
||||
if (!selectedVariable) return [];
|
||||
|
||||
if (selectedVariable.type === "text") {
|
||||
const allowedQuestions = questions.filter(
|
||||
(question, idx) =>
|
||||
idx !== currQuestionIdx &&
|
||||
[
|
||||
TSurveyQuestionTypeEnum.OpenText,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
TSurveyQuestionTypeEnum.Rating,
|
||||
TSurveyQuestionTypeEnum.NPS,
|
||||
TSurveyQuestionTypeEnum.Date,
|
||||
].includes(question.type)
|
||||
const allowedQuestions = questions.filter((question) =>
|
||||
[
|
||||
TSurveyQuestionTypeEnum.OpenText,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
TSurveyQuestionTypeEnum.Rating,
|
||||
TSurveyQuestionTypeEnum.NPS,
|
||||
TSurveyQuestionTypeEnum.Date,
|
||||
].includes(question.type)
|
||||
);
|
||||
|
||||
const questionOptions = allowedQuestions.map((question) => {
|
||||
@@ -939,10 +935,8 @@ export const getActionValueOptions = (
|
||||
|
||||
return groupedOptions;
|
||||
} else if (selectedVariable.type === "number") {
|
||||
const allowedQuestions = questions.filter(
|
||||
(question, idx) =>
|
||||
idx !== currQuestionIdx &&
|
||||
[TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS].includes(question.type)
|
||||
const allowedQuestions = questions.filter((question) =>
|
||||
[TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS].includes(question.type)
|
||||
);
|
||||
|
||||
const questionOptions = allowedQuestions.map((question) => {
|
||||
|
||||
@@ -146,7 +146,7 @@ export const createGroupFromResource = (group: TConditionGroup, resourceId: stri
|
||||
conditions: [item],
|
||||
};
|
||||
group.conditions[i] = newGroup;
|
||||
group.connector = "and";
|
||||
group.connector = group.connector ?? "and";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,38 +85,23 @@ const evaluateSingleCondition = (
|
||||
|
||||
switch (condition.operator) {
|
||||
case "equals":
|
||||
// when left value is of picture selection question and right value is its option
|
||||
if (
|
||||
condition.leftOperand.type === "question" &&
|
||||
(leftField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.PictureSelection &&
|
||||
Array.isArray(leftValue) &&
|
||||
leftValue.length > 0 &&
|
||||
typeof rightValue === "string"
|
||||
) {
|
||||
return leftValue.includes(rightValue);
|
||||
}
|
||||
|
||||
// when left value is of date question and right value is string
|
||||
if (
|
||||
condition.leftOperand.type === "question" &&
|
||||
(leftField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.Date &&
|
||||
typeof leftValue === "string" &&
|
||||
typeof rightValue === "string"
|
||||
) {
|
||||
return new Date(leftValue).getTime() === new Date(rightValue).getTime();
|
||||
if (condition.leftOperand.type === "question") {
|
||||
if (
|
||||
(leftField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.Date &&
|
||||
typeof leftValue === "string" &&
|
||||
typeof rightValue === "string"
|
||||
) {
|
||||
// when left value is of date question and right value is string
|
||||
return new Date(leftValue).getTime() === new Date(rightValue).getTime();
|
||||
}
|
||||
}
|
||||
|
||||
// when left value is of openText, hiddenField, variable and right value is of multichoice
|
||||
if (condition.rightOperand?.type === "question") {
|
||||
if (
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceSingle ||
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceMulti
|
||||
) {
|
||||
if (Array.isArray(condition.rightOperand.value)) {
|
||||
return condition.rightOperand.value.includes(leftValue);
|
||||
} else {
|
||||
return leftValue === condition.rightOperand.value;
|
||||
}
|
||||
if ((rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceMulti) {
|
||||
if (Array.isArray(rightValue) && typeof leftValue === "string" && rightValue.length === 1) {
|
||||
return rightValue.includes(leftValue as string);
|
||||
} else return false;
|
||||
} else if (
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.Date &&
|
||||
typeof leftValue === "string" &&
|
||||
@@ -157,15 +142,10 @@ const evaluateSingleCondition = (
|
||||
|
||||
// when left value is of openText, hiddenField, variable and right value is of multichoice
|
||||
if (condition.rightOperand?.type === "question") {
|
||||
if (
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceSingle ||
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceMulti
|
||||
) {
|
||||
if (Array.isArray(condition.rightOperand.value)) {
|
||||
return !condition.rightOperand.value.includes(leftValue);
|
||||
} else {
|
||||
return leftValue !== condition.rightOperand.value;
|
||||
}
|
||||
if ((rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceMulti) {
|
||||
if (Array.isArray(rightValue) && typeof leftValue === "string" && rightValue.length === 1) {
|
||||
return !rightValue.includes(leftValue as string);
|
||||
} else return false;
|
||||
} else if (
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.Date &&
|
||||
typeof leftValue === "string" &&
|
||||
@@ -281,6 +261,10 @@ const getLeftOperandValue = (
|
||||
|
||||
const responseValue = data[leftOperand.value];
|
||||
|
||||
if (currentQuestion.type === "openText" && currentQuestion.inputType === "number") {
|
||||
return Number(responseValue) || 0;
|
||||
}
|
||||
|
||||
if (currentQuestion.type === "multipleChoiceSingle" || currentQuestion.type === "multipleChoiceMulti") {
|
||||
const isOthersEnabled = currentQuestion.choices.at(-1)?.id === "other";
|
||||
|
||||
@@ -357,7 +341,9 @@ const getRightOperandValue = (
|
||||
if (variable.type === "number") return Number(variableValue) || 0;
|
||||
return variableValue || "";
|
||||
case "hiddenField":
|
||||
return data[rightOperand.value];
|
||||
return !isNaN(data[rightOperand.value] as number)
|
||||
? Number(data[rightOperand.value])
|
||||
: data[rightOperand.value];
|
||||
case "static":
|
||||
return rightOperand.value;
|
||||
default:
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ScrollableContainer } from "@/components/wrappers/ScrollableContainer";
|
||||
import { replaceRecallInfo } from "@/lib/recall";
|
||||
import { useEffect } from "preact/hooks";
|
||||
import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
|
||||
import { TResponseData } from "@formbricks/types/responses";
|
||||
import { TResponseData, TResponseVariables } from "@formbricks/types/responses";
|
||||
import { TSurvey, TSurveyEndScreenCard, TSurveyRedirectUrlCard } from "@formbricks/types/surveys/types";
|
||||
|
||||
interface EndingCardProps {
|
||||
@@ -19,6 +19,7 @@ interface EndingCardProps {
|
||||
isCurrent: boolean;
|
||||
languageCode: string;
|
||||
responseData: TResponseData;
|
||||
variablesData: TResponseVariables;
|
||||
}
|
||||
|
||||
export const EndingCard = ({
|
||||
@@ -30,6 +31,7 @@ export const EndingCard = ({
|
||||
isCurrent,
|
||||
languageCode,
|
||||
responseData,
|
||||
variablesData,
|
||||
}: EndingCardProps) => {
|
||||
const media =
|
||||
endingCard.type === "endScreen" && (endingCard.imageUrl || endingCard.videoUrl) ? (
|
||||
@@ -99,7 +101,7 @@ export const EndingCard = ({
|
||||
? replaceRecallInfo(
|
||||
getLocalizedValue(endingCard.headline, languageCode),
|
||||
responseData,
|
||||
survey.variables
|
||||
variablesData
|
||||
)
|
||||
: "Respondants will not see this card"
|
||||
}
|
||||
@@ -111,7 +113,7 @@ export const EndingCard = ({
|
||||
? replaceRecallInfo(
|
||||
getLocalizedValue(endingCard.subheader, languageCode),
|
||||
responseData,
|
||||
survey.variables
|
||||
variablesData
|
||||
)
|
||||
: "They will be forwarded immediately"
|
||||
}
|
||||
@@ -123,7 +125,7 @@ export const EndingCard = ({
|
||||
buttonLabel={replaceRecallInfo(
|
||||
getLocalizedValue(endingCard.buttonLabel, languageCode),
|
||||
responseData,
|
||||
survey.variables
|
||||
variablesData
|
||||
)}
|
||||
isLastQuestion={false}
|
||||
focus={autoFocusEnabled}
|
||||
|
||||
@@ -9,7 +9,7 @@ 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 { parseRecallInformation, replaceRecallInfo } from "@/lib/recall";
|
||||
import { parseRecallInformation } from "@/lib/recall";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
import { SurveyBaseProps } from "@formbricks/types/formbricks-surveys";
|
||||
@@ -341,9 +341,9 @@ export const Survey = ({
|
||||
languageCode={selectedLanguage}
|
||||
responseCount={responseCount}
|
||||
autoFocusEnabled={autoFocusEnabled}
|
||||
replaceRecallInfo={replaceRecallInfo}
|
||||
isCurrent={offset === 0}
|
||||
responseData={responseData}
|
||||
variablesData={currentVariables}
|
||||
/>
|
||||
);
|
||||
} else if (questionIdx >= localSurvey.questions.length) {
|
||||
@@ -361,6 +361,7 @@ export const Survey = ({
|
||||
languageCode={selectedLanguage}
|
||||
isResponseSendingFinished={isResponseSendingFinished}
|
||||
responseData={responseData}
|
||||
variablesData={currentVariables}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -371,12 +372,7 @@ export const Survey = ({
|
||||
<QuestionConditional
|
||||
key={question.id}
|
||||
surveyId={localSurvey.id}
|
||||
question={parseRecallInformation(
|
||||
question,
|
||||
selectedLanguage,
|
||||
responseData,
|
||||
localSurvey.variables
|
||||
)}
|
||||
question={parseRecallInformation(question, selectedLanguage, responseData, currentVariables)}
|
||||
value={responseData[question.id]}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { SubmitButton } from "@/components/buttons/SubmitButton";
|
||||
import { ScrollableContainer } from "@/components/wrappers/ScrollableContainer";
|
||||
import { replaceRecallInfo } from "@/lib/recall";
|
||||
import { calculateElementIdx } from "@/lib/utils";
|
||||
import { useEffect } from "preact/hooks";
|
||||
import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
|
||||
import { TResponseData, TResponseTtc } from "@formbricks/types/responses";
|
||||
import { TI18nString, TSurvey, TSurveyVariables } from "@formbricks/types/surveys/types";
|
||||
import { TResponseData, TResponseTtc, TResponseVariables } from "@formbricks/types/responses";
|
||||
import { TI18nString, TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { Headline } from "./Headline";
|
||||
import { HtmlBody } from "./HtmlBody";
|
||||
|
||||
@@ -18,9 +19,9 @@ interface WelcomeCardProps {
|
||||
languageCode: string;
|
||||
responseCount?: number;
|
||||
autoFocusEnabled: boolean;
|
||||
replaceRecallInfo: (text: string, responseData: TResponseData, variables: TSurveyVariables) => string;
|
||||
isCurrent: boolean;
|
||||
responseData: TResponseData;
|
||||
variablesData: TResponseVariables;
|
||||
}
|
||||
|
||||
const TimerIcon = () => {
|
||||
@@ -70,9 +71,9 @@ export const WelcomeCard = ({
|
||||
survey,
|
||||
responseCount,
|
||||
autoFocusEnabled,
|
||||
replaceRecallInfo,
|
||||
isCurrent,
|
||||
responseData,
|
||||
variablesData,
|
||||
}: WelcomeCardProps) => {
|
||||
const calculateTimeToComplete = () => {
|
||||
let idx = calculateElementIdx(survey, 0);
|
||||
@@ -145,16 +146,12 @@ export const WelcomeCard = ({
|
||||
headline={replaceRecallInfo(
|
||||
getLocalizedValue(headline, languageCode),
|
||||
responseData,
|
||||
survey.variables
|
||||
variablesData
|
||||
)}
|
||||
questionId="welcomeCard"
|
||||
/>
|
||||
<HtmlBody
|
||||
htmlString={replaceRecallInfo(
|
||||
getLocalizedValue(html, languageCode),
|
||||
responseData,
|
||||
survey.variables
|
||||
)}
|
||||
htmlString={replaceRecallInfo(getLocalizedValue(html, languageCode), responseData, variablesData)}
|
||||
questionId="welcomeCard"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -85,38 +85,23 @@ const evaluateSingleCondition = (
|
||||
|
||||
switch (condition.operator) {
|
||||
case "equals":
|
||||
// when left value is of picture selection question and right value is its option
|
||||
if (
|
||||
condition.leftOperand.type === "question" &&
|
||||
(leftField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.PictureSelection &&
|
||||
Array.isArray(leftValue) &&
|
||||
leftValue.length > 0 &&
|
||||
typeof rightValue === "string"
|
||||
) {
|
||||
return leftValue.includes(rightValue);
|
||||
}
|
||||
|
||||
// when left value is of date question and right value is string
|
||||
if (
|
||||
condition.leftOperand.type === "question" &&
|
||||
(leftField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.Date &&
|
||||
typeof leftValue === "string" &&
|
||||
typeof rightValue === "string"
|
||||
) {
|
||||
return new Date(leftValue).getTime() === new Date(rightValue).getTime();
|
||||
if (condition.leftOperand.type === "question") {
|
||||
if (
|
||||
(leftField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.Date &&
|
||||
typeof leftValue === "string" &&
|
||||
typeof rightValue === "string"
|
||||
) {
|
||||
// when left value is of date question and right value is string
|
||||
return new Date(leftValue).getTime() === new Date(rightValue).getTime();
|
||||
}
|
||||
}
|
||||
|
||||
// when left value is of openText, hiddenField, variable and right value is of multichoice
|
||||
if (condition.rightOperand?.type === "question") {
|
||||
if (
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceSingle ||
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceMulti
|
||||
) {
|
||||
if (Array.isArray(condition.rightOperand.value)) {
|
||||
return condition.rightOperand.value.includes(leftValue);
|
||||
} else {
|
||||
return leftValue === condition.rightOperand.value;
|
||||
}
|
||||
if ((rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceMulti) {
|
||||
if (Array.isArray(rightValue) && typeof leftValue === "string" && rightValue.length === 1) {
|
||||
return rightValue.includes(leftValue as string);
|
||||
} else return false;
|
||||
} else if (
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.Date &&
|
||||
typeof leftValue === "string" &&
|
||||
@@ -157,15 +142,10 @@ const evaluateSingleCondition = (
|
||||
|
||||
// when left value is of openText, hiddenField, variable and right value is of multichoice
|
||||
if (condition.rightOperand?.type === "question") {
|
||||
if (
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceSingle ||
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceMulti
|
||||
) {
|
||||
if (Array.isArray(condition.rightOperand.value)) {
|
||||
return !condition.rightOperand.value.includes(leftValue);
|
||||
} else {
|
||||
return leftValue !== condition.rightOperand.value;
|
||||
}
|
||||
if ((rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.MultipleChoiceMulti) {
|
||||
if (Array.isArray(rightValue) && typeof leftValue === "string" && rightValue.length === 1) {
|
||||
return !rightValue.includes(leftValue as string);
|
||||
} else return false;
|
||||
} else if (
|
||||
(rightField as TSurveyQuestion).type === TSurveyQuestionTypeEnum.Date &&
|
||||
typeof leftValue === "string" &&
|
||||
@@ -281,6 +261,10 @@ const getLeftOperandValue = (
|
||||
|
||||
const responseValue = data[leftOperand.value];
|
||||
|
||||
if (currentQuestion.type === "openText" && currentQuestion.inputType === "number") {
|
||||
return Number(responseValue) || 0;
|
||||
}
|
||||
|
||||
if (currentQuestion.type === "multipleChoiceSingle" || currentQuestion.type === "multipleChoiceMulti") {
|
||||
const isOthersEnabled = currentQuestion.choices.at(-1)?.id === "other";
|
||||
|
||||
@@ -357,7 +341,9 @@ const getRightOperandValue = (
|
||||
if (variable.type === "number") return Number(variableValue) || 0;
|
||||
return variableValue || "";
|
||||
case "hiddenField":
|
||||
return data[rightOperand.value];
|
||||
return !isNaN(data[rightOperand.value] as number)
|
||||
? Number(data[rightOperand.value])
|
||||
: data[rightOperand.value];
|
||||
case "static":
|
||||
return rightOperand.value;
|
||||
default:
|
||||
|
||||
@@ -2,13 +2,13 @@ import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
|
||||
import { structuredClone } from "@formbricks/lib/pollyfills/structuredClone";
|
||||
import { formatDateWithOrdinal, isValidDateString } from "@formbricks/lib/utils/datetime";
|
||||
import { extractFallbackValue, extractId, extractRecallInfo } from "@formbricks/lib/utils/recall";
|
||||
import { TResponseData } from "@formbricks/types/responses";
|
||||
import { TSurveyQuestion, TSurveyVariables } from "@formbricks/types/surveys/types";
|
||||
import { TResponseData, TResponseVariables } from "@formbricks/types/responses";
|
||||
import { TSurveyQuestion } from "@formbricks/types/surveys/types";
|
||||
|
||||
export const replaceRecallInfo = (
|
||||
text: string,
|
||||
responseData: TResponseData,
|
||||
variables: TSurveyVariables
|
||||
variables: TResponseVariables
|
||||
): string => {
|
||||
let modifiedText = text;
|
||||
|
||||
@@ -23,9 +23,8 @@ export const replaceRecallInfo = (
|
||||
let value: string | null = null;
|
||||
|
||||
// Fetching value from variables based on recallItemId
|
||||
if (variables.length) {
|
||||
const variable = variables.find((variable) => variable.id === recallItemId);
|
||||
value = variable?.value?.toString() ?? fallback;
|
||||
if (variables[recallItemId]) {
|
||||
value = (variables[recallItemId] as string) ?? fallback;
|
||||
}
|
||||
|
||||
// Fetching value from responseData or attributes based on recallItemId
|
||||
@@ -53,7 +52,7 @@ export const parseRecallInformation = (
|
||||
question: TSurveyQuestion,
|
||||
languageCode: string,
|
||||
responseData: TResponseData,
|
||||
variables: TSurveyVariables
|
||||
variables: TResponseVariables
|
||||
) => {
|
||||
const modifiedQuestion = structuredClone(question);
|
||||
if (question.headline && question.headline[languageCode]?.includes("recall:")) {
|
||||
|
||||
@@ -106,14 +106,19 @@ export const ZSingleCondition = z
|
||||
if (val.rightOperand === undefined) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `Conditional Logic: rightOperand is required for operator "${val.operator}"`,
|
||||
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: rightOperand should not be present for operator "${val.operator}"`,
|
||||
message: `Conditional Logic: right operand should not be present for operator "${val.operator}"`,
|
||||
path: ["rightOperand"],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1159,18 +1159,28 @@ const validateConditions = (
|
||||
path: ["questions", questionIndex, "logic", logicIndex, "conditions"],
|
||||
});
|
||||
} else {
|
||||
const validQuestionTypes = [
|
||||
TSurveyQuestionTypeEnum.OpenText,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceMulti,
|
||||
TSurveyQuestionTypeEnum.Rating,
|
||||
TSurveyQuestionTypeEnum.NPS,
|
||||
TSurveyQuestionTypeEnum.Date,
|
||||
];
|
||||
if (!validQuestionTypes.includes(question.type)) {
|
||||
const validQuestionTypes = [TSurveyQuestionTypeEnum.OpenText];
|
||||
|
||||
if (question.inputType === "number") {
|
||||
validQuestionTypes.push(...[TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS]);
|
||||
}
|
||||
|
||||
if (["equals", "doesNotEqual"].includes(condition.operator)) {
|
||||
if (question.inputType !== "number") {
|
||||
validQuestionTypes.push(
|
||||
...[
|
||||
TSurveyQuestionTypeEnum.Date,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceMulti,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!validQuestionTypes.includes(ques.type)) {
|
||||
issues.push({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `Conditional Logic: Invalid question type "${question.type}" for right operand in logic no: ${String(logicIndex + 1)} of question ${String(questionIndex + 1)}`,
|
||||
message: `Conditional Logic: Invalid question type "${ques.type}" for right operand in logic no: ${String(logicIndex + 1)} of question ${String(questionIndex + 1)}`,
|
||||
path: ["questions", questionIndex, "logic", logicIndex, "conditions"],
|
||||
});
|
||||
}
|
||||
@@ -1467,11 +1477,15 @@ const validateConditions = (
|
||||
const validQuestionTypes = [
|
||||
TSurveyQuestionTypeEnum.OpenText,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
TSurveyQuestionTypeEnum.Rating,
|
||||
TSurveyQuestionTypeEnum.NPS,
|
||||
TSurveyQuestionTypeEnum.Date,
|
||||
];
|
||||
|
||||
if (["equals", "doesNotEqual"].includes(operator)) {
|
||||
validQuestionTypes.push(
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceMulti,
|
||||
TSurveyQuestionTypeEnum.Date
|
||||
);
|
||||
}
|
||||
|
||||
if (!validQuestionTypes.includes(question.type)) {
|
||||
issues.push({
|
||||
code: z.ZodIssueCode.custom,
|
||||
@@ -1547,12 +1561,15 @@ const validateConditions = (
|
||||
const validQuestionTypes = [
|
||||
TSurveyQuestionTypeEnum.OpenText,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceSingle,
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceMulti,
|
||||
TSurveyQuestionTypeEnum.Rating,
|
||||
TSurveyQuestionTypeEnum.NPS,
|
||||
TSurveyQuestionTypeEnum.Date,
|
||||
];
|
||||
|
||||
if (["equals", "doesNotEqual"].includes(condition.operator)) {
|
||||
validQuestionTypes.push(
|
||||
TSurveyQuestionTypeEnum.MultipleChoiceMulti,
|
||||
TSurveyQuestionTypeEnum.Date
|
||||
);
|
||||
}
|
||||
|
||||
if (!validQuestionTypes.includes(question.type)) {
|
||||
issues.push({
|
||||
code: z.ZodIssueCode.custom,
|
||||
@@ -1571,6 +1588,12 @@ const validateConditions = (
|
||||
message: `Conditional Logic: Variable ID ${variableId} does not exist in logic no: ${String(logicIndex + 1)} of question ${String(questionIndex + 1)}`,
|
||||
path: ["questions", questionIndex, "logic", logicIndex, "conditions"],
|
||||
});
|
||||
} else if (variable.type !== "text") {
|
||||
issues.push({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `Conditional Logic: Variable type should be text in logic no: ${String(logicIndex + 1)} of question ${String(questionIndex + 1)}`,
|
||||
path: ["questions", questionIndex, "logic", logicIndex, "conditions"],
|
||||
});
|
||||
}
|
||||
} else if (rightOperand?.type === "hiddenField") {
|
||||
const fieldId = rightOperand.value;
|
||||
|
||||
Reference in New Issue
Block a user