Compare commits

...

1 Commits

Author SHA1 Message Date
Piyush Gupta
6cb52a11f4 email embed sharing modal 2025-07-11 17:45:44 +05:30
8 changed files with 127 additions and 108 deletions

View File

@@ -63,7 +63,7 @@ export const ShareSurveyModal = ({
},
{
id: ShareViewType.EMAIL,
label: t("environments.surveys.summary.embed_in_an_email"),
label: t("environments.surveys.summary.email_embed"),
icon: MailIcon,
},
{

View File

@@ -4,8 +4,9 @@ import { getFormattedErrorMessage } from "@/lib/utils/helper";
import { Button } from "@/modules/ui/components/button";
import { CodeBlock } from "@/modules/ui/components/code-block";
import { LoadingSpinner } from "@/modules/ui/components/loading-spinner";
import { OptionsSwitch } from "@/modules/ui/components/options-switch";
import { useTranslate } from "@tolgee/react";
import { Code2Icon, CopyIcon, MailIcon } from "lucide-react";
import { CopyIcon, MailIcon } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import toast from "react-hot-toast";
import { AuthenticationError } from "@formbricks/types/errors";
@@ -16,26 +17,16 @@ interface EmailTabProps {
email: string;
}
export const EmailTab = ({ surveyId, email }: EmailTabProps) => {
const [showEmbed, setShowEmbed] = useState(false);
const [emailHtmlPreview, setEmailHtmlPreview] = useState<string>("");
const PreviewTab = ({
emailHtmlPreview,
email,
surveyId,
}: {
emailHtmlPreview: string;
email: string;
surveyId: string;
}) => {
const { t } = useTranslate();
const emailHtml = useMemo(() => {
if (!emailHtmlPreview) return "";
return emailHtmlPreview
.replaceAll("?preview=true&amp;", "?")
.replaceAll("?preview=true&;", "?")
.replaceAll("?preview=true", "");
}, [emailHtmlPreview]);
useEffect(() => {
const getData = async () => {
const emailHtml = await getEmailHtmlAction({ surveyId });
setEmailHtmlPreview(emailHtml?.data || "");
};
getData();
}, [surveyId]);
const sendPreviewEmail = async () => {
try {
@@ -56,77 +47,105 @@ export const EmailTab = ({ surveyId, email }: EmailTabProps) => {
};
return (
<div className="flex flex-col gap-5">
<div className="flex items-center justify-end gap-4">
{showEmbed ? (
<Button
variant="secondary"
title="Embed survey in your website"
aria-label="Embed survey in your website"
onClick={() => {
toast.success(t("environments.surveys.summary.embed_code_copied_to_clipboard"));
navigator.clipboard.writeText(emailHtml);
}}
className="shrink-0">
{t("common.copy_code")}
<CopyIcon />
</Button>
) : (
<>
<Button
variant="secondary"
title="send preview email"
aria-label="send preview email"
onClick={() => sendPreviewEmail()}
className="shrink-0">
{t("environments.surveys.summary.send_preview")}
<MailIcon />
</Button>
</>
)}
<Button
title={t("environments.surveys.summary.view_embed_code_for_email")}
aria-label={t("environments.surveys.summary.view_embed_code_for_email")}
onClick={() => {
setShowEmbed(!showEmbed);
}}
className="shrink-0">
{showEmbed
? t("environments.surveys.summary.hide_embed_code")
: t("environments.surveys.summary.view_embed_code")}
<Code2Icon />
</Button>
<div className="space-y-4">
<div className="grow overflow-y-auto rounded-xl border border-slate-200 bg-white p-4">
<div className="mb-6 flex gap-2">
<div className="h-3 w-3 rounded-full bg-red-500"></div>
<div className="h-3 w-3 rounded-full bg-amber-500"></div>
<div className="h-3 w-3 rounded-full bg-emerald-500"></div>
</div>
<div>
<div className="mb-2 border-b border-slate-200 pb-2 text-sm">To : {email || "user@mail.com"}</div>
<div className="border-b border-slate-200 pb-2 text-sm">
Subject : {t("environments.surveys.summary.formbricks_email_survey_preview")}
</div>
<div className="p-4">
{emailHtmlPreview ? (
<div dangerouslySetInnerHTML={{ __html: emailHtmlPreview }}></div>
) : (
<LoadingSpinner />
)}
</div>
</div>
</div>
{showEmbed ? (
<div className="prose prose-slate -mt-4 max-w-full">
<CodeBlock
customCodeClass="text-sm h-48 overflow-y-scroll"
language="html"
showCopyToClipboard={false}>
{emailHtml}
</CodeBlock>
</div>
<Button
variant="default"
title="send preview email"
aria-label="send preview email"
onClick={() => sendPreviewEmail()}
className="shrink-0">
{t("environments.surveys.summary.send_preview")}
<MailIcon />
</Button>
</div>
);
};
const EmbedCodeTab = ({ emailHtml }: { emailHtml: string }) => {
const { t } = useTranslate();
return (
<div className="space-y-4">
<div className="prose prose-slate -mt-4 max-w-full">
<CodeBlock
customCodeClass="text-sm h-48 overflow-y-scroll"
language="html"
showCopyToClipboard={false}>
{emailHtml}
</CodeBlock>
</div>
<Button
variant="default"
title="Embed survey in your website"
aria-label="Embed survey in your website"
onClick={() => {
toast.success(t("environments.surveys.summary.embed_code_copied_to_clipboard"));
navigator.clipboard.writeText(emailHtml);
}}
className="shrink-0">
{t("common.copy_code")}
<CopyIcon />
</Button>
</div>
);
};
export const EmailTab = ({ surveyId, email }: EmailTabProps) => {
const [emailHtmlPreview, setEmailHtmlPreview] = useState<string>("");
const [selectedTab, setSelectedTab] = useState("preview");
const { t } = useTranslate();
const emailHtml = useMemo(() => {
if (!emailHtmlPreview) return "";
return emailHtmlPreview
.replaceAll("?preview=true&amp;", "?")
.replaceAll("?preview=true&;", "?")
.replaceAll("?preview=true", "");
}, [emailHtmlPreview]);
useEffect(() => {
const getData = async () => {
const emailHtml = await getEmailHtmlAction({ surveyId });
setEmailHtmlPreview(emailHtml?.data || "");
};
getData();
}, [surveyId]);
return (
<div className="flex max-h-full flex-col gap-4">
<OptionsSwitch
options={[
{ value: "preview", label: t("environments.surveys.summary.preview") },
{ value: "embed", label: t("environments.surveys.summary.embed_code") },
]}
currentOption={selectedTab}
handleOptionChange={(value) => setSelectedTab(value)}
/>
{selectedTab === "preview" ? (
<PreviewTab emailHtmlPreview={emailHtmlPreview} email={email} surveyId={surveyId} />
) : (
<div className="mb-12 grow overflow-y-auto rounded-xl border border-slate-200 bg-white p-4">
<div className="mb-6 flex gap-2">
<div className="h-3 w-3 rounded-full bg-red-500"></div>
<div className="h-3 w-3 rounded-full bg-amber-500"></div>
<div className="h-3 w-3 rounded-full bg-emerald-500"></div>
</div>
<div>
<div className="mb-2 border-b border-slate-200 pb-2 text-sm">To : {email || "user@mail.com"}</div>
<div className="border-b border-slate-200 pb-2 text-sm">
Subject : {t("environments.surveys.summary.formbricks_email_survey_preview")}
</div>
<div className="p-4">
{emailHtml ? (
<div dangerouslySetInnerHTML={{ __html: emailHtmlPreview }}></div>
) : (
<LoadingSpinner />
)}
</div>
</div>
</div>
<EmbedCodeTab emailHtml={emailHtml} />
)}
</div>
);

View File

@@ -1723,15 +1723,15 @@
"drop_offs": "Drop-Off Rate",
"drop_offs_tooltip": "So oft wurde die Umfrage gestartet, aber nicht abgeschlossen.",
"dynamic_popup": "Dynamisch (Pop-up)",
"email_embed": "E-Mail-Einbettung",
"email_sent": "E-Mail gesendet!",
"embed_code": "Einbettungscode",
"embed_code_copied_to_clipboard": "Einbettungscode in die Zwischenablage kopiert!",
"embed_in_an_email": "In eine E-Mail einbetten",
"embed_in_app": "In App einbetten",
"embed_mode": "Einbettungsmodus",
"embed_mode_description": "Bette deine Umfrage mit einem minimalistischen Design ein, ohne Karten und Hintergrund.",
"embed_on_website": "Auf Website einbetten",
"embed_pop_up_survey_title": "Wie man eine Pop-up-Umfrage auf seiner Website einbindet",
"embed_survey": "Umfrage einbetten",
"expiry_date_description": "Sobald der Link abläuft, kann der Empfänger nicht mehr auf die Umfrage antworten.",
"expiry_date_optional": "Ablaufdatum (optional)",
"failed_to_copy_link": "Kopieren des Links fehlgeschlagen",
@@ -1773,6 +1773,7 @@
"personal_links_upgrade_prompt_description": "Erstellen Sie persönliche Links für ein Segment und verknüpfen Sie Umfrageantworten mit jedem Kontakt.",
"personal_links_upgrade_prompt_title": "Verwende persönliche Links mit einem höheren Plan",
"personal_links_work_with_segments": "Persönliche Links funktionieren mit Segmenten.",
"preview": "Vorschau",
"publish_to_web": "Im Web veröffentlichen",
"publish_to_web_warning": "Du bist dabei, diese Umfrageergebnisse öffentlich zugänglich zu machen.",
"publish_to_web_warning_description": "Deine Umfrageergebnisse werden öffentlich sein. Jeder außerhalb deiner Organisation kann darauf zugreifen, wenn er den Link hat.",
@@ -1785,7 +1786,6 @@
"selected_responses_csv": "Ausgewählte Antworten (CSV)",
"selected_responses_excel": "Ausgewählte Antworten (Excel)",
"send_preview": "Vorschau senden",
"send_to_panel": "An das Panel senden",
"setup_instructions": "Einrichtung",
"setup_integrations": "Integrationen einrichten",
"share_results": "Ergebnisse teilen",

View File

@@ -1723,15 +1723,15 @@
"drop_offs": "Drop-Offs",
"drop_offs_tooltip": "Number of times the survey has been started but not completed.",
"dynamic_popup": "Dynamic (Pop-up)",
"email_embed": "Email embed",
"email_sent": "Email sent!",
"embed_code": "Embed code",
"embed_code_copied_to_clipboard": "Embed code copied to clipboard!",
"embed_in_an_email": "Embed in an email",
"embed_in_app": "Embed in app",
"embed_mode": "Embed Mode",
"embed_mode_description": "Embed your survey with a minimalist design, discarding padding and background.",
"embed_on_website": "Embed on website",
"embed_pop_up_survey_title": "How to embed a pop-up survey on your website",
"embed_survey": "Embed survey",
"expiry_date_description": "Once the link expires, the recipient cannot respond to survey any longer.",
"expiry_date_optional": "Expiry date (optional)",
"failed_to_copy_link": "Failed to copy link",
@@ -1773,6 +1773,7 @@
"personal_links_upgrade_prompt_description": "Generate personal links for a segment and link survey responses to each contact.",
"personal_links_upgrade_prompt_title": "Use personal links with a higher plan",
"personal_links_work_with_segments": "Personal links work with segments.",
"preview": "Preview",
"publish_to_web": "Publish to web",
"publish_to_web_warning": "You are about to release these survey results to the public.",
"publish_to_web_warning_description": "Your survey results will be public. Anyone outside your organization can access them if they have the link.",
@@ -1785,7 +1786,6 @@
"selected_responses_csv": "Selected responses (CSV)",
"selected_responses_excel": "Selected responses (Excel)",
"send_preview": "Send preview",
"send_to_panel": "Send to panel",
"setup_instructions": "Setup instructions",
"setup_integrations": "Setup integrations",
"share_results": "Share results",

View File

@@ -1723,15 +1723,15 @@
"drop_offs": "Dépôts",
"drop_offs_tooltip": "Nombre de fois que l'enquête a été commencée mais non terminée.",
"dynamic_popup": "Dynamique (Pop-up)",
"email_embed": "Email intégré",
"email_sent": "Email envoyé !",
"embed_code": "Code d'intégration",
"embed_code_copied_to_clipboard": "Code d'intégration copié dans le presse-papiers !",
"embed_in_an_email": "Inclure dans un e-mail",
"embed_in_app": "Intégrer dans l'application",
"embed_mode": "Mode d'intégration",
"embed_mode_description": "Intégrez votre enquête avec un design minimaliste, en supprimant les marges et l'arrière-plan.",
"embed_on_website": "Incorporer sur le site web",
"embed_pop_up_survey_title": "Comment intégrer une enquête pop-up sur votre site web",
"embed_survey": "Intégrer l'enquête",
"expiry_date_description": "Une fois le lien expiré, le destinataire ne peut plus répondre au sondage.",
"expiry_date_optional": "Date d'expiration (facultatif)",
"failed_to_copy_link": "Échec de la copie du lien",
@@ -1773,6 +1773,7 @@
"personal_links_upgrade_prompt_description": "Générez des liens personnels pour un segment et associez les réponses du sondage à chaque contact.",
"personal_links_upgrade_prompt_title": "Utilisez des liens personnels avec un plan supérieur",
"personal_links_work_with_segments": "Les liens personnels fonctionnent avec les segments.",
"preview": "Aperçu",
"publish_to_web": "Publier sur le web",
"publish_to_web_warning": "Vous êtes sur le point de rendre ces résultats d'enquête publics.",
"publish_to_web_warning_description": "Les résultats de votre enquête seront publics. Toute personne en dehors de votre organisation pourra y accéder si elle a le lien.",
@@ -1785,7 +1786,6 @@
"selected_responses_csv": "Réponses sélectionnées (CSV)",
"selected_responses_excel": "Réponses sélectionnées (Excel)",
"send_preview": "Envoyer un aperçu",
"send_to_panel": "Envoyer au panneau",
"setup_instructions": "Instructions d'installation",
"setup_integrations": "Configurer les intégrations",
"share_results": "Partager les résultats",

View File

@@ -1723,15 +1723,15 @@
"drop_offs": "Pontos de Entrega",
"drop_offs_tooltip": "Número de vezes que a pesquisa foi iniciada mas não concluída.",
"dynamic_popup": "Dinâmico (Pop-up)",
"email_embed": "Incorporação de Email",
"email_sent": "Email enviado!",
"embed_code": "Código de incorporação",
"embed_code_copied_to_clipboard": "Código incorporado copiado para a área de transferência!",
"embed_in_an_email": "Incorporar em um e-mail",
"embed_in_app": "Integrar no app",
"embed_mode": "Modo Embutido",
"embed_mode_description": "Incorpore sua pesquisa com um design minimalista, sem preenchimento e fundo.",
"embed_on_website": "Incorporar no site",
"embed_pop_up_survey_title": "Como incorporar uma pesquisa pop-up no seu site",
"embed_survey": "Incorporar pesquisa",
"expiry_date_description": "Quando o link expirar, o destinatário não poderá mais responder à pesquisa.",
"expiry_date_optional": "Data de expiração (opcional)",
"failed_to_copy_link": "Falha ao copiar link",
@@ -1773,6 +1773,7 @@
"personal_links_upgrade_prompt_description": "Gerar links pessoais para um segmento e vincular respostas de pesquisa a cada contato.",
"personal_links_upgrade_prompt_title": "Use links pessoais com um plano superior",
"personal_links_work_with_segments": "Links pessoais funcionam com segmentos.",
"preview": "Prévia",
"publish_to_web": "Publicar na web",
"publish_to_web_warning": "Você está prestes a divulgar esses resultados da pesquisa para o público.",
"publish_to_web_warning_description": "Os resultados da sua pesquisa serão públicos. Qualquer pessoa fora da sua organização pode acessá-los se tiver o link.",
@@ -1785,7 +1786,6 @@
"selected_responses_csv": "Respostas selecionadas (CSV)",
"selected_responses_excel": "Respostas selecionadas (Excel)",
"send_preview": "Enviar prévia",
"send_to_panel": "Enviar para o painel",
"setup_instructions": "Instruções de configuração",
"setup_integrations": "Configurar integrações",
"share_results": "Compartilhar resultados",

View File

@@ -1723,15 +1723,15 @@
"drop_offs": "Desistências",
"drop_offs_tooltip": "Número de vezes que o inquérito foi iniciado mas não concluído.",
"dynamic_popup": "Dinâmico (Pop-up)",
"email_embed": "Incorporação de Email",
"email_sent": "Email enviado!",
"embed_code": "Código de incorporação",
"embed_code_copied_to_clipboard": "Código incorporado copiado para a área de transferência!",
"embed_in_an_email": "Incorporar num email",
"embed_in_app": "Incorporar na aplicação",
"embed_mode": "Modo de Incorporação",
"embed_mode_description": "Incorpore o seu inquérito com um design minimalista, descartando o preenchimento e o fundo.",
"embed_on_website": "Incorporar no site",
"embed_pop_up_survey_title": "Como incorporar um questionário pop-up no seu site",
"embed_survey": "Incorporar inquérito",
"expiry_date_description": "Uma vez que o link expira, o destinatário não pode mais responder ao questionário.",
"expiry_date_optional": "Data de expiração (opcional)",
"failed_to_copy_link": "Falha ao copiar link",
@@ -1773,6 +1773,7 @@
"personal_links_upgrade_prompt_description": "Gerar links pessoais para um segmento e associar as respostas do inquérito a cada contacto.",
"personal_links_upgrade_prompt_title": "Utilize links pessoais com um plano superior",
"personal_links_work_with_segments": "Os links pessoais funcionam com segmentos.",
"preview": "Pré-visualização",
"publish_to_web": "Publicar na web",
"publish_to_web_warning": "Está prestes a divulgar estes resultados do inquérito ao público.",
"publish_to_web_warning_description": "Os resultados do seu inquérito serão públicos. Qualquer pessoa fora da sua organização pode aceder a eles se tiver o link.",
@@ -1785,7 +1786,6 @@
"selected_responses_csv": "Respostas selecionadas (CSV)",
"selected_responses_excel": "Respostas selecionadas (Excel)",
"send_preview": "Enviar pré-visualização",
"send_to_panel": "Enviar para painel",
"setup_instructions": "Instruções de configuração",
"setup_integrations": "Configurar integrações",
"share_results": "Partilhar resultados",

View File

@@ -1723,15 +1723,15 @@
"drop_offs": "放棄",
"drop_offs_tooltip": "問卷已開始但未完成的次數。",
"dynamic_popup": "動態(彈窗)",
"email_embed": "電子郵件嵌入",
"email_sent": "已發送電子郵件!",
"embed_code": "嵌入程式碼",
"embed_code_copied_to_clipboard": "嵌入程式碼已複製到剪貼簿!",
"embed_in_an_email": "嵌入電子郵件中",
"embed_in_app": "嵌入應用程式",
"embed_mode": "嵌入模式",
"embed_mode_description": "以簡約設計嵌入您的問卷,捨棄邊距和背景。",
"embed_on_website": "嵌入網站",
"embed_pop_up_survey_title": "如何在您的網站上嵌入彈出式問卷",
"embed_survey": "嵌入問卷",
"expiry_date_description": "一旦連結過期,收件者將無法再回應 survey。",
"expiry_date_optional": "到期日 (可選)",
"failed_to_copy_link": "無法複製連結",
@@ -1773,6 +1773,7 @@
"personal_links_upgrade_prompt_description": "為一個群組生成個人連結,並將調查回應連結到每個聯絡人。",
"personal_links_upgrade_prompt_title": "使用 個人 連結 與 更高 的 計劃",
"personal_links_work_with_segments": "個人 連結 可 與 分段 一起 使用",
"preview": "預覽",
"publish_to_web": "發布至網站",
"publish_to_web_warning": "您即將將這些問卷結果發布到公共領域。",
"publish_to_web_warning_description": "您的問卷結果將會是公開的。任何組織外的人員都可以存取這些結果(如果他們有連結)。",
@@ -1785,7 +1786,6 @@
"selected_responses_csv": "選擇的回應 (CSV)",
"selected_responses_excel": "選擇的回應 (Excel)",
"send_preview": "發送預覽",
"send_to_panel": "發送到小組",
"setup_instructions": "設定說明",
"setup_integrations": "設定整合",
"share_results": "分享結果",