+
+ {render({
+ value,
+ onChange: handleChange,
+ children:
+ enabledLanguages.length > 1 ? (
+
+ ) : null,
+ })}
+
+
+ {enabledLanguages.length > 1 && (
+ <>
+ {usedLanguageCode !== "default" && value && typeof value["default"] !== "undefined" && (
+
+ {t("environments.project.languages.translate")}:{" "}
+ {contactAttributeKeys
+ ? recallToHeadline(value, localSurvey, false, "default", contactAttributeKeys)["default"]
+ : value.default}
+
+ )}
+
+ {usedLanguageCode === "default" && localSurvey.languages?.length > 1 && isTranslationIncomplete && (
+
+ {t("environments.project.languages.incomplete_translations")}
+
+ )}
+ >
+ )}
+
+ );
+};
diff --git a/apps/web/modules/surveys/components/QuestionFormInput/components/RecallItemSelect.tsx b/apps/web/modules/surveys/components/QuestionFormInput/components/RecallItemSelect.tsx
index a3588c8ff4..970097938a 100644
--- a/apps/web/modules/surveys/components/QuestionFormInput/components/RecallItemSelect.tsx
+++ b/apps/web/modules/surveys/components/QuestionFormInput/components/RecallItemSelect.tsx
@@ -7,6 +7,7 @@ import { Input } from "@/modules/ui/components/input";
import { DropdownMenuItem } from "@radix-ui/react-dropdown-menu";
import {
CalendarDaysIcon,
+ ContactIcon,
EyeOffIcon,
FileDigitIcon,
FileTextIcon,
@@ -40,6 +41,7 @@ const questionIconMapping = {
date: CalendarDaysIcon,
cal: PhoneIcon,
address: HomeIcon,
+ contactInfo: ContactIcon,
ranking: ListOrderedIcon,
};
@@ -92,20 +94,20 @@ export const RecallItemSelect = ({
}));
}
return [];
- }, [localSurvey.hiddenFields]);
+ }, [localSurvey.hiddenFields, recallItemIds]);
- const attributeClassRecallItems = useMemo(() => {
+ const contactAttributekeysRecallItems = useMemo(() => {
if (localSurvey.type !== "app") return [];
return contactAttributeKeys
.filter((attributeKey) => !recallItemIds.includes(attributeKey.key.replaceAll(" ", "nbsp")))
.map((attributeKey) => {
return {
id: attributeKey.key.replaceAll(" ", "nbsp"),
- label: attributeKey.name ?? attributeKey.key,
+ label: attributeKey.key,
type: "attributeClass" as const,
};
});
- }, [contactAttributeKeys]);
+ }, [contactAttributeKeys, localSurvey.type, recallItemIds]);
const variableRecallItems = useMemo(() => {
if (localSurvey.variables.length) {
@@ -146,7 +148,7 @@ export const RecallItemSelect = ({
return [
...surveyQuestionRecallItems,
...hiddenFieldRecallItems,
- ...attributeClassRecallItems,
+ ...contactAttributekeysRecallItems,
...variableRecallItems,
].filter((recallItems) => {
if (searchValue.trim() === "") return true;
@@ -157,7 +159,7 @@ export const RecallItemSelect = ({
}, [
surveyQuestionRecallItems,
hiddenFieldRecallItems,
- attributeClassRecallItems,
+ contactAttributekeysRecallItems,
variableRecallItems,
searchValue,
]);
diff --git a/apps/web/modules/surveys/components/QuestionFormInput/components/RecallWrapper.tsx b/apps/web/modules/surveys/components/QuestionFormInput/components/RecallWrapper.tsx
new file mode 100644
index 0000000000..8222c9d2d4
--- /dev/null
+++ b/apps/web/modules/surveys/components/QuestionFormInput/components/RecallWrapper.tsx
@@ -0,0 +1,309 @@
+import { FallbackInput } from "@/modules/surveys/components/QuestionFormInput/components/FallbackInput";
+import { RecallItemSelect } from "@/modules/surveys/components/QuestionFormInput/components/RecallItemSelect";
+import { Button } from "@/modules/ui/components/button";
+import { PencilIcon } from "lucide-react";
+import { useTranslations } from "next-intl";
+import React, { ReactNode, useCallback, useEffect, useRef, useState } from "react";
+import { toast } from "react-hot-toast";
+import { structuredClone } from "@formbricks/lib/pollyfills/structuredClone";
+import {
+ extractId,
+ extractRecallInfo,
+ findRecallInfoById,
+ getFallbackValues,
+ getRecallItems,
+ headlineToRecall,
+ recallToHeadline,
+ replaceRecallInfoWithUnderline,
+} from "@formbricks/lib/utils/recall";
+import { TContactAttributeKey } from "@formbricks/types/contact-attribute-key";
+import { TSurvey, TSurveyRecallItem } from "@formbricks/types/surveys/types";
+
+interface RecallWrapperRenderProps {
+ value: string;
+ onChange: (val: string) => void;
+ highlightedJSX: JSX.Element[];
+ children: ReactNode;
+ isRecallSelectVisible: boolean;
+}
+
+interface RecallWrapperProps {
+ value: string;
+ onChange: (val: string, recallItems: TSurveyRecallItem[], fallbacks: { [id: string]: string }) => void;
+ localSurvey: TSurvey;
+ questionId: string;
+ contactAttributeKeys: TContactAttributeKey[];
+ render: (props: RecallWrapperRenderProps) => React.ReactNode;
+ usedLanguageCode: string;
+ isRecallAllowed: boolean;
+ onAddFallback: (fallback: string) => void;
+}
+
+export const RecallWrapper = ({
+ value,
+ onChange,
+ localSurvey,
+ questionId,
+ contactAttributeKeys,
+ render,
+ usedLanguageCode,
+ isRecallAllowed,
+ onAddFallback,
+}: RecallWrapperProps) => {
+ const t = useTranslations();
+ const [showRecallItemSelect, setShowRecallItemSelect] = useState(false);
+ const [showFallbackInput, setShowFallbackInput] = useState(false);
+ const [recallItems, setRecallItems] = useState