From 8af6c1599808f112c4dd7bbc8afaf1b45d745d2b Mon Sep 17 00:00:00 2001 From: Victor Hugo dos Santos <115753265+victorvhs017@users.noreply.github.com> Date: Fri, 11 Jul 2025 19:45:42 +0700 Subject: [PATCH] feat: new share modal website embed and pop out (#6217) --- .../settings/components/SettingsCard.tsx | 7 +- .../components/share-survey-modal.test.tsx | 36 ++- .../summary/components/share-survey-modal.tsx | 20 +- .../shareEmbedModal/DynamicPopupTab.test.tsx | 178 ++++++++++++ .../shareEmbedModal/DynamicPopupTab.tsx | 76 ++++++ .../shareEmbedModal/TabContainer.test.tsx | 75 ++++++ .../shareEmbedModal/TabContainer.tsx | 21 ++ .../shareEmbedModal/WebsiteEmbedTab.test.tsx | 192 +++++++++++++ .../shareEmbedModal/WebsiteEmbedTab.tsx | 57 ++++ .../shareEmbedModal/WebsiteTab.test.tsx | 254 ------------------ .../components/shareEmbedModal/WebsiteTab.tsx | 118 -------- .../shareEmbedModal/share-view.test.tsx | 74 +++-- .../components/shareEmbedModal/share-view.tsx | 24 +- apps/web/locales/de-DE.json | 23 +- apps/web/locales/en-US.json | 25 +- apps/web/locales/fr-FR.json | 23 +- apps/web/locales/pt-BR.json | 23 +- apps/web/locales/pt-PT.json | 23 +- apps/web/locales/zh-Hant-TW.json | 23 +- .../ui/components/alert/index.test.tsx | 64 +++++ .../web/modules/ui/components/alert/index.tsx | 8 +- .../ui/components/code-block/index.test.tsx | 35 +++ .../ui/components/code-block/index.tsx | 4 +- .../ui/components/typography/index.test.tsx | 19 +- .../ui/components/typography/index.tsx | 48 +++- .../embed-surveys/embed-mode-toggle.webp | Bin 43938 -> 18744 bytes .../surveys/link-surveys/embed-surveys.mdx | 2 +- 27 files changed, 1011 insertions(+), 441 deletions(-) create mode 100644 apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/DynamicPopupTab.test.tsx create mode 100644 apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/DynamicPopupTab.tsx create mode 100644 apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/TabContainer.test.tsx create mode 100644 apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/TabContainer.tsx create mode 100644 apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteEmbedTab.test.tsx create mode 100644 apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteEmbedTab.tsx delete mode 100644 apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteTab.test.tsx delete mode 100644 apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteTab.tsx diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/components/SettingsCard.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/components/SettingsCard.tsx index dfb1f2107e..0885289369 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/components/SettingsCard.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/components/SettingsCard.tsx @@ -2,6 +2,7 @@ import { cn } from "@/lib/cn"; import { Badge } from "@/modules/ui/components/badge"; +import { H3, Small } from "@/modules/ui/components/typography"; import { useTranslate } from "@tolgee/react"; export const SettingsCard = ({ @@ -31,7 +32,7 @@ export const SettingsCard = ({ id={title}>
-

{title}

+

{title}

{beta && } {soon && ( @@ -39,7 +40,9 @@ export const SettingsCard = ({ )}
-

{description}

+ + {description} +
{children}
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.test.tsx index 33cfd44518..66cd1e6ae7 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.test.tsx @@ -217,8 +217,10 @@ describe("ShareEmbedSurvey", () => { tabs: { id: string; label: string; icon: LucideIcon }[]; activeId: string; }; - expect(embedViewProps.tabs.length).toBe(4); + expect(embedViewProps.tabs.length).toBe(5); expect(embedViewProps.tabs.find((tab) => tab.id === "app")).toBeUndefined(); + expect(embedViewProps.tabs.find((tab) => tab.id === "dynamic-popup")).toBeDefined(); + expect(embedViewProps.tabs.find((tab) => tab.id === "website-embed")).toBeDefined(); expect(embedViewProps.tabs[0].id).toBe("link"); expect(embedViewProps.activeId).toBe("link"); }); @@ -230,7 +232,9 @@ describe("ShareEmbedSurvey", () => { activeId: string; }; expect(embedViewProps.tabs.length).toBe(1); - expect(embedViewProps.tabs[0].id).toBe("app"); + expect(embedViewProps.tabs.find((tab) => tab.id === "app")).toBeDefined(); + expect(embedViewProps.tabs.find((tab) => tab.id === "website-embed")).toBeUndefined(); + expect(embedViewProps.tabs.find((tab) => tab.id === "dynamic-popup")).toBeUndefined(); expect(embedViewProps.activeId).toBe("app"); }); @@ -285,4 +289,32 @@ describe("ShareEmbedSurvey", () => { linkTab = embedViewProps.tabs.find((tab) => tab.id === "link"); expect(linkTab?.label).toBe("environments.surveys.summary.single_use_links"); }); + + test("dynamic popup tab is only visible for link surveys", () => { + // Test link survey includes dynamic popup tab + render(); + let embedViewProps = vi.mocked(mockShareViewComponent).mock.calls[0][0] as { + tabs: { id: string; label: string }[]; + }; + expect(embedViewProps.tabs.find((tab) => tab.id === "dynamic-popup")).toBeDefined(); + cleanup(); + vi.mocked(mockShareViewComponent).mockClear(); + + // Test web survey excludes dynamic popup tab + render(); + embedViewProps = vi.mocked(mockShareViewComponent).mock.calls[0][0] as { + tabs: { id: string; label: string }[]; + }; + expect(embedViewProps.tabs.find((tab) => tab.id === "dynamic-popup")).toBeUndefined(); + }); + + test("website-embed and dynamic-popup tabs replace old webpage tab", () => { + render(); + const embedViewProps = vi.mocked(mockShareViewComponent).mock.calls[0][0] as { + tabs: { id: string; label: string }[]; + }; + expect(embedViewProps.tabs.find((tab) => tab.id === "webpage")).toBeUndefined(); + expect(embedViewProps.tabs.find((tab) => tab.id === "website-embed")).toBeDefined(); + expect(embedViewProps.tabs.find((tab) => tab.id === "dynamic-popup")).toBeDefined(); + }); }); diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.tsx index f960272e9a..3188f284cd 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.tsx @@ -1,9 +1,10 @@ "use client"; import { getSurveyUrl } from "@/modules/analysis/utils"; -import { Dialog, DialogContent } from "@/modules/ui/components/dialog"; +import { Dialog, DialogContent, DialogTitle } from "@/modules/ui/components/dialog"; +import { VisuallyHidden } from "@radix-ui/react-visually-hidden"; import { useTranslate } from "@tolgee/react"; -import { Code2Icon, LinkIcon, MailIcon, SmartphoneIcon, UserIcon } from "lucide-react"; +import { Code2Icon, LinkIcon, MailIcon, SmartphoneIcon, SquareStack, UserIcon } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; import { logger } from "@formbricks/logger"; import { TSegment } from "@formbricks/types/segment"; @@ -18,7 +19,8 @@ enum ShareViewType { LINK = "link", PERSONAL_LINKS = "personal-links", EMAIL = "email", - WEBPAGE = "webpage", + WEBSITE_EMBED = "website-embed", + DYNAMIC_POPUP = "dynamic-popup", APP = "app", } @@ -67,10 +69,15 @@ export const ShareSurveyModal = ({ icon: MailIcon, }, { - id: ShareViewType.WEBPAGE, + id: ShareViewType.WEBSITE_EMBED, label: t("environments.surveys.summary.embed_on_website"), icon: Code2Icon, }, + { + id: ShareViewType.DYNAMIC_POPUP, + label: t("environments.surveys.summary.dynamic_popup"), + icon: SquareStack, + }, ], [t, isSingleUseLinkSurvey] ); @@ -126,7 +133,10 @@ export const ShareSurveyModal = ({ return ( - + + + + {showView === "start" ? ( ({ + Alert: (props: { variant?: string; size?: string; children: React.ReactNode }) => ( +
+ {props.children} +
+ ), + AlertButton: (props: { asChild?: boolean; children: React.ReactNode }) => ( +
+ {props.children} +
+ ), + AlertDescription: (props: { children: React.ReactNode }) => ( +
{props.children}
+ ), + AlertTitle: (props: { children: React.ReactNode }) =>
{props.children}
, +})); + +vi.mock("@/modules/ui/components/button", () => ({ + Button: (props: { variant?: string; asChild?: boolean; children: React.ReactNode }) => ( +
+ {props.children} +
+ ), +})); + +vi.mock("@/modules/ui/components/typography", () => ({ + H4: (props: { children: React.ReactNode }) =>
{props.children}
, +})); + +vi.mock("@tolgee/react", () => ({ + useTranslate: () => ({ + t: (key: string) => key, + }), +})); + +vi.mock("lucide-react", () => ({ + ExternalLinkIcon: (props: { className?: string }) => ( +
+ ExternalLinkIcon +
+ ), +})); + +// Mock Next.js Link +vi.mock("next/link", () => ({ + default: (props: { href: string; target?: string; className?: string; children: React.ReactNode }) => ( + + {props.children} + + ), +})); + +describe("DynamicPopupTab", () => { + afterEach(() => { + cleanup(); + }); + + const defaultProps = { + environmentId: "env-123", + surveyId: "survey-123", + }; + + test("renders alert with correct props", () => { + render(); + + const alert = screen.getByTestId("alert"); + expect(alert).toBeInTheDocument(); + expect(alert).toHaveAttribute("data-variant", "info"); + expect(alert).toHaveAttribute("data-size", "default"); + }); + + test("renders alert title with translation key", () => { + render(); + + const alertTitle = screen.getByTestId("alert-title"); + expect(alertTitle).toBeInTheDocument(); + expect(alertTitle).toHaveTextContent("environments.surveys.summary.dynamic_popup.alert_title"); + }); + + test("renders alert description with translation key", () => { + render(); + + const alertDescription = screen.getByTestId("alert-description"); + expect(alertDescription).toBeInTheDocument(); + expect(alertDescription).toHaveTextContent( + "environments.surveys.summary.dynamic_popup.alert_description" + ); + }); + + test("renders alert button with link to survey edit page", () => { + render(); + + const alertButton = screen.getByTestId("alert-button"); + expect(alertButton).toBeInTheDocument(); + expect(alertButton).toHaveAttribute("data-as-child", "true"); + + const link = screen.getAllByTestId("next-link")[0]; + expect(link).toHaveAttribute("href", "/environments/env-123/surveys/survey-123/edit"); + expect(link).toHaveTextContent("environments.surveys.summary.dynamic_popup.alert_button"); + }); + + test("renders title with correct text", () => { + render(); + + const h4 = screen.getByTestId("h4"); + expect(h4).toBeInTheDocument(); + expect(h4).toHaveTextContent("environments.surveys.summary.dynamic_popup.title"); + }); + + test("renders attribute-based targeting documentation button", () => { + render(); + + const links = screen.getAllByTestId("next-link"); + const attributeLink = links.find((link) => link.getAttribute("href")?.includes("advanced-targeting")); + + expect(attributeLink).toBeInTheDocument(); + expect(attributeLink).toHaveAttribute( + "href", + "https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/advanced-targeting" + ); + expect(attributeLink).toHaveAttribute("target", "_blank"); + }); + + test("renders code and no code triggers documentation button", () => { + render(); + + const links = screen.getAllByTestId("next-link"); + const actionsLink = links.find((link) => link.getAttribute("href")?.includes("actions")); + + expect(actionsLink).toBeInTheDocument(); + expect(actionsLink).toHaveAttribute( + "href", + "https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/actions" + ); + expect(actionsLink).toHaveAttribute("target", "_blank"); + }); + + test("renders recontact options documentation button", () => { + render(); + + const links = screen.getAllByTestId("next-link"); + const recontactLink = links.find((link) => link.getAttribute("href")?.includes("recontact")); + + expect(recontactLink).toBeInTheDocument(); + expect(recontactLink).toHaveAttribute( + "href", + "https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/recontact" + ); + expect(recontactLink).toHaveAttribute("target", "_blank"); + }); + + test("all documentation buttons have external link icons", () => { + render(); + + const externalLinkIcons = screen.getAllByTestId("external-link-icon"); + expect(externalLinkIcons).toHaveLength(3); + + externalLinkIcons.forEach((icon) => { + expect(icon).toHaveClass("h-4 w-4 flex-shrink-0"); + }); + }); + + test("documentation button links open in new tab", () => { + render(); + + const documentationLinks = screen.getAllByTestId("next-link").slice(1, 4); // Skip the alert button link + + documentationLinks.forEach((link) => { + expect(link).toHaveAttribute("target", "_blank"); + }); + }); +}); diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/DynamicPopupTab.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/DynamicPopupTab.tsx new file mode 100644 index 0000000000..ff57677daa --- /dev/null +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/DynamicPopupTab.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { Alert, AlertButton, AlertDescription, AlertTitle } from "@/modules/ui/components/alert"; +import { Button } from "@/modules/ui/components/button"; +import { H4 } from "@/modules/ui/components/typography"; +import { useTranslate } from "@tolgee/react"; +import { ExternalLinkIcon } from "lucide-react"; +import Link from "next/link"; + +interface DynamicPopupTabProps { + environmentId: string; + surveyId: string; +} + +interface DocumentationButtonProps { + href: string; + title: string; + readDocsText: string; +} + +const DocumentationButton = ({ href, title, readDocsText }: DocumentationButtonProps) => { + return ( + + ); +}; + +export const DynamicPopupTab = ({ environmentId, surveyId }: DynamicPopupTabProps) => { + const { t } = useTranslate(); + + return ( +
+ + {t("environments.surveys.summary.dynamic_popup.alert_title")} + + {t("environments.surveys.summary.dynamic_popup.alert_description")} + + + + {t("environments.surveys.summary.dynamic_popup.alert_button")} + + + + +
+

