fix: iframe url not being automatically populated (#5892)

Co-authored-by: Divyanshu Lohani <DivyanshuLohani@users.noreply.github.com>
Co-authored-by: Dhruwang <dhruwangjariwala18@gmail.com>
This commit is contained in:
DivyanshuLohani
2025-06-06 12:42:59 +05:30
committed by GitHub
parent a9946737df
commit 3ffc9bd290
11 changed files with 116 additions and 37 deletions
@@ -41,6 +41,36 @@ const mockSurveyWeb = {
styling: null,
} as unknown as TSurvey;
vi.mock("@/lib/constants", () => ({
INTERCOM_SECRET_KEY: "test-secret-key",
IS_INTERCOM_CONFIGURED: true,
INTERCOM_APP_ID: "test-app-id",
ENCRYPTION_KEY: "test-encryption-key",
ENTERPRISE_LICENSE_KEY: "test-enterprise-license-key",
GITHUB_ID: "test-github-id",
GITHUB_SECRET: "test-githubID",
GOOGLE_CLIENT_ID: "test-google-client-id",
GOOGLE_CLIENT_SECRET: "test-google-client-secret",
AZUREAD_CLIENT_ID: "test-azuread-client-id",
AZUREAD_CLIENT_SECRET: "test-azure",
AZUREAD_TENANT_ID: "test-azuread-tenant-id",
OIDC_DISPLAY_NAME: "test-oidc-display-name",
OIDC_CLIENT_ID: "test-oidc-client-id",
OIDC_ISSUER: "test-oidc-issuer",
OIDC_CLIENT_SECRET: "test-oidc-client-secret",
OIDC_SIGNING_ALGORITHM: "test-oidc-signing-algorithm",
WEBAPP_URL: "test-webapp-url",
IS_POSTHOG_CONFIGURED: true,
POSTHOG_API_HOST: "test-posthog-api-host",
POSTHOG_API_KEY: "test-posthog-api-key",
FORMBRICKS_ENVIRONMENT_ID: "mock-formbricks-environment-id",
IS_FORMBRICKS_ENABLED: true,
SESSION_MAX_AGE: 1000,
REDIS_URL: "test-redis-url",
AUDIT_LOG_ENABLED: true,
IS_FORMBRICKS_CLOUD: false,
}));
const mockSurveyLink = {
...mockSurveyWeb,
id: "survey2",
@@ -1,6 +1,7 @@
"use client";
import { ShareSurveyLink } from "@/modules/analysis/components/ShareSurveyLink";
import { getSurveyUrl } from "@/modules/analysis/utils";
import { Badge } from "@/modules/ui/components/badge";
import { Dialog, DialogContent, DialogDescription, DialogTitle } from "@/modules/ui/components/dialog";
import { useTranslate } from "@tolgee/react";
@@ -62,6 +63,20 @@ export const ShareEmbedSurvey = ({
const [showView, setShowView] = useState<"start" | "embed" | "panel">("start");
const [surveyUrl, setSurveyUrl] = useState("");
useEffect(() => {
const fetchSurveyUrl = async () => {
try {
const url = await getSurveyUrl(survey, surveyDomain, "default");
setSurveyUrl(url);
} catch (error) {
console.error("Failed to fetch survey URL:", error);
// Fallback to a default URL if fetching fails
setSurveyUrl(`${surveyDomain}/s/${survey.id}`);
}
};
fetchSurveyUrl();
}, [survey, surveyDomain]);
useEffect(() => {
if (survey.type !== "link") {
setActiveId(tabs[3].id);
+1
View File
@@ -2629,6 +2629,7 @@
"product_market_fit_superhuman_question_3_choice_3": "Produktmanager",
"product_market_fit_superhuman_question_3_choice_4": "People Manager",
"product_market_fit_superhuman_question_3_choice_5": "Softwareentwickler",
"product_market_fit_superhuman_question_3_headline": "Was ist deine Rolle?",
"product_market_fit_superhuman_question_3_subheader": "Bitte wähle eine der folgenden Optionen aus:",
"product_market_fit_superhuman_question_4_headline": "Wer würde am ehesten von $[projectName] profitieren?",
"product_market_fit_superhuman_question_5_headline": "Welchen Mehrwert ziehst Du aus $[projectName]?",
+1
View File
@@ -2629,6 +2629,7 @@
"product_market_fit_superhuman_question_3_choice_3": "Product Manager",
"product_market_fit_superhuman_question_3_choice_4": "Product Owner",
"product_market_fit_superhuman_question_3_choice_5": "Software Engineer",
"product_market_fit_superhuman_question_3_headline": "What is your role?",
"product_market_fit_superhuman_question_3_subheader": "Please select one of the following options:",
"product_market_fit_superhuman_question_4_headline": "What type of people do you think would most benefit from $[projectName]?",
"product_market_fit_superhuman_question_5_headline": "What is the main benefit you receive from $[projectName]?",
+1
View File
@@ -2629,6 +2629,7 @@
"product_market_fit_superhuman_question_3_choice_3": "Chef de produit",
"product_market_fit_superhuman_question_3_choice_4": "Propriétaire de produit",
"product_market_fit_superhuman_question_3_choice_5": "Ingénieur logiciel",
"product_market_fit_superhuman_question_3_headline": "Quel est votre rôle ?",
"product_market_fit_superhuman_question_3_subheader": "Veuillez sélectionner l'une des options suivantes :",
"product_market_fit_superhuman_question_4_headline": "Quel type de personnes pensez-vous bénéficierait le plus de $[projectName] ?",
"product_market_fit_superhuman_question_5_headline": "Quel est le principal avantage que vous tirez de $[projectName] ?",
+1
View File
@@ -2629,6 +2629,7 @@
"product_market_fit_superhuman_question_3_choice_3": "Gerente de Produto",
"product_market_fit_superhuman_question_3_choice_4": "Dono do Produto",
"product_market_fit_superhuman_question_3_choice_5": "Engenheiro de Software",
"product_market_fit_superhuman_question_3_headline": "Qual é a sua função?",
"product_market_fit_superhuman_question_3_subheader": "Por favor, escolha uma das opções a seguir:",
"product_market_fit_superhuman_question_4_headline": "Que tipo de pessoas você acha que mais se beneficiariam do $[projectName]?",
"product_market_fit_superhuman_question_5_headline": "Qual é o principal benefício que você recebe do $[projectName]?",
+1
View File
@@ -2629,6 +2629,7 @@
"product_market_fit_superhuman_question_3_choice_3": "Gestor de Produto",
"product_market_fit_superhuman_question_3_choice_4": "Proprietário do Produto",
"product_market_fit_superhuman_question_3_choice_5": "Engenheiro de Software",
"product_market_fit_superhuman_question_3_headline": "Qual é o seu papel?",
"product_market_fit_superhuman_question_3_subheader": "Por favor, selecione uma das seguintes opções:",
"product_market_fit_superhuman_question_4_headline": "Que tipo de pessoas acha que mais beneficiariam de $[projectName]?",
"product_market_fit_superhuman_question_5_headline": "Qual é o principal benefício que recebe de $[projectName]?",
+1
View File
@@ -2629,6 +2629,7 @@
"product_market_fit_superhuman_question_3_choice_3": "產品經理",
"product_market_fit_superhuman_question_3_choice_4": "產品負責人",
"product_market_fit_superhuman_question_3_choice_5": "軟體工程師",
"product_market_fit_superhuman_question_3_headline": "您的角色是什麼?",
"product_market_fit_superhuman_question_3_subheader": "請選取以下其中一個選項:",
"product_market_fit_superhuman_question_4_headline": "您認為哪些類型的人最能從 {projectName} 中受益?",
"product_market_fit_superhuman_question_5_headline": "您從 {projectName} 獲得的主要好處是什麼?",
@@ -2,14 +2,14 @@
import { useSurveyQRCode } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/survey-qr-code";
import { getFormattedErrorMessage } from "@/lib/utils/helper";
import { generateSingleUseIdAction } from "@/modules/survey/list/actions";
import { Button } from "@/modules/ui/components/button";
import { useTranslate } from "@tolgee/react";
import { Copy, QrCode, RefreshCcw, SquareArrowOutUpRight } from "lucide-react";
import { useCallback, useEffect, useState } from "react";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { TSurvey } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { getSurveyUrl } from "../../utils";
import { LanguageDropdown } from "./components/LanguageDropdown";
import { SurveyLinkDisplay } from "./components/SurveyLinkDisplay";
@@ -31,46 +31,30 @@ export const ShareSurveyLink = ({
const { t } = useTranslate();
const [language, setLanguage] = useState("default");
const getUrl = useCallback(async () => {
let url = `${surveyDomain}/s/${survey.id}`;
const queryParams: string[] = [];
if (survey.singleUse?.enabled) {
const singleUseIdResponse = await generateSingleUseIdAction({
surveyId: survey.id,
isEncrypted: survey.singleUse.isEncrypted,
});
if (singleUseIdResponse?.data) {
queryParams.push(`suId=${singleUseIdResponse.data}`);
} else {
const errorMessage = getFormattedErrorMessage(singleUseIdResponse);
useEffect(() => {
const fetchSurveyUrl = async () => {
try {
const url = await getSurveyUrl(survey, surveyDomain, language);
setSurveyUrl(url);
} catch (error) {
const errorMessage = getFormattedErrorMessage(error);
toast.error(errorMessage);
}
};
fetchSurveyUrl();
}, [survey, language, surveyDomain, setSurveyUrl]);
const generateNewSingleUseLink = async () => {
try {
const newUrl = await getSurveyUrl(survey, surveyDomain, language);
setSurveyUrl(newUrl);
toast.success(t("environments.surveys.new_single_use_link_generated"));
} catch (error) {
const errorMessage = getFormattedErrorMessage(error);
toast.error(errorMessage);
}
if (language !== "default") {
queryParams.push(`lang=${language}`);
}
if (queryParams.length) {
url += `?${queryParams.join("&")}`;
}
setSurveyUrl(url);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [survey, surveyDomain, language]);
const generateNewSingleUseLink = () => {
getUrl();
toast.success(t("environments.surveys.new_single_use_link_generated"));
};
useEffect(() => {
getUrl();
}, [survey, getUrl, language]);
const { downloadQRCode } = useSurveyQRCode(surveyUrl);
return (
+8
View File
@@ -3,6 +3,14 @@ import { isValidElement } from "react";
import { afterEach, describe, expect, test, vi } from "vitest";
import { renderHyperlinkedContent } from "./utils";
vi.mock("@/lib/utils/helper", () => ({
getFormattedErrorMessage: vi.fn(),
}));
vi.mock("@/modules/survey/list/actions", () => ({
generateSingleUseIdAction: vi.fn(),
}));
describe("renderHyperlinkedContent", () => {
afterEach(() => {
cleanup();
+36
View File
@@ -1,4 +1,7 @@
import { getFormattedErrorMessage } from "@/lib/utils/helper";
import { generateSingleUseIdAction } from "@/modules/survey/list/actions";
import { JSX } from "react";
import { TSurvey } from "@formbricks/types/surveys/types";
// Utility function to render hyperlinked content
export const renderHyperlinkedContent = (data: string): JSX.Element[] => {
@@ -26,3 +29,36 @@ export const renderHyperlinkedContent = (data: string): JSX.Element[] => {
)
);
};
export const getSurveyUrl = async (
survey: TSurvey,
surveyDomain: string,
language: string
): Promise<string> => {
let url = `${surveyDomain}/s/${survey.id}`;
const queryParams: string[] = [];
if (survey.singleUse?.enabled) {
const singleUseIdResponse = await generateSingleUseIdAction({
surveyId: survey.id,
isEncrypted: survey.singleUse.isEncrypted,
});
if (singleUseIdResponse?.data) {
queryParams.push(`suId=${singleUseIdResponse.data}`);
} else {
const errorMessage = getFormattedErrorMessage(singleUseIdResponse);
throw new Error(errorMessage);
}
}
if (language !== "default") {
queryParams.push(`lang=${language}`);
}
if (queryParams.length) {
url += `?${queryParams.join("&")}`;
}
return url;
};