diff --git a/apps/demo/pages/app/index.tsx b/apps/demo/pages/app/index.tsx
index 772da37b44..7dd858d363 100644
--- a/apps/demo/pages/app/index.tsx
+++ b/apps/demo/pages/app/index.tsx
@@ -34,7 +34,12 @@ export default function AppPage({}) {
if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) {
const isUserId = window.location.href.includes("userId=true");
- const attributes = isUserId ? { "Init Attribute 1": "eight", "Init Attribute 2": "two" } : undefined;
+ const defaultAttributes = {
+ language: "gu",
+ };
+ const userInitAttributes = { "Init Attribute 1": "eight", "Init Attribute 2": "two" };
+
+ const attributes = isUserId ? { ...defaultAttributes, ...userInitAttributes } : defaultAttributes;
const userId = isUserId ? "THIS-IS-A-VERY-LONG-USER-ID-FOR-TESTING" : undefined;
formbricks.init({
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
diff --git a/apps/formbricks-com/app/docs/self-hosting/enterprise/page.mdx b/apps/formbricks-com/app/docs/self-hosting/enterprise/page.mdx
index 83d993fd74..4e0a9c5411 100644
--- a/apps/formbricks-com/app/docs/self-hosting/enterprise/page.mdx
+++ b/apps/formbricks-com/app/docs/self-hosting/enterprise/page.mdx
@@ -1,7 +1,6 @@
export const metadata = {
title: "Enterprise License to unlock advanced functionality",
- description:
- "Request a self-hosting licenses to unlock advanced enterprise functionality",
+ description: "Request a enterprise licenses to unlock advanced enterprise functionality",
};
#### Self-Hosting
@@ -14,13 +13,17 @@ Additional to the AGPL licensed Formbricks core, the Formbricks repository conta
**Please note:** Sooner than later we will introduce a enterprise license pricing. For a free beta key, fill out this form:
-
+
+ style={{ position: "absolute", left: 0, top: 0, width: "100%", height: "100%", border: 0 }}>
-
**Can’t figure it out?**: [Join our Discord!](https://formbricks.com/discord)
diff --git a/apps/formbricks-com/components/dummyUI/CTAQuestion.tsx b/apps/formbricks-com/components/dummyUI/CTAQuestion.tsx
index 2d7817e0fc..45f59082e0 100644
--- a/apps/formbricks-com/components/dummyUI/CTAQuestion.tsx
+++ b/apps/formbricks-com/components/dummyUI/CTAQuestion.tsx
@@ -1,7 +1,6 @@
-import { TSurveyCTAQuestion } from "@formbricks/types/surveys";
-
import Headline from "./Headline";
import HtmlBody from "./HtmlBody";
+import { TSurveyCTAQuestion } from "./types";
interface CTAQuestionProps {
question: TSurveyCTAQuestion;
diff --git a/apps/formbricks-com/components/dummyUI/DemoPreview.tsx b/apps/formbricks-com/components/dummyUI/DemoPreview.tsx
index bf2c6e08ec..91962b52fe 100644
--- a/apps/formbricks-com/components/dummyUI/DemoPreview.tsx
+++ b/apps/formbricks-com/components/dummyUI/DemoPreview.tsx
@@ -2,10 +2,9 @@
import React, { useEffect, useState } from "react";
-import { TTemplate } from "@formbricks/types/templates";
-
import PreviewSurvey from "./PreviewSurvey";
import { findTemplateByName } from "./templates";
+import { TTemplate } from "./types";
interface DemoPreviewProps {
template: string;
diff --git a/apps/formbricks-com/components/dummyUI/DemoView.tsx b/apps/formbricks-com/components/dummyUI/DemoView.tsx
index 7427269719..ed97a55367 100644
--- a/apps/formbricks-com/components/dummyUI/DemoView.tsx
+++ b/apps/formbricks-com/components/dummyUI/DemoView.tsx
@@ -1,10 +1,9 @@
import { useEffect, useState } from "react";
-import { TTemplate } from "@formbricks/types/templates";
-
import PreviewSurvey from "./PreviewSurvey";
import TemplateList from "./TemplateList";
import { templates } from "./templates";
+import { TTemplate } from "./types";
export default function SurveyTemplatesPage({}) {
const [activeTemplate, setActiveTemplate] = useState
(null);
diff --git a/apps/formbricks-com/components/dummyUI/MultipleChoiceMultiQuestion.tsx b/apps/formbricks-com/components/dummyUI/MultipleChoiceMultiQuestion.tsx
index 806627ac24..c4765f9d3c 100644
--- a/apps/formbricks-com/components/dummyUI/MultipleChoiceMultiQuestion.tsx
+++ b/apps/formbricks-com/components/dummyUI/MultipleChoiceMultiQuestion.tsx
@@ -1,10 +1,10 @@
import { useEffect, useState } from "react";
import { cn } from "@formbricks/lib/cn";
-import { TSurveyMultipleChoiceMultiQuestion } from "@formbricks/types/surveys";
import Headline from "./Headline";
import Subheader from "./Subheader";
+import { TSurveyMultipleChoiceMultiQuestion } from "./types";
interface MultipleChoiceMultiProps {
question: TSurveyMultipleChoiceMultiQuestion;
diff --git a/apps/formbricks-com/components/dummyUI/MultipleChoiceSingleQuestion.tsx b/apps/formbricks-com/components/dummyUI/MultipleChoiceSingleQuestion.tsx
index 1ea0112b93..cf6bdad352 100644
--- a/apps/formbricks-com/components/dummyUI/MultipleChoiceSingleQuestion.tsx
+++ b/apps/formbricks-com/components/dummyUI/MultipleChoiceSingleQuestion.tsx
@@ -1,10 +1,10 @@
import { useState } from "react";
import { cn } from "@formbricks/lib/cn";
-import { TSurveyMultipleChoiceSingleQuestion } from "@formbricks/types/surveys";
import Headline from "./Headline";
import Subheader from "./Subheader";
+import { TSurveyMultipleChoiceSingleQuestion } from "./types";
interface MultipleChoiceSingleProps {
question: TSurveyMultipleChoiceSingleQuestion;
@@ -20,6 +20,7 @@ export default function MultipleChoiceSingleQuestion({
brandColor,
}: MultipleChoiceSingleProps) {
const [selectedChoice, setSelectedChoice] = useState(null);
+
return (
+
+
Language
+
+ {person.attributes.language ? (
+ {person.attributes.language}
+ ) : (
+ Not provided
+ )}
+
+
User Id
@@ -43,7 +53,7 @@ export default async function AttributesSection({ personId }: { personId: string
{Object.entries(person.attributes)
- .filter(([key, _]) => key !== "email" && key !== "userId")
+ .filter(([key, _]) => key !== "email" && key !== "userId" && key !== "language")
.map(([key, value]) => (
{capitalizeFirstLetter(key.toString())}
diff --git a/apps/web/app/(app)/environments/[environmentId]/(peopleAndSegments)/people/[personId]/components/ResponsesFeed.tsx b/apps/web/app/(app)/environments/[environmentId]/(peopleAndSegments)/people/[personId]/components/ResponsesFeed.tsx
index 1755adeaba..84b0174fda 100644
--- a/apps/web/app/(app)/environments/[environmentId]/(peopleAndSegments)/people/[personId]/components/ResponsesFeed.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/(peopleAndSegments)/people/[personId]/components/ResponsesFeed.tsx
@@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
import { useMembershipRole } from "@formbricks/lib/membership/hooks/useMembershipRole";
import { getAccessFlags } from "@formbricks/lib/membership/utils";
+import { checkForRecallInHeadline } from "@formbricks/lib/utils/recall";
import { TEnvironment } from "@formbricks/types/environment";
import { TResponse } from "@formbricks/types/responses";
import { TSurvey } from "@formbricks/types/surveys";
@@ -92,7 +93,7 @@ const ResponseSurveyCard = ({
{survey && (
;
}
+ const isMultiLanguageAllowed = getMultiLanguagePermission(team);
+
const [products, environments] = await Promise.all([
getProducts(team.id),
getEnvironments(environment.productId),
@@ -46,6 +48,7 @@ export default async function EnvironmentsNavbar({ environmentId, session }: Env
isFormbricksCloud={IS_FORMBRICKS_CLOUD}
webAppUrl={WEBAPP_URL}
membershipRole={currentUserMembership?.role}
+ isMultiLanguageAllowed={isMultiLanguageAllowed}
/>
);
}
diff --git a/apps/web/app/(app)/environments/[environmentId]/components/Navigation.tsx b/apps/web/app/(app)/environments/[environmentId]/components/Navigation.tsx
index 41953a4ad6..1a2186f784 100644
--- a/apps/web/app/(app)/environments/[environmentId]/components/Navigation.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/components/Navigation.tsx
@@ -10,6 +10,7 @@ import {
CreditCardIcon,
FileCheckIcon,
HeartIcon,
+ LanguagesIcon,
LinkIcon,
LogOutIcon,
MailIcon,
@@ -69,6 +70,7 @@ interface NavigationProps {
isFormbricksCloud: boolean;
webAppUrl: string;
membershipRole?: TMembershipRole;
+ isMultiLanguageAllowed: boolean;
}
export default function Navigation({
@@ -81,6 +83,7 @@ export default function Navigation({
isFormbricksCloud,
webAppUrl,
membershipRole,
+ isMultiLanguageAllowed,
}: NavigationProps) {
const router = useRouter();
const pathname = usePathname();
@@ -166,6 +169,12 @@ export default function Navigation({
href: `/environments/${environment.id}/settings/lookandfeel`,
hidden: isViewer,
},
+ {
+ icon: LanguagesIcon,
+ label: "Survey Languages",
+ href: `/environments/${environment.id}/settings/language`,
+ hidden: !isMultiLanguageAllowed,
+ },
],
},
{
diff --git a/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/components/AddIntegrationModal.tsx b/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/components/AddIntegrationModal.tsx
index d95666af73..879d7d2942 100644
--- a/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/components/AddIntegrationModal.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/components/AddIntegrationModal.tsx
@@ -8,6 +8,7 @@ import { useEffect, useState } from "react";
import { Control, Controller, UseFormSetValue, useForm } from "react-hook-form";
import { toast } from "react-hot-toast";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { checkForRecallInHeadline } from "@formbricks/lib/utils/recall";
import { TIntegrationItem } from "@formbricks/types/integration";
import {
@@ -334,7 +335,7 @@ export default function AddIntegrationModal(props: AddIntegrationModalProps) {
- {checkForRecallInHeadline(selectedSurvey)?.questions.map((question) => (
+ {checkForRecallInHeadline(selectedSurvey, "default")?.questions.map((question) => (
value !== question.id));
}}
/>
- {question.headline}
+ {getLocalizedValue(question.headline, "default")}
)}
diff --git a/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/page.tsx b/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/page.tsx
index 3c967f772c..af93fad1f6 100644
--- a/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/page.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/page.tsx
@@ -4,6 +4,7 @@ import { getAirtableTables } from "@formbricks/lib/airtable/service";
import { AIRTABLE_CLIENT_ID, WEBAPP_URL } from "@formbricks/lib/constants";
import { getEnvironment } from "@formbricks/lib/environment/service";
import { getIntegrations } from "@formbricks/lib/integration/service";
+import { getProductByEnvironmentId } from "@formbricks/lib/product/service";
import { getSurveys } from "@formbricks/lib/survey/service";
import { TIntegrationItem } from "@formbricks/types/integration";
import { TIntegrationAirtable } from "@formbricks/types/integration/airtable";
@@ -19,6 +20,10 @@ export default async function Airtable({ params }) {
if (!environment) {
throw new Error("Environment not found");
}
+ const product = await getProductByEnvironmentId(params.environmentId);
+ if (!product) {
+ throw new Error("Product not found");
+ }
const airtableIntegration: TIntegrationAirtable | undefined = integrations?.find(
(integration): integration is TIntegrationAirtable => integration.type === "airtable"
diff --git a/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/components/AddIntegrationModal.tsx b/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/components/AddIntegrationModal.tsx
index 6ad6dc8e91..706370af26 100644
--- a/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/components/AddIntegrationModal.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/components/AddIntegrationModal.tsx
@@ -6,6 +6,7 @@ import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import toast from "react-hot-toast";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { checkForRecallInHeadline } from "@formbricks/lib/utils/recall";
import { TIntegrationItem } from "@formbricks/types/integration";
import {
@@ -274,7 +275,7 @@ export default function AddIntegrationModal({
- {checkForRecallInHeadline(selectedSurvey)?.questions.map((question) => (
+ {checkForRecallInHeadline(selectedSurvey, "default")?.questions.map((question) => (
))}
diff --git a/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/page.tsx b/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/page.tsx
index e7c1097eb2..b4ce204274 100644
--- a/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/page.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/page.tsx
@@ -9,6 +9,7 @@ import {
import { getEnvironment } from "@formbricks/lib/environment/service";
import { getSpreadSheets } from "@formbricks/lib/googleSheet/service";
import { getIntegrations } from "@formbricks/lib/integration/service";
+import { getProductByEnvironmentId } from "@formbricks/lib/product/service";
import { getSurveys } from "@formbricks/lib/survey/service";
import { TIntegrationItem } from "@formbricks/types/integration";
import { TIntegrationGoogleSheets } from "@formbricks/types/integration/googleSheet";
@@ -24,6 +25,10 @@ export default async function GoogleSheet({ params }) {
if (!environment) {
throw new Error("Environment not found");
}
+ const product = await getProductByEnvironmentId(params.environmentId);
+ if (!product) {
+ throw new Error("Product not found");
+ }
const googleSheetIntegration: TIntegrationGoogleSheets | undefined = integrations?.find(
(integration): integration is TIntegrationGoogleSheets => integration.type === "googleSheets"
diff --git a/apps/web/app/(app)/environments/[environmentId]/integrations/notion/components/AddIntegrationModal.tsx b/apps/web/app/(app)/environments/[environmentId]/integrations/notion/components/AddIntegrationModal.tsx
index 57cc1815c3..2b071610d0 100644
--- a/apps/web/app/(app)/environments/[environmentId]/integrations/notion/components/AddIntegrationModal.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/integrations/notion/components/AddIntegrationModal.tsx
@@ -107,7 +107,7 @@ export default function AddIntegrationModal({
const questionItems = useMemo(() => {
const questions = selectedSurvey
- ? checkForRecallInHeadline(selectedSurvey)?.questions.map((q) => ({
+ ? checkForRecallInHeadline(selectedSurvey, "default")?.questions.map((q) => ({
id: q.id,
name: q.headline,
type: q.type,
@@ -226,7 +226,7 @@ export default function AddIntegrationModal({
return questionItems.filter((q) => !selectedQuestionIds.includes(q.id));
};
- const createCopy = (item) => JSON.parse(JSON.stringify(item));
+ const createCopy = (item) => structuredClone(item);
const MappingRow = ({ idx }: { idx: number }) => {
const filteredQuestionItems = getFilteredQuestionItems(idx);
diff --git a/apps/web/app/(app)/environments/[environmentId]/layout.tsx b/apps/web/app/(app)/environments/[environmentId]/layout.tsx
index ad7f22a55c..3f1b8cfd58 100644
--- a/apps/web/app/(app)/environments/[environmentId]/layout.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/layout.tsx
@@ -4,7 +4,6 @@ import { getServerSession } from "next-auth";
import { redirect } from "next/navigation";
import { authOptions } from "@formbricks/lib/authOptions";
-import { IS_FORMBRICKS_CLOUD } from "@formbricks/lib/constants";
import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth";
import { getTeamByEnvironmentId } from "@formbricks/lib/team/service";
import { AuthorizationError } from "@formbricks/types/errors";
@@ -42,11 +41,7 @@ export default async function EnvironmentLayout({ children, params }) {
/>
-
+
{children}
diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/billing/components/PricingTable.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/billing/components/PricingTable.tsx
index 55016786a0..e6e99bda12 100644
--- a/apps/web/app/(app)/environments/[environmentId]/settings/billing/components/PricingTable.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/settings/billing/components/PricingTable.tsx
@@ -113,7 +113,7 @@ export default function PricingTableComponent({
},
{
title: "Multi-Language Surveys",
- comingSoon: true,
+ comingSoon: false,
},
{
title: "Unlimited Responses",
@@ -162,7 +162,7 @@ export default function PricingTableComponent({
},
{
title: "Multi-Language Surveys",
- comingSoon: true,
+ comingSoon: false,
},
];
diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/components/SettingsNavbar.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/components/SettingsNavbar.tsx
index ca4cb220cd..9e14086756 100644
--- a/apps/web/app/(app)/environments/[environmentId]/settings/components/SettingsNavbar.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/settings/components/SettingsNavbar.tsx
@@ -11,6 +11,7 @@ import {
FileSearch2Icon,
HashIcon,
KeyIcon,
+ LanguagesIcon,
LinkIcon,
SlidersIcon,
UserCircleIcon,
@@ -28,19 +29,23 @@ import { TProduct } from "@formbricks/types/product";
import { TTeam } from "@formbricks/types/teams";
import { Popover, PopoverContent, PopoverTrigger } from "@formbricks/ui/Popover";
+interface SettingsNavbarProps {
+ environmentId: string;
+ isFormbricksCloud: boolean;
+ team: TTeam;
+ product: TProduct;
+ membershipRole?: TMembershipRole;
+ isMultiLanguageAllowed: boolean;
+}
+
export default function SettingsNavbar({
environmentId,
isFormbricksCloud,
team,
product,
membershipRole,
-}: {
- environmentId: string;
- isFormbricksCloud: boolean;
- team: TTeam;
- product: TProduct;
- membershipRole?: TMembershipRole;
-}) {
+ isMultiLanguageAllowed,
+}: SettingsNavbarProps) {
const pathname = usePathname();
const [mobileNavMenuOpen, setMobileNavMenuOpen] = useState(false);
const { isAdmin, isOwner, isViewer } = getAccessFlags(membershipRole);
@@ -100,6 +105,13 @@ export default function SettingsNavbar({
current: pathname?.includes("/lookandfeel"),
hidden: isViewer,
},
+ {
+ name: "Survey Languages",
+ href: `/environments/${environmentId}/settings/language`,
+ icon: LanguagesIcon,
+ current: pathname?.includes("/language"),
+ hidden: !isMultiLanguageAllowed,
+ },
{
name: "API Keys",
href: `/environments/${environmentId}/settings/api-keys`,
@@ -206,7 +218,7 @@ export default function SettingsNavbar({
hidden: false,
},
],
- [environmentId, isFormbricksCloud, pathname, isPricingDisabled, isViewer]
+ [environmentId, pathname, isViewer, isMultiLanguageAllowed, isFormbricksCloud, isPricingDisabled]
);
if (!navigation) return null;
diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/language/page.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/language/page.tsx
new file mode 100644
index 0000000000..7e00152690
--- /dev/null
+++ b/apps/web/app/(app)/environments/[environmentId]/settings/language/page.tsx
@@ -0,0 +1,39 @@
+import SettingsCard from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
+import SettingsTitle from "@/app/(app)/environments/[environmentId]/settings/components/SettingsTitle";
+import { notFound } from "next/navigation";
+
+import { getMultiLanguagePermission } from "@formbricks/ee/lib/service";
+import EditLanguage from "@formbricks/ee/multiLanguage/components/EditLanguage";
+import { getProductByEnvironmentId } from "@formbricks/lib/product/service";
+import { getTeam } from "@formbricks/lib/team/service";
+
+export default async function LanguageSettingsPage({ params }: { params: { environmentId: string } }) {
+ const product = await getProductByEnvironmentId(params.environmentId);
+
+ if (!product) {
+ throw new Error("Product not found");
+ }
+
+ const team = await getTeam(product?.teamId);
+
+ if (!team) {
+ throw new Error("Team not found");
+ }
+
+ const isMultiLanguageAllowed = getMultiLanguagePermission(team);
+
+ if (!isMultiLanguageAllowed) {
+ notFound();
+ }
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/layout.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/layout.tsx
index 04d5e58bfb..58cc0a23dc 100644
--- a/apps/web/app/(app)/environments/[environmentId]/settings/layout.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/settings/layout.tsx
@@ -1,6 +1,7 @@
import { Metadata } from "next";
import { getServerSession } from "next-auth";
+import { getMultiLanguagePermission } from "@formbricks/ee/lib/service";
import { authOptions } from "@formbricks/lib/authOptions";
import { IS_FORMBRICKS_CLOUD } from "@formbricks/lib/constants";
import { getMembershipByUserIdTeamId } from "@formbricks/lib/membership/service";
@@ -19,9 +20,11 @@ export default async function SettingsLayout({ children, params }) {
getProductByEnvironmentId(params.environmentId),
getServerSession(authOptions),
]);
+
if (!team) {
throw new Error("Team not found");
}
+
if (!product) {
throw new Error("Product not found");
}
@@ -30,6 +33,8 @@ export default async function SettingsLayout({ children, params }) {
throw new Error("Unauthenticated");
}
+ const isMultiLanguageAllowed = getMultiLanguagePermission(team);
+
const currentUserMembership = await getMembershipByUserIdTeamId(session?.user.id, team.id);
return (
@@ -41,6 +46,7 @@ export default async function SettingsLayout({ children, params }) {
team={team}
product={product}
membershipRole={currentUserMembership?.role}
+ isMultiLanguageAllowed={isMultiLanguageAllowed}
/>
diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/components/AddMemberModal.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/components/AddMemberModal.tsx
index b5a2c475df..bacf738d7a 100644
--- a/apps/web/app/(app)/environments/[environmentId]/settings/members/components/AddMemberModal.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/components/AddMemberModal.tsx
@@ -89,7 +89,7 @@ export default function AddMemberModal({
))}
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponsePage.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponsePage.tsx
index 0307dd68ad..70c4249463 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponsePage.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponsePage.tsx
@@ -65,7 +65,7 @@ const ResponsePage = ({
const searchParams = useSearchParams();
survey = useMemo(() => {
- return checkForRecallInHeadline(survey);
+ return checkForRecallInHeadline(survey, "default");
}, [survey]);
const fetchNextPage = useCallback(async () => {
@@ -133,7 +133,7 @@ const ResponsePage = ({
/>
-
+
{
- const session = await getServerSession(authOptions);
- if (!session) throw new AuthorizationError("Not authorized");
-
- const hasUserSurveyAccess = await canUserAccessSurvey(session.user.id, surveyId);
-
- if (!hasUserSurveyAccess) throw new AuthorizationError("Not authorized");
-
- return generateSurveySingleUseId(isEncrypted);
-}
-
export const sendEmailAction = async ({ html, subject, to }: TSendEmailActionArgs) => {
const session = await getServerSession(authOptions);
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/CTASummary.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/CTASummary.tsx
index 05c6db739f..776cb1ee02 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/CTASummary.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/CTASummary.tsx
@@ -2,6 +2,7 @@ import Headline from "@/app/(app)/environments/[environmentId]/surveys/[surveyId
import { questionTypes } from "@/app/lib/questions";
import { InboxIcon } from "lucide-react";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { TSurveySummaryCta } from "@formbricks/types/responses";
import { ProgressBar } from "@formbricks/ui/ProgressBar";
@@ -15,7 +16,7 @@ export default function CTASummary({ questionSummary }: CTASummaryProps) {
return (
-
+
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/CalSummary.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/CalSummary.tsx
index 6f9d270bd6..770438565d 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/CalSummary.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/CalSummary.tsx
@@ -2,6 +2,7 @@ import Headline from "@/app/(app)/environments/[environmentId]/surveys/[surveyId
import { questionTypes } from "@/app/lib/questions";
import { InboxIcon } from "lucide-react";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { TSurveySummaryCal } from "@formbricks/types/responses";
import { ProgressBar } from "@formbricks/ui/ProgressBar";
@@ -16,7 +17,7 @@ export default function CalSummary({ questionSummary }: CalSummaryProps) {
return (
-
+
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/ConsentSummary.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/ConsentSummary.tsx
index 7ded55ce76..c2e8a9fe49 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/ConsentSummary.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/ConsentSummary.tsx
@@ -2,6 +2,7 @@ import Headline from "@/app/(app)/environments/[environmentId]/surveys/[surveyId
import { questionTypes } from "@/app/lib/questions";
import { InboxIcon } from "lucide-react";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { TSurveySummaryConsent } from "@formbricks/types/responses";
import { ProgressBar } from "@formbricks/ui/ProgressBar";
@@ -15,7 +16,7 @@ export default function ConsentSummary({ questionSummary }: ConsentSummaryProps)
return (
-
+
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/DateQuestionSummary.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/DateQuestionSummary.tsx
index 6da94588ca..7dbe624ab7 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/DateQuestionSummary.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/DateQuestionSummary.tsx
@@ -3,6 +3,7 @@ import { questionTypes } from "@/app/lib/questions";
import { InboxIcon } from "lucide-react";
import Link from "next/link";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { getPersonIdentifier } from "@formbricks/lib/person/util";
import { timeSince } from "@formbricks/lib/time";
import { formatDateWithOrdinal } from "@formbricks/lib/utils/datetime";
@@ -20,8 +21,7 @@ export default function DateQuestionSummary({ questionSummary, environmentId }:
return (
-
-
+
{questionTypeInfo &&
}
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/FileUploadSummary.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/FileUploadSummary.tsx
index 1b4c3c4070..5b7b015436 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/FileUploadSummary.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/FileUploadSummary.tsx
@@ -3,6 +3,7 @@ import { questionTypes } from "@/app/lib/questions";
import { DownloadIcon, FileIcon, InboxIcon } from "lucide-react";
import Link from "next/link";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { getPersonIdentifier } from "@formbricks/lib/person/util";
import { getOriginalFileNameFromUrl } from "@formbricks/lib/storage/utils";
import { timeSince } from "@formbricks/lib/time";
@@ -20,7 +21,7 @@ export default function FileUploadSummary({ questionSummary, environmentId }: Fi
return (
-
+
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/MultipleChoiceSummary.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/MultipleChoiceSummary.tsx
index 973479ca0a..a5c7f7afe1 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/MultipleChoiceSummary.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/MultipleChoiceSummary.tsx
@@ -3,6 +3,7 @@ import { questionTypes } from "@/app/lib/questions";
import { InboxIcon } from "lucide-react";
import Link from "next/link";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { getPersonIdentifier } from "@formbricks/lib/person/util";
import { TSurveySummaryMultipleChoice } from "@formbricks/types/responses";
import { PersonAvatar } from "@formbricks/ui/Avatars";
@@ -33,7 +34,7 @@ export default function MultipleChoiceSummary({
return (
-
+
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/NPSSummary.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/NPSSummary.tsx
index 37ad95c34c..4bbcd66124 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/NPSSummary.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/NPSSummary.tsx
@@ -2,6 +2,7 @@ import Headline from "@/app/(app)/environments/[environmentId]/surveys/[surveyId
import { questionTypes } from "@/app/lib/questions";
import { InboxIcon } from "lucide-react";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { TSurveySummaryNps } from "@formbricks/types/responses";
import { HalfCircle, ProgressBar } from "@formbricks/ui/ProgressBar";
@@ -15,7 +16,7 @@ export default function NPSSummary({ questionSummary }: NPSSummaryProps) {
return (
-
+
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/OpenTextSummary.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/OpenTextSummary.tsx
index baaff5817e..d47f447a8c 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/OpenTextSummary.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/OpenTextSummary.tsx
@@ -3,6 +3,7 @@ import { questionTypes } from "@/app/lib/questions";
import { InboxIcon } from "lucide-react";
import Link from "next/link";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { getPersonIdentifier } from "@formbricks/lib/person/util";
import { timeSince } from "@formbricks/lib/time";
import { TSurveySummaryOpenText } from "@formbricks/types/responses";
@@ -19,7 +20,8 @@ export default function OpenTextSummary({ questionSummary, environmentId }: Open
return (
-
+
+
{questionTypeInfo &&
}
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/PictureChoiceSummary.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/PictureChoiceSummary.tsx
index fe8e492f68..6e644a4a44 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/PictureChoiceSummary.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/PictureChoiceSummary.tsx
@@ -3,6 +3,7 @@ import { questionTypes } from "@/app/lib/questions";
import { InboxIcon } from "lucide-react";
import Image from "next/image";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { TSurveySummaryPictureSelection } from "@formbricks/types/responses";
import { ProgressBar } from "@formbricks/ui/ProgressBar";
@@ -19,7 +20,7 @@ export default function PictureChoiceSummary({ questionSummary }: PictureChoiceS
return (
-
+
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/RatingSummary.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/RatingSummary.tsx
index 2581dd82fe..efc1c23b6c 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/RatingSummary.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/RatingSummary.tsx
@@ -3,6 +3,7 @@ import { questionTypes } from "@/app/lib/questions";
import { CircleSlash2, InboxIcon, SmileIcon, StarIcon } from "lucide-react";
import { useMemo } from "react";
+import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { TSurveySummaryRating } from "@formbricks/types/responses";
import { ProgressBar } from "@formbricks/ui/ProgressBar";
import { RatingResponse } from "@formbricks/ui/RatingResponse";
@@ -24,7 +25,7 @@ export default function RatingSummary({ questionSummary }: RatingSummaryProps) {
return (
-
+
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/ShareEmbedSurvey.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/ShareEmbedSurvey.tsx
index 6ca3cc1e9f..453de03967 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/ShareEmbedSurvey.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/ShareEmbedSurvey.tsx
@@ -1,27 +1,16 @@
"use client";
-import { generateSingleUseIdAction } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/actions";
-import {
- ArrowLeftIcon,
- BellRing,
- BlocksIcon,
- Code2Icon,
- CopyIcon,
- LinkIcon,
- MailIcon,
- RefreshCcw,
-} from "lucide-react";
+import { ArrowLeftIcon, BellRing, BlocksIcon, Code2Icon, LinkIcon, MailIcon } from "lucide-react";
import Link from "next/link";
import { useRouter } from "next/navigation";
-import { useCallback, useEffect, useRef, useState } from "react";
-import toast from "react-hot-toast";
+import { useState } from "react";
import { cn } from "@formbricks/lib/cn";
-import { TProduct } from "@formbricks/types/product";
import { TSurvey } from "@formbricks/types/surveys";
import { TUser } from "@formbricks/types/user";
import { Button } from "@formbricks/ui/Button";
import { Dialog, DialogContent } from "@formbricks/ui/Dialog";
+import { ShareSurveyLink } from "@formbricks/ui/ShareSurveyLink";
import EmailTab from "./shareEmbedTabs/EmailTab";
import LinkTab from "./shareEmbedTabs/LinkTab";
@@ -32,7 +21,6 @@ interface ShareEmbedSurveyProps {
open: boolean;
setOpen: React.Dispatch
>;
webAppUrl: string;
- product: TProduct;
user: TUser;
}
export default function ShareEmbedSurvey({ survey, open, setOpen, webAppUrl, user }: ShareEmbedSurveyProps) {
@@ -49,35 +37,8 @@ export default function ShareEmbedSurvey({ survey, open, setOpen, webAppUrl, use
const [activeId, setActiveId] = useState(tabs[0].id);
const [showInitialPage, setShowInitialPage] = useState(true);
- const linkTextRef = useRef(null);
const [surveyUrl, setSurveyUrl] = useState("");
- const getUrl = useCallback(async () => {
- let url = webAppUrl + "/s/" + survey.id;
- if (survey.singleUse?.enabled) {
- const singleUseId = await generateSingleUseIdAction(survey.id, survey.singleUse.isEncrypted);
- url += "?suId=" + singleUseId;
- }
- setSurveyUrl(url);
- }, [survey, webAppUrl]);
-
- useEffect(() => {
- getUrl();
- }, [survey, webAppUrl, getUrl]);
-
- const handleTextSelection = () => {
- if (linkTextRef.current) {
- const range = document.createRange();
- range.selectNodeContents(linkTextRef.current);
-
- const selection = window.getSelection();
- if (selection) {
- selection.removeAllRanges();
- selection.addRange(range);
- }
- }
- };
-
const handleOpenChange = (open: boolean) => {
setActiveId(tabs[0].id);
setOpen(open);
@@ -91,11 +52,6 @@ export default function ShareEmbedSurvey({ survey, open, setOpen, webAppUrl, use
setShowInitialPage(!showInitialPage);
};
- const generateNewSingleUseLink = () => {
- getUrl();
- toast.success("New single use link generated");
- };
-
return (