{t("environments.surveys.summary.dynamic_popup.title")}

+ + + +
+
+ ); +}; diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/TabContainer.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/TabContainer.test.tsx new file mode 100644 index 0000000000..e4faeefe8b --- /dev/null +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/TabContainer.test.tsx @@ -0,0 +1,75 @@ +import "@testing-library/jest-dom/vitest"; +import { cleanup, render, screen } from "@testing-library/react"; +import { afterEach, describe, expect, test, vi } from "vitest"; +import { TabContainer } from "./TabContainer"; + +// Mock components +vi.mock("@/modules/ui/components/typography", () => ({ + H3: (props: { children: React.ReactNode }) =>

{props.children}

, + Small: (props: { color?: string; margin?: string; children: React.ReactNode }) => ( +

+ {props.children} +

+ ), +})); + +describe("TabContainer", () => { + afterEach(() => { + cleanup(); + }); + + const defaultProps = { + title: "Test Tab Title", + description: "Test tab description", + children:
Tab content
, + }; + + test("renders title with correct props", () => { + render(); + + const title = screen.getByTestId("h3"); + expect(title).toBeInTheDocument(); + expect(title).toHaveTextContent("Test Tab Title"); + }); + + test("renders description with correct text and props", () => { + render(); + + const description = screen.getByTestId("small"); + expect(description).toBeInTheDocument(); + expect(description).toHaveTextContent("Test tab description"); + expect(description).toHaveAttribute("data-color", "muted"); + expect(description).toHaveAttribute("data-margin", "headerDescription"); + }); + + test("renders children content", () => { + render(); + + const tabContent = screen.getByTestId("tab-content"); + expect(tabContent).toBeInTheDocument(); + expect(tabContent).toHaveTextContent("Tab content"); + }); + + test("renders with correct container structure", () => { + render(); + + const container = screen.getByTestId("h3").parentElement?.parentElement; + expect(container).toHaveClass("flex", "h-full", "grow", "flex-col", "items-start", "space-y-4"); + }); + + test("renders header with correct structure", () => { + render(); + + const header = screen.getByTestId("h3").parentElement; + expect(header).toBeInTheDocument(); + expect(header).toContainElement(screen.getByTestId("h3")); + expect(header).toContainElement(screen.getByTestId("small")); + }); + + test("renders children directly in container", () => { + render(); + + const container = screen.getByTestId("h3").parentElement?.parentElement; + expect(container).toContainElement(screen.getByTestId("tab-content")); + }); +}); diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/TabContainer.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/TabContainer.tsx new file mode 100644 index 0000000000..35720a3cfe --- /dev/null +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/TabContainer.tsx @@ -0,0 +1,21 @@ +import { H3, Small } from "@/modules/ui/components/typography"; + +interface TabContainerProps { + title: string; + description: string; + children: React.ReactNode; +} + +export const TabContainer = ({ title, description, children }: TabContainerProps) => { + return ( +
+
+

{title}

+ + {description} + +
+ {children} +
+ ); +}; diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteEmbedTab.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteEmbedTab.test.tsx new file mode 100644 index 0000000000..2e580c4e64 --- /dev/null +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteEmbedTab.test.tsx @@ -0,0 +1,192 @@ +import "@testing-library/jest-dom/vitest"; +import { cleanup, render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { afterEach, describe, expect, test, vi } from "vitest"; +import { WebsiteEmbedTab } from "./WebsiteEmbedTab"; + +// Mock components +vi.mock("@/modules/ui/components/advanced-option-toggle", () => ({ + AdvancedOptionToggle: (props: { + htmlId: string; + isChecked: boolean; + onToggle: (checked: boolean) => void; + title: string; + description: string; + customContainerClass?: string; + }) => ( +
+ + props.onToggle(e.target.checked)} + data-testid="embed-mode-toggle" + /> + {props.description} + {props.customContainerClass && ( + {props.customContainerClass} + )} +
+ ), +})); + +vi.mock("@/modules/ui/components/button", () => ({ + Button: (props: { + title?: string; + "aria-label"?: string; + onClick?: () => void; + children: React.ReactNode; + type?: "button" | "submit" | "reset"; + }) => ( + + ), +})); + +vi.mock("@/modules/ui/components/code-block", () => ({ + CodeBlock: (props: { + language: string; + showCopyToClipboard: boolean; + noMargin?: boolean; + children: string; + }) => ( +
+ {props.language} + {props.showCopyToClipboard.toString()} + {props.noMargin && true} +
{props.children}
+
+ ), +})); + +vi.mock("@tolgee/react", () => ({ + useTranslate: () => ({ + t: (key: string) => key, + }), +})); + +vi.mock("lucide-react", () => ({ + CopyIcon: () =>
CopyIcon
, +})); + +// Mock react-hot-toast +vi.mock("react-hot-toast", () => ({ + default: { + success: vi.fn(), + }, +})); + +// Mock clipboard API +Object.assign(navigator, { + clipboard: { + writeText: vi.fn().mockImplementation(() => Promise.resolve()), + }, +}); + +describe("WebsiteEmbedTab", () => { + afterEach(() => { + cleanup(); + vi.clearAllMocks(); + }); + + const defaultProps = { + surveyUrl: "https://example.com/survey/123", + }; + + test("renders all components correctly", () => { + render(); + + expect(screen.getByTestId("code-block")).toBeInTheDocument(); + expect(screen.getByTestId("advanced-option-toggle")).toBeInTheDocument(); + expect(screen.getByTestId("copy-button")).toBeInTheDocument(); + expect(screen.getByTestId("copy-icon")).toBeInTheDocument(); + }); + + test("renders correct iframe code without embed mode", () => { + render(); + + const codeBlock = screen.getByTestId("code-block"); + expect(codeBlock).toBeInTheDocument(); + + const code = codeBlock.querySelector("pre")?.textContent; + expect(code).toContain(defaultProps.surveyUrl); + expect(code).toContain(" { + render(); + + const toggle = screen.getByTestId("embed-mode-toggle"); + await userEvent.click(toggle); + + const codeBlock = screen.getByTestId("code-block"); + const code = codeBlock.querySelector("pre")?.textContent; + expect(code).toContain('src="https://example.com/survey/123?embed=true"'); + }); + + test("toggle changes embed mode state", async () => { + render(); + + const toggle = screen.getByTestId("embed-mode-toggle"); + expect(toggle).not.toBeChecked(); + + await userEvent.click(toggle); + expect(toggle).toBeChecked(); + + await userEvent.click(toggle); + expect(toggle).not.toBeChecked(); + }); + + test("copy button copies iframe code to clipboard", async () => { + render(); + + const copyButton = screen.getByTestId("copy-button"); + await userEvent.click(copyButton); + + expect(navigator.clipboard.writeText).toHaveBeenCalledWith( + expect.stringContaining(defaultProps.surveyUrl) + ); + const toast = await import("react-hot-toast"); + expect(toast.default.success).toHaveBeenCalledWith( + "environments.surveys.summary.embed_code_copied_to_clipboard" + ); + }); + + test("copy button copies correct code with embed mode enabled", async () => { + render(); + + const toggle = screen.getByTestId("embed-mode-toggle"); + await userEvent.click(toggle); + + const copyButton = screen.getByTestId("copy-button"); + await userEvent.click(copyButton); + + expect(navigator.clipboard.writeText).toHaveBeenCalledWith(expect.stringContaining("?embed=true")); + }); + + test("renders code block with correct props", () => { + render(); + + expect(screen.getByTestId("language")).toHaveTextContent("html"); + expect(screen.getByTestId("show-copy")).toHaveTextContent("false"); + expect(screen.getByTestId("no-margin")).toBeInTheDocument(); + }); + + test("renders advanced option toggle with correct props", () => { + render(); + + const toggle = screen.getByTestId("advanced-option-toggle"); + expect(toggle).toHaveTextContent("environments.surveys.summary.embed_mode"); + expect(toggle).toHaveTextContent("environments.surveys.summary.embed_mode_description"); + expect(screen.getByTestId("custom-container-class")).toHaveTextContent("p-0"); + }); +}); diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteEmbedTab.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteEmbedTab.tsx new file mode 100644 index 0000000000..3480fe9c72 --- /dev/null +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteEmbedTab.tsx @@ -0,0 +1,57 @@ +"use client"; + +import { AdvancedOptionToggle } from "@/modules/ui/components/advanced-option-toggle"; +import { Button } from "@/modules/ui/components/button"; +import { CodeBlock } from "@/modules/ui/components/code-block"; +import { useTranslate } from "@tolgee/react"; +import { CopyIcon } from "lucide-react"; +import { useState } from "react"; +import toast from "react-hot-toast"; + +interface WebsiteEmbedTabProps { + surveyUrl: string; +} + +export const WebsiteEmbedTab = ({ surveyUrl }: WebsiteEmbedTabProps) => { + const [embedModeEnabled, setEmbedModeEnabled] = useState(false); + const { t } = useTranslate(); + + const iframeCode = `
+ +
`; + + return ( + <> +
+ + {iframeCode} + +
+ + + + ); +}; diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteTab.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteTab.test.tsx deleted file mode 100644 index 9902d1bb3b..0000000000 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteTab.test.tsx +++ /dev/null @@ -1,254 +0,0 @@ -import { cleanup, render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import toast from "react-hot-toast"; -import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; -import { WebsiteTab } from "./WebsiteTab"; - -// Mock child components and hooks -const mockAdvancedOptionToggle = vi.fn(); -vi.mock("@/modules/ui/components/advanced-option-toggle", () => ({ - AdvancedOptionToggle: (props: any) => { - mockAdvancedOptionToggle(props); - return ( -
- {props.title} - props.onToggle(!props.isChecked)} /> -
- ); - }, -})); - -vi.mock("@/modules/ui/components/button", () => ({ - Button: ({ children, onClick, ...props }: any) => ( - - ), -})); - -const mockCodeBlock = vi.fn(); -vi.mock("@/modules/ui/components/code-block", () => ({ - CodeBlock: (props: any) => { - mockCodeBlock(props); - return ( -
- {props.children} -
- ); - }, -})); - -const mockOptionsSwitch = vi.fn(); -vi.mock("@/modules/ui/components/options-switch", () => ({ - OptionsSwitch: (props: any) => { - mockOptionsSwitch(props); - return ( -
- {props.options.map((opt: { value: string; label: string }) => ( - - ))} -
- ); - }, -})); - -vi.mock("lucide-react", () => ({ - CopyIcon: () =>
, -})); - -vi.mock("next/link", () => ({ - default: ({ children, href, target }: { children: React.ReactNode; href: string; target?: string }) => ( - - {children} - - ), -})); - -const mockWriteText = vi.fn(); -Object.defineProperty(navigator, "clipboard", { - value: { - writeText: mockWriteText, - }, - configurable: true, -}); - -const surveyUrl = "https://app.formbricks.com/s/survey123"; -const environmentId = "env456"; - -describe("WebsiteTab", () => { - afterEach(() => { - cleanup(); - vi.clearAllMocks(); - }); - - test("renders OptionsSwitch and StaticTab by default", () => { - render(); - expect(screen.getByTestId("options-switch")).toBeInTheDocument(); - expect(mockOptionsSwitch).toHaveBeenCalledWith( - expect.objectContaining({ - currentOption: "static", - options: [ - { value: "static", label: "environments.surveys.summary.static_iframe" }, - { value: "popup", label: "environments.surveys.summary.dynamic_popup" }, - ], - }) - ); - // StaticTab content checks - expect(screen.getByText("common.copy_code")).toBeInTheDocument(); - expect(screen.getByTestId("code-block")).toBeInTheDocument(); - expect(screen.getByTestId("advanced-option-toggle")).toBeInTheDocument(); - expect(screen.getByText("environments.surveys.summary.static_iframe")).toBeInTheDocument(); - expect(screen.getByText("environments.surveys.summary.dynamic_popup")).toBeInTheDocument(); - }); - - test("switches to PopupTab when 'Dynamic Popup' option is clicked", async () => { - render(); - const popupButton = screen.getByRole("button", { - name: "environments.surveys.summary.dynamic_popup", - }); - await userEvent.click(popupButton); - - expect(mockOptionsSwitch.mock.calls.some((call) => call[0].currentOption === "popup")).toBe(true); - // PopupTab content checks - expect(screen.getByText("environments.surveys.summary.embed_pop_up_survey_title")).toBeInTheDocument(); - expect(screen.getByText("environments.surveys.summary.setup_instructions")).toBeInTheDocument(); - expect(screen.getByRole("list")).toBeInTheDocument(); // Check for the ol element - - const listItems = screen.getAllByRole("listitem"); - expect(listItems[0]).toHaveTextContent( - "common.follow_these environments.surveys.summary.setup_instructions environments.surveys.summary.to_connect_your_website_with_formbricks" - ); - expect(listItems[1]).toHaveTextContent( - "environments.surveys.summary.make_sure_the_survey_type_is_set_to common.website_survey" - ); - expect(listItems[2]).toHaveTextContent( - "environments.surveys.summary.define_when_and_where_the_survey_should_pop_up" - ); - - expect( - screen.getByRole("link", { name: "environments.surveys.summary.setup_instructions" }) - ).toHaveAttribute("href", `/environments/${environmentId}/project/website-connection`); - expect( - screen.getByText("environments.surveys.summary.unsupported_video_tag_warning").closest("video") - ).toBeInTheDocument(); - }); - - describe("StaticTab", () => { - const formattedBaseCode = `
\n \n
`; - const normalizedBaseCode = `
`; - - const formattedEmbedCode = `
\n \n
`; - const normalizedEmbedCode = `
`; - - test("renders correctly with initial iframe code and embed mode toggle", () => { - render(); // Defaults to StaticTab - - expect(screen.getByTestId("code-block")).toHaveTextContent(normalizedBaseCode); - expect(mockCodeBlock).toHaveBeenCalledWith( - expect.objectContaining({ children: formattedBaseCode, language: "html" }) - ); - - expect(screen.getByTestId("advanced-option-toggle")).toBeInTheDocument(); - expect(mockAdvancedOptionToggle).toHaveBeenCalledWith( - expect.objectContaining({ - isChecked: false, - title: "environments.surveys.summary.embed_mode", - description: "environments.surveys.summary.embed_mode_description", - }) - ); - expect(screen.getByText("environments.surveys.summary.embed_mode")).toBeInTheDocument(); - }); - - test("copies iframe code to clipboard when 'Copy Code' is clicked", async () => { - render(); - const copyButton = screen.getByRole("button", { name: "Embed survey in your website" }); - - await userEvent.click(copyButton); - - expect(mockWriteText).toHaveBeenCalledWith(formattedBaseCode); - expect(toast.success).toHaveBeenCalledWith( - "environments.surveys.summary.embed_code_copied_to_clipboard" - ); - expect(screen.getByText("common.copy_code")).toBeInTheDocument(); - }); - - test("updates iframe code when 'Embed Mode' is toggled", async () => { - render(); - const embedToggle = screen - .getByTestId("advanced-option-toggle") - .querySelector('input[type="checkbox"]'); - expect(embedToggle).not.toBeNull(); - - await userEvent.click(embedToggle!); - - expect(screen.getByTestId("code-block")).toHaveTextContent(normalizedEmbedCode); - expect(mockCodeBlock.mock.calls.find((call) => call[0].children === formattedEmbedCode)).toBeTruthy(); - expect(mockAdvancedOptionToggle.mock.calls.some((call) => call[0].isChecked === true)).toBe(true); - - // Toggle back - await userEvent.click(embedToggle!); - expect(screen.getByTestId("code-block")).toHaveTextContent(normalizedBaseCode); - expect(mockCodeBlock.mock.calls.find((call) => call[0].children === formattedBaseCode)).toBeTruthy(); - expect(mockAdvancedOptionToggle.mock.calls.some((call) => call[0].isChecked === false)).toBe(true); - }); - }); - - describe("PopupTab", () => { - beforeEach(async () => { - // Ensure PopupTab is active - render(); - const popupButton = screen.getByRole("button", { - name: "environments.surveys.summary.dynamic_popup", - }); - await userEvent.click(popupButton); - }); - - test("renders title and instructions", () => { - expect(screen.getByText("environments.surveys.summary.embed_pop_up_survey_title")).toBeInTheDocument(); - - const listItems = screen.getAllByRole("listitem"); - expect(listItems).toHaveLength(3); - expect(listItems[0]).toHaveTextContent( - "common.follow_these environments.surveys.summary.setup_instructions environments.surveys.summary.to_connect_your_website_with_formbricks" - ); - expect(listItems[1]).toHaveTextContent( - "environments.surveys.summary.make_sure_the_survey_type_is_set_to common.website_survey" - ); - expect(listItems[2]).toHaveTextContent( - "environments.surveys.summary.define_when_and_where_the_survey_should_pop_up" - ); - - // Specific checks for elements or distinct text content - expect(screen.getByText("environments.surveys.summary.setup_instructions")).toBeInTheDocument(); // Checks the link text - expect(screen.getByText("common.website_survey")).toBeInTheDocument(); // Checks the bold text - // The text for the last list item is its sole content, so getByText works here. - expect( - screen.getByText("environments.surveys.summary.define_when_and_where_the_survey_should_pop_up") - ).toBeInTheDocument(); - }); - - test("renders the setup instructions link with correct href", () => { - const link = screen.getByRole("link", { name: "environments.surveys.summary.setup_instructions" }); - expect(link).toBeInTheDocument(); - expect(link).toHaveAttribute("href", `/environments/${environmentId}/project/website-connection`); - expect(link).toHaveAttribute("target", "_blank"); - }); - - test("renders the video", () => { - const videoElement = screen - .getByText("environments.surveys.summary.unsupported_video_tag_warning") - .closest("video"); - expect(videoElement).toBeInTheDocument(); - expect(videoElement).toHaveAttribute("autoPlay"); - expect(videoElement).toHaveAttribute("loop"); - const sourceElement = videoElement?.querySelector("source"); - expect(sourceElement).toHaveAttribute("src", "/video/tooltips/change-survey-type.mp4"); - expect(sourceElement).toHaveAttribute("type", "video/mp4"); - expect( - screen.getByText("environments.surveys.summary.unsupported_video_tag_warning") - ).toBeInTheDocument(); - }); - }); -}); diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteTab.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteTab.tsx deleted file mode 100644 index 535e4c1c7f..0000000000 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/WebsiteTab.tsx +++ /dev/null @@ -1,118 +0,0 @@ -"use client"; - -import { AdvancedOptionToggle } from "@/modules/ui/components/advanced-option-toggle"; -import { Button } from "@/modules/ui/components/button"; -import { CodeBlock } from "@/modules/ui/components/code-block"; -import { OptionsSwitch } from "@/modules/ui/components/options-switch"; -import { useTranslate } from "@tolgee/react"; -import { CopyIcon } from "lucide-react"; -import Link from "next/link"; -import { useState } from "react"; -import toast from "react-hot-toast"; - -export const WebsiteTab = ({ surveyUrl, environmentId }) => { - const [selectedTab, setSelectedTab] = useState("static"); - const { t } = useTranslate(); - - return ( -
- setSelectedTab(value)} - /> - -
- {selectedTab === "static" ? ( - - ) : ( - - )} -
-
- ); -}; - -const StaticTab = ({ surveyUrl }) => { - const [embedModeEnabled, setEmbedModeEnabled] = useState(false); - const { t } = useTranslate(); - const iframeCode = `
- -
`; - - return ( -
-
-
- -
-
- - {iframeCode} - -
-
- -
-
- ); -}; - -const PopupTab = ({ environmentId }) => { - const { t } = useTranslate(); - return ( -
-

- {t("environments.surveys.summary.embed_pop_up_survey_title")} -

-
    -
  1. - {t("common.follow_these")}{" "} - - {t("environments.surveys.summary.setup_instructions")} - {" "} - {t("environments.surveys.summary.to_connect_your_website_with_formbricks")} -
  2. -
  3. - {t("environments.surveys.summary.make_sure_the_survey_type_is_set_to")}{" "} - {t("common.website_survey")} -
  4. -
  5. {t("environments.surveys.summary.define_when_and_where_the_survey_should_pop_up")}
  6. -
-
- -
-
- ); -}; diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.test.tsx index 1d7f764f1d..6c1a1145ba 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.test.tsx @@ -22,16 +22,30 @@ vi.mock("./LinkTab", () => ({
), })); -vi.mock("./WebsiteTab", () => ({ - WebsiteTab: (props: { surveyUrl: string; environmentId: string }) => ( -
- WebsiteTab Content for {props.surveyUrl} in {props.environmentId} +vi.mock("./WebsiteEmbedTab", () => ({ + WebsiteEmbedTab: (props: { surveyUrl: string }) => ( +
WebsiteEmbedTab Content for {props.surveyUrl}
+ ), +})); +vi.mock("./DynamicPopupTab", () => ({ + DynamicPopupTab: (props: { environmentId: string; surveyId: string }) => ( +
+ DynamicPopupTab Content for {props.surveyId} in {props.environmentId} +
+ ), +})); +vi.mock("./TabContainer", () => ({ + TabContainer: (props: { children: React.ReactNode; title: string; description: string }) => ( +
+
{props.title}
+
{props.description}
+ {props.children}
), })); vi.mock("./personal-links-tab", () => ({ - PersonalLinksTab: (props: { segments: any[]; surveyId: string; environmentId: string }) => ( + PersonalLinksTab: (props: { surveyId: string; environmentId: string }) => (
PersonalLinksTab Content for {props.surveyId} in {props.environmentId}
@@ -39,7 +53,7 @@ vi.mock("./personal-links-tab", () => ({ })); vi.mock("@/modules/ui/components/upgrade-prompt", () => ({ - UpgradePrompt: (props: { title: string; description: string; buttons: any[] }) => ( + UpgradePrompt: (props: { title: string; description: string }) => (
{props.title} - {props.description}
@@ -53,6 +67,7 @@ vi.mock("lucide-react", () => ({ LinkIcon: () =>
LinkIcon
, GlobeIcon: () =>
GlobeIcon
, SmartphoneIcon: () =>
SmartphoneIcon
, + CheckCircle2Icon: () =>
CheckCircle2Icon
, AlertCircle: ({ className }: { className?: string }) => (
AlertCircle @@ -132,7 +147,8 @@ vi.mock("@/lib/cn", () => ({ const mockTabs = [ { id: "email", label: "Email", icon: () =>
}, - { id: "webpage", label: "Web Page", icon: () =>
}, + { id: "website-embed", label: "Website Embed", icon: () =>
}, + { id: "dynamic-popup", label: "Dynamic Popup", icon: () =>
}, { id: "link", label: "Link", icon: () =>
}, { id: "app", label: "App", icon: () =>
}, ]; @@ -268,9 +284,9 @@ describe("ShareView", () => { test("calls setActiveId when a tab is clicked (desktop)", async () => { render(); - const webpageTabButton = screen.getByLabelText("Web Page"); - await userEvent.click(webpageTabButton); - expect(defaultProps.setActiveId).toHaveBeenCalledWith("webpage"); + const websiteEmbedTabButton = screen.getByLabelText("Website Embed"); + await userEvent.click(websiteEmbedTabButton); + expect(defaultProps.setActiveId).toHaveBeenCalledWith("website-embed"); }); test("renders EmailTab when activeId is 'email'", () => { @@ -281,11 +297,21 @@ describe("ShareView", () => { ).toBeInTheDocument(); }); - test("renders WebsiteTab when activeId is 'webpage'", () => { - render(); - expect(screen.getByTestId("website-tab")).toBeInTheDocument(); + test("renders WebsiteEmbedTab when activeId is 'website-embed'", () => { + render(); + expect(screen.getByTestId("tab-container")).toBeInTheDocument(); + expect(screen.getByTestId("website-embed-tab")).toBeInTheDocument(); + expect(screen.getByText(`WebsiteEmbedTab Content for ${defaultProps.surveyUrl}`)).toBeInTheDocument(); + }); + + test("renders DynamicPopupTab when activeId is 'dynamic-popup'", () => { + render(); + expect(screen.getByTestId("tab-container")).toBeInTheDocument(); + expect(screen.getByTestId("dynamic-popup-tab")).toBeInTheDocument(); expect( - screen.getByText(`WebsiteTab Content for ${defaultProps.surveyUrl} in ${defaultProps.environmentId}`) + screen.getByText( + `DynamicPopupTab Content for ${defaultProps.survey.id} in ${defaultProps.environmentId}` + ) ).toBeInTheDocument(); }); @@ -316,7 +342,7 @@ describe("ShareView", () => { render(); // Get responsive buttons - these are Button components containing icons - const responsiveButtons = screen.getAllByTestId("webpage-tab-icon"); + const responsiveButtons = screen.getAllByTestId("website-embed-tab-icon"); // The responsive button should be the one inside the md:hidden container const responsiveButton = responsiveButtons .find((icon) => { @@ -327,7 +353,7 @@ describe("ShareView", () => { if (responsiveButton) { await userEvent.click(responsiveButton); - expect(defaultProps.setActiveId).toHaveBeenCalledWith("webpage"); + expect(defaultProps.setActiveId).toHaveBeenCalledWith("website-embed"); } }); @@ -339,9 +365,9 @@ describe("ShareView", () => { expect(emailTabButton).toHaveClass("font-medium"); expect(emailTabButton).toHaveClass("text-slate-900"); - const webpageTabButton = screen.getByLabelText("Web Page"); - expect(webpageTabButton).not.toHaveClass("bg-slate-100"); - expect(webpageTabButton).not.toHaveClass("font-medium"); + const websiteEmbedTabButton = screen.getByLabelText("Website Embed"); + expect(websiteEmbedTabButton).not.toHaveClass("bg-slate-100"); + expect(websiteEmbedTabButton).not.toHaveClass("font-medium"); }); test("applies active styles to the active tab (responsive)", () => { @@ -361,16 +387,18 @@ describe("ShareView", () => { expect(responsiveEmailButton).toHaveClass("bg-white text-slate-900 shadow-sm hover:bg-white"); } - const responsiveWebpageButtons = screen.getAllByTestId("webpage-tab-icon"); - const responsiveWebpageButton = responsiveWebpageButtons + const responsiveWebsiteEmbedButtons = screen.getAllByTestId("website-embed-tab-icon"); + const responsiveWebsiteEmbedButton = responsiveWebsiteEmbedButtons .find((icon) => { const button = icon.closest("button"); return button && button.getAttribute("data-variant") === "ghost"; }) ?.closest("button"); - if (responsiveWebpageButton) { - expect(responsiveWebpageButton).toHaveClass("border-transparent text-slate-700 hover:text-slate-900"); + if (responsiveWebsiteEmbedButton) { + expect(responsiveWebsiteEmbedButton).toHaveClass( + "border-transparent text-slate-700 hover:text-slate-900" + ); } }); }); diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.tsx index 955e42c08b..8163c0ce23 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.tsx @@ -1,5 +1,7 @@ "use client"; +import { DynamicPopupTab } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/DynamicPopupTab"; +import { TabContainer } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/TabContainer"; import { cn } from "@/lib/cn"; import { Button } from "@/modules/ui/components/button"; import { @@ -15,6 +17,7 @@ import { } from "@/modules/ui/components/sidebar"; import { TooltipRenderer } from "@/modules/ui/components/tooltip"; import { Small } from "@/modules/ui/components/typography"; +import { useTranslate } from "@tolgee/react"; import { useEffect, useState } from "react"; import { TSegment } from "@formbricks/types/segment"; import { TSurvey } from "@formbricks/types/surveys/types"; @@ -22,7 +25,7 @@ import { TUserLocale } from "@formbricks/types/user"; import { AppTab } from "./AppTab"; import { EmailTab } from "./EmailTab"; import { LinkTab } from "./LinkTab"; -import { WebsiteTab } from "./WebsiteTab"; +import { WebsiteEmbedTab } from "./WebsiteEmbedTab"; import { PersonalLinksTab } from "./personal-links-tab"; interface ShareViewProps { @@ -57,6 +60,7 @@ export const ShareView = ({ isFormbricksCloud, }: ShareViewProps) => { const [isLargeScreen, setIsLargeScreen] = useState(true); + const { t } = useTranslate(); useEffect(() => { const checkScreenSize = () => { @@ -74,8 +78,22 @@ export const ShareView = ({ switch (activeId) { case "email": return ; - case "webpage": - return ; + case "website-embed": + return ( + + + + ); + case "dynamic-popup": + return ( + + + + ); case "link": return ( { const alertElement = screen.getByRole("alert"); expect(alertElement).toHaveClass("my-custom-class"); }); + + test("applies correct styles to anchor tags inside alert variants", () => { + render( + + Info Alert with Link + This alert has a link + + Test Link + + + ); + + const alertElement = screen.getByRole("alert"); + expect(alertElement).toHaveClass("text-info-foreground"); + expect(alertElement).toHaveClass("border-info/50"); + + const linkElement = screen.getByRole("link", { name: "Test Link" }); + expect(linkElement).toBeInTheDocument(); + }); + + test("applies correct styles to anchor tags in AlertButton with asChild", () => { + render( + + Error Alert + This alert has a button link + + Take Action + + + ); + + const alertElement = screen.getByRole("alert"); + expect(alertElement).toHaveClass("text-error-foreground"); + expect(alertElement).toHaveClass("border-error/50"); + + const linkElement = screen.getByRole("link", { name: "Take Action" }); + expect(linkElement).toBeInTheDocument(); + }); + + test("applies styles for all alert variants with anchor tags", () => { + const variants = ["error", "warning", "info", "success"] as const; + + variants.forEach((variant) => { + const { unmount } = render( + + {variant} Alert + Alert with anchor tag + + Link + + + ); + + const alertElement = screen.getByRole("alert"); + expect(alertElement).toHaveClass(`text-${variant}-foreground`); + expect(alertElement).toHaveClass(`border-${variant}/50`); + + const linkElement = screen.getByTestId(`${variant}-link`); + expect(linkElement).toBeInTheDocument(); + + unmount(); + }); + }); }); diff --git a/apps/web/modules/ui/components/alert/index.tsx b/apps/web/modules/ui/components/alert/index.tsx index 7f84e11968..b40ec6f95d 100644 --- a/apps/web/modules/ui/components/alert/index.tsx +++ b/apps/web/modules/ui/components/alert/index.tsx @@ -26,12 +26,12 @@ const alertVariants = cva("relative w-full rounded-lg border [&>svg]:size-4", { variant: { default: "text-foreground border-border", error: - "text-error-foreground [&>svg]:text-error border-error/50 [&_button]:bg-error-background [&_button]:text-error-foreground [&_button:hover]:bg-error-background-muted", + "text-error-foreground [&>svg]:text-error border-error/50 [&_button]:bg-error-background [&_button]:text-error-foreground [&_button:hover]:bg-error-background-muted [&_a]:bg-error-background [&_a]:text-error-foreground [&_a:hover]:bg-error-background-muted", warning: - "text-warning-foreground [&>svg]:text-warning border-warning/50 [&_button]:bg-warning-background [&_button]:text-warning-foreground [&_button:hover]:bg-warning-background-muted", - info: "text-info-foreground [&>svg]:text-info border-info/50 [&_button]:bg-info-background [&_button]:text-info-foreground [&_button:hover]:bg-info-background-muted", + "text-warning-foreground [&>svg]:text-warning border-warning/50 [&_button]:bg-warning-background [&_button]:text-warning-foreground [&_button:hover]:bg-warning-background-muted [&_a]:bg-warning-background [&_a]:text-warning-foreground [&_a:hover]:bg-warning-background-muted", + info: "text-info-foreground [&>svg]:text-info border-info/50 [&_button]:bg-info-background [&_button]:text-info-foreground [&_button:hover]:bg-info-background-muted [&_a]:bg-info-background [&_a]:text-info-foreground [&_a:hover]:bg-info-background-muted", success: - "text-success-foreground [&>svg]:text-success border-success/50 [&_button]:bg-success-background [&_button]:text-success-foreground [&_button:hover]:bg-success-background-muted", + "text-success-foreground [&>svg]:text-success border-success/50 [&_button]:bg-success-background [&_button]:text-success-foreground [&_button:hover]:bg-success-background-muted [&_a]:bg-success-background [&_a]:text-success-foreground [&_a:hover]:bg-success-background-muted", }, size: { default: diff --git a/apps/web/modules/ui/components/code-block/index.test.tsx b/apps/web/modules/ui/components/code-block/index.test.tsx index 13a7cb76e9..3f60eb73ab 100644 --- a/apps/web/modules/ui/components/code-block/index.test.tsx +++ b/apps/web/modules/ui/components/code-block/index.test.tsx @@ -118,4 +118,39 @@ describe("CodeBlock", () => { expect(codeElement).toHaveClass(`language-${language}`); expect(codeElement).toHaveClass(customCodeClass); }); + + test("applies no margin class when noMargin is true", () => { + const codeSnippet = "const test = 'no margin';"; + const language = "javascript"; + render( + + {codeSnippet} + + ); + + const containerElement = screen.getByText(codeSnippet).closest("div"); + expect(containerElement).not.toHaveClass("mt-4"); + }); + + test("applies default margin class when noMargin is false", () => { + const codeSnippet = "const test = 'with margin';"; + const language = "javascript"; + render( + + {codeSnippet} + + ); + + const containerElement = screen.getByText(codeSnippet).closest("div"); + expect(containerElement).toHaveClass("mt-4"); + }); + + test("applies default margin class when noMargin is undefined", () => { + const codeSnippet = "const test = 'default margin';"; + const language = "javascript"; + render({codeSnippet}); + + const containerElement = screen.getByText(codeSnippet).closest("div"); + expect(containerElement).toHaveClass("mt-4"); + }); }); diff --git a/apps/web/modules/ui/components/code-block/index.tsx b/apps/web/modules/ui/components/code-block/index.tsx index be1cefccf7..2be2420510 100644 --- a/apps/web/modules/ui/components/code-block/index.tsx +++ b/apps/web/modules/ui/components/code-block/index.tsx @@ -15,6 +15,7 @@ interface CodeBlockProps { customCodeClass?: string; customEditorClass?: string; showCopyToClipboard?: boolean; + noMargin?: boolean; } export const CodeBlock = ({ @@ -23,6 +24,7 @@ export const CodeBlock = ({ customEditorClass = "", customCodeClass = "", showCopyToClipboard = true, + noMargin = false, }: CodeBlockProps) => { const { t } = useTranslate(); useEffect(() => { @@ -30,7 +32,7 @@ export const CodeBlock = ({ }, [children]); return ( -
+
{showCopyToClipboard && (
{ expect(h3Element).toBeInTheDocument(); expect(h3Element).toHaveTextContent("Heading 3"); - expect(h3Element?.className).toContain("text-2xl"); - expect(h3Element?.className).toContain("font-semibold"); + expect(h3Element?.className).toContain("text-lg"); + expect(h3Element?.className).toContain("tracking-tight"); expect(h3Element?.className).toContain("text-slate-800"); }); @@ -49,8 +49,8 @@ describe("Typography Components", () => { expect(h4Element).toBeInTheDocument(); expect(h4Element).toHaveTextContent("Heading 4"); - expect(h4Element?.className).toContain("text-xl"); - expect(h4Element?.className).toContain("font-semibold"); + expect(h4Element?.className).toContain("text-base"); + expect(h4Element?.className).toContain("tracking-tight"); expect(h4Element?.className).toContain("text-slate-800"); }); @@ -75,12 +75,11 @@ describe("Typography Components", () => { test("renders Large correctly", () => { const { container } = render(Large text); - const divElement = container.querySelector("div"); + const pElement = container.querySelector("p"); - expect(divElement).toBeInTheDocument(); - expect(divElement).toHaveTextContent("Large text"); - expect(divElement?.className).toContain("text-lg"); - expect(divElement?.className).toContain("font-semibold"); + expect(pElement).toBeInTheDocument(); + expect(pElement).toHaveTextContent("Large text"); + expect(pElement?.className).toContain("text-lg"); }); test("renders Small correctly", () => { @@ -90,6 +89,8 @@ describe("Typography Components", () => { expect(pElement).toBeInTheDocument(); expect(pElement).toHaveTextContent("Small text"); expect(pElement?.className).toContain("text-sm"); + expect(pElement?.className).toContain("leading-none"); + expect(pElement?.className).toContain("text-slate-800"); expect(pElement?.className).toContain("font-medium"); }); diff --git a/apps/web/modules/ui/components/typography/index.tsx b/apps/web/modules/ui/components/typography/index.tsx index e003fa89ac..f2170064d3 100644 --- a/apps/web/modules/ui/components/typography/index.tsx +++ b/apps/web/modules/ui/components/typography/index.tsx @@ -1,4 +1,5 @@ import { cn } from "@/modules/ui/lib/utils"; +import { cva } from "class-variance-authority"; import React, { forwardRef } from "react"; const H1 = forwardRef>((props, ref) => { @@ -40,7 +41,7 @@ const H3 = forwardRef + className={cn("scroll-m-20 text-lg tracking-tight text-slate-800", props.className)}> {props.children} ); @@ -54,7 +55,7 @@ const H4 = forwardRef + className={cn("scroll-m-20 text-base tracking-tight text-slate-800", props.className)}> {props.children} ); @@ -87,18 +88,53 @@ export { P }; const Large = forwardRef>((props, ref) => { return ( -
+

{props.children} -

+

); }); Large.displayName = "Large"; export { Large }; -const Small = forwardRef>((props, ref) => { +const Base = forwardRef>((props, ref) => { return ( -

+

+ {props.children} +

+ ); +}); + +Base.displayName = "Base"; +export { Base }; + +const smallVariants = cva("text-sm leading-none", { + variants: { + color: { + default: "text-slate-800 font-medium", + muted: "text-slate-500", + }, + margin: { + default: "mt-0", + headerDescription: "mt-1", + }, + }, +}); + +interface SmallProps extends React.HTMLAttributes { + color?: "default" | "muted"; + margin?: "default" | "headerDescription"; +} + +const Small = forwardRef((props, ref) => { + return ( +

{props.children}

); diff --git a/docs/images/xm-and-surveys/surveys/link-surveys/embed-surveys/embed-mode-toggle.webp b/docs/images/xm-and-surveys/surveys/link-surveys/embed-surveys/embed-mode-toggle.webp index 661e76177b151932e7992b88152d2074d04e3ccf..2c43fe71acaad70d70ecc244eb54ffdd16a69bdf 100644 GIT binary patch literal 18744 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