mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-23 05:17:49 -05:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b50605058 | |||
| a736436e29 | |||
| 7dbb0300d3 |
+2
-2
@@ -1910,9 +1910,9 @@ checksums:
|
|||||||
s/want_to_respond: fbb26054f6af3b625cb569e19063302f
|
s/want_to_respond: fbb26054f6af3b625cb569e19063302f
|
||||||
setup/intro/get_started: 5c783951b0100a168bdd2161ff294833
|
setup/intro/get_started: 5c783951b0100a168bdd2161ff294833
|
||||||
setup/intro/made_with_love_in_kiel: 1bbdd6e93bcdf7cbfbcac16db448a2e4
|
setup/intro/made_with_love_in_kiel: 1bbdd6e93bcdf7cbfbcac16db448a2e4
|
||||||
setup/intro/paragraph_1: 360c902da0db044c6cc346ac18099902
|
setup/intro/paragraph_1: 41e6a1e7c9a4a1922c7064a89f6733fd
|
||||||
setup/intro/paragraph_2: 5b3cce4d8c75bab4d671e2af7fc7ee9f
|
setup/intro/paragraph_2: 5b3cce4d8c75bab4d671e2af7fc7ee9f
|
||||||
setup/intro/paragraph_3: 0675e53f2f48e3a04db6e52698bdebae
|
setup/intro/paragraph_3: 5bf4718d4c44ff27e55e0880331f293d
|
||||||
setup/intro/welcome_to_formbricks: 561427153e3effa108f54407dfc2126f
|
setup/intro/welcome_to_formbricks: 561427153e3effa108f54407dfc2126f
|
||||||
setup/invite/add_another_member: 02947deaa4710893794f3cc6e160c2b4
|
setup/invite/add_another_member: 02947deaa4710893794f3cc6e160c2b4
|
||||||
setup/invite/continue: 3cfba90b4600131e82fc4260c568d044
|
setup/invite/continue: 3cfba90b4600131e82fc4260c568d044
|
||||||
|
|||||||
@@ -2048,7 +2048,7 @@
|
|||||||
"made_with_love_in_kiel": "Gebaut mit 🤍 in Deutschland",
|
"made_with_love_in_kiel": "Gebaut mit 🤍 in Deutschland",
|
||||||
"paragraph_1": "Formbricks ist eine Experience Management Suite, die auf der <b>am schnellsten wachsenden Open-Source-Umfrageplattform</b> weltweit basiert.",
|
"paragraph_1": "Formbricks ist eine Experience Management Suite, die auf der <b>am schnellsten wachsenden Open-Source-Umfrageplattform</b> weltweit basiert.",
|
||||||
"paragraph_2": "Führe gezielte Umfragen auf Websites, in Apps oder überall online durch. Sammle wertvolle Insights, um unwiderstehliche Erlebnisse für Kunden, Nutzer und Mitarbeiter zu gestalten.",
|
"paragraph_2": "Führe gezielte Umfragen auf Websites, in Apps oder überall online durch. Sammle wertvolle Insights, um unwiderstehliche Erlebnisse für Kunden, Nutzer und Mitarbeiter zu gestalten.",
|
||||||
"paragraph_3": "Wir schreiben DATENSCHUTZ groß (ha!). Hoste Formbricks selbst, um <b>volle Kontrolle über deine Daten</b> zu behalten.",
|
"paragraph_3": "Wir verpflichten uns zu höchstem Datenschutz. Hosten Sie selbst, um die <b>volle Kontrolle über Ihre Daten</b> zu behalten.",
|
||||||
"welcome_to_formbricks": "Willkommen bei Formbricks!"
|
"welcome_to_formbricks": "Willkommen bei Formbricks!"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -2046,9 +2046,9 @@
|
|||||||
"intro": {
|
"intro": {
|
||||||
"get_started": "Get started",
|
"get_started": "Get started",
|
||||||
"made_with_love_in_kiel": "Made with \uD83E\uDD0D in Germany",
|
"made_with_love_in_kiel": "Made with \uD83E\uDD0D in Germany",
|
||||||
"paragraph_1": "Formbricks is an Experience Management Suite built of the <b>fastest growing open source survey platform</b> worldwide.",
|
"paragraph_1": "Formbricks is an Experience Management Suite built on the <b>fastest growing open-source survey platform</b> worldwide.",
|
||||||
"paragraph_2": "Run targeted surveys on websites, in apps or anywhere online. Gather valuable insights to <b>craft irresistible experiences</b> for customers, users and employees.",
|
"paragraph_2": "Run targeted surveys on websites, in apps or anywhere online. Gather valuable insights to <b>craft irresistible experiences</b> for customers, users and employees.",
|
||||||
"paragraph_3": "We're commited to highest degree of data privacy. Self-host to keep <b>full control over your data</b>.",
|
"paragraph_3": "We're committed to the highest degree of data privacy. Self-host to keep <b>full control over your data</b>.",
|
||||||
"welcome_to_formbricks": "Welcome to Formbricks!"
|
"welcome_to_formbricks": "Welcome to Formbricks!"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -2046,9 +2046,9 @@
|
|||||||
"intro": {
|
"intro": {
|
||||||
"get_started": "Comenzar",
|
"get_started": "Comenzar",
|
||||||
"made_with_love_in_kiel": "Hecho con 🤍 en Alemania",
|
"made_with_love_in_kiel": "Hecho con 🤍 en Alemania",
|
||||||
"paragraph_1": "Formbricks es una Suite de Gestión de Experiencia construida sobre la <b>plataforma de encuestas de código abierto de más rápido crecimiento</b> en todo el mundo.",
|
"paragraph_1": "Formbricks es una suite de gestión de experiencias construida sobre la <b>plataforma de encuestas de código abierto de más rápido crecimiento</b> a nivel mundial.",
|
||||||
"paragraph_2": "Realiza encuestas dirigidas en sitios web, en aplicaciones o en cualquier lugar online. Recopila información valiosa para <b>crear experiencias irresistibles</b> para clientes, usuarios y empleados.",
|
"paragraph_2": "Realiza encuestas dirigidas en sitios web, en aplicaciones o en cualquier lugar online. Recopila información valiosa para <b>crear experiencias irresistibles</b> para clientes, usuarios y empleados.",
|
||||||
"paragraph_3": "Estamos comprometidos con el más alto grado de privacidad de datos. Alójalo tú mismo para mantener <b>control total sobre tus datos</b>.",
|
"paragraph_3": "Estamos comprometidos con el más alto grado de privacidad de datos. Aloja en tu propio servidor para mantener el <b>control total sobre tus datos</b>.",
|
||||||
"welcome_to_formbricks": "¡Bienvenido a Formbricks!"
|
"welcome_to_formbricks": "¡Bienvenido a Formbricks!"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -2046,9 +2046,9 @@
|
|||||||
"intro": {
|
"intro": {
|
||||||
"get_started": "Commencer",
|
"get_started": "Commencer",
|
||||||
"made_with_love_in_kiel": "Fabriqué avec 🤍 en Allemagne",
|
"made_with_love_in_kiel": "Fabriqué avec 🤍 en Allemagne",
|
||||||
"paragraph_1": "Formbricks est une suite de gestion de l'expérience construite sur la <b>plateforme d'enquête open source à la croissance la plus rapide</b> au monde.",
|
"paragraph_1": "Formbricks est une suite de gestion de l'expérience construite sur la <b>plateforme de sondage open-source à la croissance la plus rapide</b> au monde.",
|
||||||
"paragraph_2": "Réalisez des enquêtes ciblées sur des sites web, dans des applications ou partout en ligne. Collectez des informations précieuses pour <b>créer des expériences irrésistibles</b> pour les clients, les utilisateurs et les employés.",
|
"paragraph_2": "Réalisez des enquêtes ciblées sur des sites web, dans des applications ou partout en ligne. Collectez des informations précieuses pour <b>créer des expériences irrésistibles</b> pour les clients, les utilisateurs et les employés.",
|
||||||
"paragraph_3": "Nous sommes engagés à garantir le plus haut niveau de confidentialité des données. Auto-hébergez pour garder <b>le contrôle total sur vos données</b>. Toujours.",
|
"paragraph_3": "Nous nous engageons à respecter le plus haut degré de confidentialité des données. Auto-hébergez pour garder <b>le contrôle total de vos données</b>.",
|
||||||
"welcome_to_formbricks": "Bienvenue sur Formbricks !"
|
"welcome_to_formbricks": "Bienvenue sur Formbricks !"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -2046,9 +2046,9 @@
|
|||||||
"intro": {
|
"intro": {
|
||||||
"get_started": "始める",
|
"get_started": "始める",
|
||||||
"made_with_love_in_kiel": "キールで愛を込めて作られました 🤍",
|
"made_with_love_in_kiel": "キールで愛を込めて作られました 🤍",
|
||||||
"paragraph_1": "Formbricksは、世界で<b>最も急速に成長しているオープンソースのフォームプラットフォーム</b>から構築されたエクスペリエンス管理スイートです。",
|
"paragraph_1": "Formbricksは、世界で<b>最も急成長しているオープンソースのアンケートプラットフォーム</b>をベースに構築されたエクスペリエンス管理スイートです。",
|
||||||
"paragraph_2": "ウェブサイト、アプリ、またはオンラインのどこでもターゲットを絞ったフォームを実行できます。貴重な洞察を収集して、顧客、ユーザー、従業員向けの<b>魅力的な体験</b>を作り出します。",
|
"paragraph_2": "ウェブサイト、アプリ、またはオンラインのどこでもターゲットを絞ったフォームを実行できます。貴重な洞察を収集して、顧客、ユーザー、従業員向けの<b>魅力的な体験</b>を作り出します。",
|
||||||
"paragraph_3": "私たちは、最高のデータプライバシーを約束します。セルフホストして、<b>データを完全に制御</b>できます。",
|
"paragraph_3": "私たちは最高レベルのデータプライバシーを重視しています。セルフホスティングにより、<b>データを完全に管理</b>できます。",
|
||||||
"welcome_to_formbricks": "Formbricksへようこそ!"
|
"welcome_to_formbricks": "Formbricksへようこそ!"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -2046,9 +2046,9 @@
|
|||||||
"intro": {
|
"intro": {
|
||||||
"get_started": "Ga aan de slag",
|
"get_started": "Ga aan de slag",
|
||||||
"made_with_love_in_kiel": "Gemaakt met 🤍 in Duitsland",
|
"made_with_love_in_kiel": "Gemaakt met 🤍 in Duitsland",
|
||||||
"paragraph_1": "Formbricks is een Experience Management Suite die is gebouwd op het <b>snelst groeiende open source enquêteplatform</b> wereldwijd.",
|
"paragraph_1": "Formbricks is een Experience Management Suite gebouwd op het <b>snelst groeiende open-source enquêteplatform</b> wereldwijd.",
|
||||||
"paragraph_2": "Voer gerichte enquêtes uit op websites, in apps of waar dan ook online. Verzamel waardevolle inzichten om <b>onweerstaanbare ervaringen te creëren</b> voor klanten, gebruikers en medewerkers.",
|
"paragraph_2": "Voer gerichte enquêtes uit op websites, in apps of waar dan ook online. Verzamel waardevolle inzichten om <b>onweerstaanbare ervaringen te creëren</b> voor klanten, gebruikers en medewerkers.",
|
||||||
"paragraph_3": "We streven naar de hoogste mate van gegevensprivacy. Zelfhosting om <b>volledige controle over uw gegevens</b> te behouden.",
|
"paragraph_3": "We zijn toegewijd aan de hoogste mate van gegevensprivacy. Self-host om <b>volledige controle over je gegevens</b> te behouden.",
|
||||||
"welcome_to_formbricks": "Welkom bij Formbricks!"
|
"welcome_to_formbricks": "Welkom bij Formbricks!"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -2046,9 +2046,9 @@
|
|||||||
"intro": {
|
"intro": {
|
||||||
"get_started": "Começar",
|
"get_started": "Começar",
|
||||||
"made_with_love_in_kiel": "Feito com 🤍 em Alemanha",
|
"made_with_love_in_kiel": "Feito com 🤍 em Alemanha",
|
||||||
"paragraph_1": "Formbricks é uma suíte de gerenciamento de experiência construída na <b>plataforma de pesquisa open source que mais cresce</b> no mundo.",
|
"paragraph_1": "Formbricks é uma suíte de gerenciamento de experiência construída sobre a <b>plataforma de pesquisa de código aberto de crescimento mais rápido</b> do mundo.",
|
||||||
"paragraph_2": "Faça pesquisas direcionadas em sites, apps ou em qualquer lugar online. Recolha insights valiosos para criar experiências irresistíveis para clientes, usuários e funcionários.",
|
"paragraph_2": "Faça pesquisas direcionadas em sites, apps ou em qualquer lugar online. Recolha insights valiosos para criar experiências irresistíveis para clientes, usuários e funcionários.",
|
||||||
"paragraph_3": "Estamos comprometidos com o mais alto nível de privacidade de dados. Hospede você mesmo para manter <b>controle total sobre seus dados</b>. Sempre",
|
"paragraph_3": "Estamos comprometidos com o mais alto grau de privacidade de dados. Hospede você mesmo para manter <b>controle total sobre seus dados</b>.",
|
||||||
"welcome_to_formbricks": "Bem-vindo ao Formbricks!"
|
"welcome_to_formbricks": "Bem-vindo ao Formbricks!"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -2046,9 +2046,9 @@
|
|||||||
"intro": {
|
"intro": {
|
||||||
"get_started": "Começar",
|
"get_started": "Começar",
|
||||||
"made_with_love_in_kiel": "Feito com 🤍 na Alemanha",
|
"made_with_love_in_kiel": "Feito com 🤍 na Alemanha",
|
||||||
"paragraph_1": "Formbricks é uma Suite de Gestão de Experiência construída na <b>plataforma de inquéritos de código aberto de crescimento mais rápido</b> do mundo.",
|
"paragraph_1": "Formbricks é uma Suite de Gestão de Experiência construída na <b>plataforma de inquéritos open-source de crescimento mais rápido</b> a nível mundial.",
|
||||||
"paragraph_2": "Execute inquéritos direcionados em websites, em apps ou em qualquer lugar online. Recolha informações valiosas para <b>criar experiências irresistíveis</b> para clientes, utilizadores e funcionários.",
|
"paragraph_2": "Execute inquéritos direcionados em websites, em apps ou em qualquer lugar online. Recolha informações valiosas para <b>criar experiências irresistíveis</b> para clientes, utilizadores e funcionários.",
|
||||||
"paragraph_3": "Estamos comprometidos com o mais alto grau de privacidade de dados. Auto-hospede para manter <b>controlo total sobre os seus dados</b>.",
|
"paragraph_3": "Estamos comprometidos com o mais alto grau de privacidade de dados. Faça self-host para manter <b>controlo total sobre os seus dados</b>.",
|
||||||
"welcome_to_formbricks": "Bem-vindo ao Formbricks!"
|
"welcome_to_formbricks": "Bem-vindo ao Formbricks!"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -2046,9 +2046,9 @@
|
|||||||
"intro": {
|
"intro": {
|
||||||
"get_started": "Începeți",
|
"get_started": "Începeți",
|
||||||
"made_with_love_in_kiel": "Creat cu 🤍 în Germania",
|
"made_with_love_in_kiel": "Creat cu 🤍 în Germania",
|
||||||
"paragraph_1": "Formbricks este o suită de management al experiențelor construită pe baza <b>platformei de sondaje open source care crește cel mai rapid</b> din lume.",
|
"paragraph_1": "Formbricks este o suită de management al experienței construită pe <b>cea mai rapidă platformă open-source de sondaje</b> din lume.",
|
||||||
"paragraph_2": "Rulați sondaje direcționate pe site-uri web, în aplicații sau oriunde online. Adunați informații valoroase pentru a <b>crea experiențe irezistibile</b> pentru clienți, utilizatori și angajați.",
|
"paragraph_2": "Rulați sondaje direcționate pe site-uri web, în aplicații sau oriunde online. Adunați informații valoroase pentru a <b>crea experiențe irezistibile</b> pentru clienți, utilizatori și angajați.",
|
||||||
"paragraph_3": "Suntem angajați la cel mai înalt grad de confidențialitate a datelor. Găzduirea proprie vă oferă <b>control deplin asupra datelor dumneavoastră</b>.",
|
"paragraph_3": "Suntem dedicați celui mai înalt nivel de confidențialitate a datelor. Găzduiește local pentru a păstra <b>controlul deplin asupra datelor tale</b>.",
|
||||||
"welcome_to_formbricks": "Bine ai venit la Formbricks!"
|
"welcome_to_formbricks": "Bine ai venit la Formbricks!"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -2046,9 +2046,9 @@
|
|||||||
"intro": {
|
"intro": {
|
||||||
"get_started": "Kom igång",
|
"get_started": "Kom igång",
|
||||||
"made_with_love_in_kiel": "Gjort med 🤍 i Tyskland",
|
"made_with_love_in_kiel": "Gjort med 🤍 i Tyskland",
|
||||||
"paragraph_1": "Formbricks är en Experience Management Suite byggd av den <b>snabbast växande öppenkällkods enkätplattformen</b> i världen.",
|
"paragraph_1": "Formbricks är en Experience Management Suite byggd på den <b>snabbast växande open source-enkätplattformen</b> i världen.",
|
||||||
"paragraph_2": "Kör riktade enkäter på webbplatser, i appar eller var som helst online. Samla värdefulla insikter för att <b>skapa oemotståndliga upplevelser</b> för kunder, användare och anställda.",
|
"paragraph_2": "Kör riktade enkäter på webbplatser, i appar eller var som helst online. Samla värdefulla insikter för att <b>skapa oemotståndliga upplevelser</b> för kunder, användare och anställda.",
|
||||||
"paragraph_3": "Vi är engagerade i högsta grad av dataintegritet. Självhosta för att behålla <b>full kontroll över dina data</b>.",
|
"paragraph_3": "Vi är engagerade i högsta möjliga datasekretess. Självhosta för att behålla <b>full kontroll över dina data</b>.",
|
||||||
"welcome_to_formbricks": "Välkommen till Formbricks!"
|
"welcome_to_formbricks": "Välkommen till Formbricks!"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -2046,9 +2046,9 @@
|
|||||||
"intro": {
|
"intro": {
|
||||||
"get_started": "开始使用",
|
"get_started": "开始使用",
|
||||||
"made_with_love_in_kiel": "以 🤍 在 德国 制作",
|
"made_with_love_in_kiel": "以 🤍 在 德国 制作",
|
||||||
"paragraph_1": "Formbricks 是一个体验管理套件, 基于全球<b>增长最快的开源调查平台</b>构建。",
|
"paragraph_1": "Formbricks 是一款体验管理套件,基于全球<b>增长最快的开源调研平台</b>构建。",
|
||||||
"paragraph_2": "在网站、应用程序或任何在线平台上运行 定向 调查。收集 有价值 的见解,为客户、用户和员工<b>打造 无法抗拒 的体验</b>。",
|
"paragraph_2": "在网站、应用程序或任何在线平台上运行 定向 调查。收集 有价值 的见解,为客户、用户和员工<b>打造 无法抗拒 的体验</b>。",
|
||||||
"paragraph_3": "我们致力于最高级别的数据隐私。 自行托管以保持<b>对您的数据的完全控制</b>。",
|
"paragraph_3": "我们致力于最高级别的数据隐私保护。自建部署,<b>全面掌控您的数据</b>。",
|
||||||
"welcome_to_formbricks": "欢迎来到 Formbricks !"
|
"welcome_to_formbricks": "欢迎来到 Formbricks !"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -2046,9 +2046,9 @@
|
|||||||
"intro": {
|
"intro": {
|
||||||
"get_started": "開始使用",
|
"get_started": "開始使用",
|
||||||
"made_with_love_in_kiel": "用 🤍 在德國製造",
|
"made_with_love_in_kiel": "用 🤍 在德國製造",
|
||||||
"paragraph_1": "Formbricks 是一套體驗管理套件,建立於全球<b>成長最快的開源問卷平台</b>之上。",
|
"paragraph_1": "Formbricks 是一套體驗管理工具,建構於全球<b>成長最快的開源問卷平台</b>之上。",
|
||||||
"paragraph_2": "在網站、應用程式或線上任何地方執行目標問卷。收集寶貴的洞察,為客戶、使用者和員工<b>打造無法抗拒的體驗</b>。",
|
"paragraph_2": "在網站、應用程式或線上任何地方執行目標問卷。收集寶貴的洞察,為客戶、使用者和員工<b>打造無法抗拒的體驗</b>。",
|
||||||
"paragraph_3": "我們致力於最高程度的資料隱私權。自行託管以<b>完全掌控您的資料</b>。",
|
"paragraph_3": "我們致力於最高等級的資料隱私。自我託管,讓您<b>完全掌控您的資料</b>。",
|
||||||
"welcome_to_formbricks": "歡迎使用 Formbricks!"
|
"welcome_to_formbricks": "歡迎使用 Formbricks!"
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ interface EditWelcomeCardProps {
|
|||||||
setSelectedLanguageCode: (languageCode: string) => void;
|
setSelectedLanguageCode: (languageCode: string) => void;
|
||||||
locale: TUserLocale;
|
locale: TUserLocale;
|
||||||
isStorageConfigured: boolean;
|
isStorageConfigured: boolean;
|
||||||
|
isExternalUrlsAllowed?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EditWelcomeCard = ({
|
export const EditWelcomeCard = ({
|
||||||
@@ -34,6 +35,7 @@ export const EditWelcomeCard = ({
|
|||||||
setSelectedLanguageCode,
|
setSelectedLanguageCode,
|
||||||
locale,
|
locale,
|
||||||
isStorageConfigured = true,
|
isStorageConfigured = true,
|
||||||
|
isExternalUrlsAllowed,
|
||||||
}: EditWelcomeCardProps) => {
|
}: EditWelcomeCardProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -65,7 +67,7 @@ export const EditWelcomeCard = ({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
open ? "bg-slate-50" : "",
|
open ? "bg-slate-50" : "",
|
||||||
"flex w-10 items-center justify-center rounded-l-lg border-b border-l border-t group-aria-expanded:rounded-bl-none",
|
"flex w-10 items-center justify-center rounded-l-lg border-t border-b border-l group-aria-expanded:rounded-bl-none",
|
||||||
isInvalid ? "bg-red-400" : "bg-white group-hover:bg-slate-50"
|
isInvalid ? "bg-red-400" : "bg-white group-hover:bg-slate-50"
|
||||||
)}>
|
)}>
|
||||||
<Hand className="h-4 w-4" />
|
<Hand className="h-4 w-4" />
|
||||||
@@ -135,6 +137,7 @@ export const EditWelcomeCard = ({
|
|||||||
setSelectedLanguageCode={setSelectedLanguageCode}
|
setSelectedLanguageCode={setSelectedLanguageCode}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
isStorageConfigured={isStorageConfigured}
|
isStorageConfigured={isStorageConfigured}
|
||||||
|
isExternalUrlsAllowed={isExternalUrlsAllowed}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
@@ -150,6 +153,7 @@ export const EditWelcomeCard = ({
|
|||||||
setSelectedLanguageCode={setSelectedLanguageCode}
|
setSelectedLanguageCode={setSelectedLanguageCode}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
isStorageConfigured={isStorageConfigured}
|
isStorageConfigured={isStorageConfigured}
|
||||||
|
isExternalUrlsAllowed={isExternalUrlsAllowed}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -170,6 +174,7 @@ export const EditWelcomeCard = ({
|
|||||||
label={t("environments.surveys.edit.next_button_label")}
|
label={t("environments.surveys.edit.next_button_label")}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
isStorageConfigured={isStorageConfigured}
|
isStorageConfigured={isStorageConfigured}
|
||||||
|
isExternalUrlsAllowed={isExternalUrlsAllowed}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -808,6 +808,7 @@ export const ElementsView = ({
|
|||||||
selectedLanguageCode={selectedLanguageCode}
|
selectedLanguageCode={selectedLanguageCode}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
isStorageConfigured={isStorageConfigured}
|
isStorageConfigured={isStorageConfigured}
|
||||||
|
isExternalUrlsAllowed={isExternalUrlsAllowed}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -42,22 +42,27 @@ const setup = async (setupConfig: TConfigInput): Promise<void> => {
|
|||||||
|
|
||||||
const setUserId = async (userId: string): Promise<void> => {
|
const setUserId = async (userId: string): Promise<void> => {
|
||||||
await queue.add(User.setUserId, CommandType.UserAction, true, userId);
|
await queue.add(User.setUserId, CommandType.UserAction, true, userId);
|
||||||
|
await queue.wait();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setEmail = async (email: string): Promise<void> => {
|
const setEmail = async (email: string): Promise<void> => {
|
||||||
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { email });
|
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { email });
|
||||||
|
await queue.wait();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setAttribute = async (key: string, value: string): Promise<void> => {
|
const setAttribute = async (key: string, value: string): Promise<void> => {
|
||||||
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { [key]: value });
|
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { [key]: value });
|
||||||
|
await queue.wait();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setAttributes = async (attributes: Record<string, string>): Promise<void> => {
|
const setAttributes = async (attributes: Record<string, string>): Promise<void> => {
|
||||||
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, attributes);
|
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, attributes);
|
||||||
|
await queue.wait();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setLanguage = async (language: string): Promise<void> => {
|
const setLanguage = async (language: string): Promise<void> => {
|
||||||
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { language });
|
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { language });
|
||||||
|
await queue.wait();
|
||||||
};
|
};
|
||||||
|
|
||||||
const logout = async (): Promise<void> => {
|
const logout = async (): Promise<void> => {
|
||||||
|
|||||||
@@ -1,12 +1,25 @@
|
|||||||
|
import { Logger } from "@/lib/common/logger";
|
||||||
import { UpdateQueue } from "@/lib/user/update-queue";
|
import { UpdateQueue } from "@/lib/user/update-queue";
|
||||||
import { type NetworkError, type Result, okVoid } from "@/types/error";
|
import { type NetworkError, type Result, err, okVoid } from "@/types/error";
|
||||||
|
|
||||||
export const setAttributes = async (
|
export const setAttributes = async (
|
||||||
attributes: Record<string, string>
|
attributes: Record<string, string>
|
||||||
// eslint-disable-next-line @typescript-eslint/require-await -- we want to use promises here
|
|
||||||
): Promise<Result<void, NetworkError>> => {
|
): Promise<Result<void, NetworkError>> => {
|
||||||
|
const logger = Logger.getInstance();
|
||||||
const updateQueue = UpdateQueue.getInstance();
|
const updateQueue = UpdateQueue.getInstance();
|
||||||
updateQueue.updateAttributes(attributes);
|
updateQueue.updateAttributes(attributes);
|
||||||
void updateQueue.processUpdates();
|
try {
|
||||||
return okVoid();
|
await updateQueue.processUpdates();
|
||||||
|
return okVoid();
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(
|
||||||
|
`Failed to process attribute updates: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||||
|
);
|
||||||
|
return err({
|
||||||
|
code: "network_error",
|
||||||
|
message: "Failed to sync attributes",
|
||||||
|
responseMessage: error instanceof Error ? error.message : "Unknown error",
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,16 @@ vi.mock("@/lib/user/update-queue", () => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Mock the Logger
|
||||||
|
vi.mock("@/lib/common/logger", () => ({
|
||||||
|
Logger: {
|
||||||
|
getInstance: vi.fn(() => ({
|
||||||
|
error: vi.fn(),
|
||||||
|
debug: vi.fn(),
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
describe("User Attributes", () => {
|
describe("User Attributes", () => {
|
||||||
const mockUpdateQueue = {
|
const mockUpdateQueue = {
|
||||||
updateAttributes: vi.fn(),
|
updateAttributes: vi.fn(),
|
||||||
@@ -32,6 +42,8 @@ describe("User Attributes", () => {
|
|||||||
|
|
||||||
describe("setAttributes", () => {
|
describe("setAttributes", () => {
|
||||||
test("successfully updates attributes and triggers processing", async () => {
|
test("successfully updates attributes and triggers processing", async () => {
|
||||||
|
mockUpdateQueue.processUpdates.mockResolvedValue(undefined);
|
||||||
|
|
||||||
const result = await setAttributes(mockAttributes);
|
const result = await setAttributes(mockAttributes);
|
||||||
|
|
||||||
// Verify UpdateQueue methods were called correctly
|
// Verify UpdateQueue methods were called correctly
|
||||||
@@ -43,6 +55,8 @@ describe("User Attributes", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("processes multiple attribute updates", async () => {
|
test("processes multiple attribute updates", async () => {
|
||||||
|
mockUpdateQueue.processUpdates.mockResolvedValue(undefined);
|
||||||
|
|
||||||
const firstAttributes = { name: mockAttributes.name };
|
const firstAttributes = { name: mockAttributes.name };
|
||||||
const secondAttributes = { email: mockAttributes.email };
|
const secondAttributes = { email: mockAttributes.email };
|
||||||
|
|
||||||
@@ -55,22 +69,35 @@ describe("User Attributes", () => {
|
|||||||
expect(mockUpdateQueue.processUpdates).toHaveBeenCalledTimes(2);
|
expect(mockUpdateQueue.processUpdates).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("processes updates asynchronously", async () => {
|
test("waits for processUpdates to complete", async () => {
|
||||||
const attributes = { name: mockAttributes.name };
|
const attributes = { name: mockAttributes.name };
|
||||||
|
let processUpdatesResolved = false;
|
||||||
|
|
||||||
// Mock processUpdates to be async
|
// Mock processUpdates to be async and set a flag when resolved
|
||||||
mockUpdateQueue.processUpdates.mockImplementation(
|
mockUpdateQueue.processUpdates.mockImplementation(
|
||||||
() =>
|
() =>
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
setTimeout(resolve, 100);
|
setTimeout(() => {
|
||||||
|
processUpdatesResolved = true;
|
||||||
|
resolve(undefined);
|
||||||
|
}, 100);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = await setAttributes(attributes);
|
const resultPromise = setAttributes(attributes);
|
||||||
|
|
||||||
expect(result.ok).toBe(true);
|
// Verify processUpdates was called
|
||||||
expect(mockUpdateQueue.processUpdates).toHaveBeenCalled();
|
expect(mockUpdateQueue.processUpdates).toHaveBeenCalled();
|
||||||
// The function returns before processUpdates completes due to void operator
|
|
||||||
|
// Verify the function hasn't resolved yet
|
||||||
|
expect(processUpdatesResolved).toBe(false);
|
||||||
|
|
||||||
|
// Wait for setAttributes to complete
|
||||||
|
const result = await resultPromise;
|
||||||
|
|
||||||
|
// Verify it completed after processUpdates
|
||||||
|
expect(processUpdatesResolved).toBe(true);
|
||||||
|
expect(result.ok).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ describe("user.ts", () => {
|
|||||||
|
|
||||||
const mockUpdateQueue = {
|
const mockUpdateQueue = {
|
||||||
updateUserId: vi.fn(),
|
updateUserId: vi.fn(),
|
||||||
processUpdates: vi.fn(),
|
processUpdates: vi.fn().mockResolvedValue(undefined),
|
||||||
};
|
};
|
||||||
|
|
||||||
getInstanceConfigMock.mockReturnValue(mockConfig as unknown as Config);
|
getInstanceConfigMock.mockReturnValue(mockConfig as unknown as Config);
|
||||||
@@ -113,6 +113,42 @@ describe("user.ts", () => {
|
|||||||
expect(mockUpdateQueue.updateUserId).toHaveBeenCalledWith(mockUserId);
|
expect(mockUpdateQueue.updateUserId).toHaveBeenCalledWith(mockUserId);
|
||||||
expect(mockUpdateQueue.processUpdates).toHaveBeenCalled();
|
expect(mockUpdateQueue.processUpdates).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("returns error if processUpdates fails", async () => {
|
||||||
|
const mockConfig = {
|
||||||
|
get: vi.fn().mockReturnValue({
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
userId: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockLogger = {
|
||||||
|
debug: vi.fn(),
|
||||||
|
error: vi.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockUpdateQueue = {
|
||||||
|
updateUserId: vi.fn(),
|
||||||
|
processUpdates: vi.fn().mockRejectedValue(new Error("Network error")),
|
||||||
|
};
|
||||||
|
|
||||||
|
getInstanceConfigMock.mockReturnValue(mockConfig as unknown as Config);
|
||||||
|
getInstanceLoggerMock.mockReturnValue(mockLogger as unknown as Logger);
|
||||||
|
getInstanceUpdateQueueMock.mockReturnValue(mockUpdateQueue as unknown as UpdateQueue);
|
||||||
|
const result = await setUserId(mockUserId);
|
||||||
|
|
||||||
|
expect(result.ok).toBe(false);
|
||||||
|
if (!result.ok) {
|
||||||
|
expect(result.error.code).toBe("network_error");
|
||||||
|
expect(result.error.status).toBe(500);
|
||||||
|
}
|
||||||
|
expect(mockUpdateQueue.updateUserId).toHaveBeenCalledWith(mockUserId);
|
||||||
|
expect(mockUpdateQueue.processUpdates).toHaveBeenCalled();
|
||||||
|
expect(mockLogger.error).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("logout", () => {
|
describe("logout", () => {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { tearDown } from "@/lib/common/setup";
|
|||||||
import { UpdateQueue } from "@/lib/user/update-queue";
|
import { UpdateQueue } from "@/lib/user/update-queue";
|
||||||
import { type ApiErrorResponse, type Result, err, okVoid } from "@/types/error";
|
import { type ApiErrorResponse, type Result, err, okVoid } from "@/types/error";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/require-await -- we want to use promises here
|
|
||||||
export const setUserId = async (userId: string): Promise<Result<void, ApiErrorResponse>> => {
|
export const setUserId = async (userId: string): Promise<Result<void, ApiErrorResponse>> => {
|
||||||
const appConfig = Config.getInstance();
|
const appConfig = Config.getInstance();
|
||||||
const logger = Logger.getInstance();
|
const logger = Logger.getInstance();
|
||||||
@@ -27,8 +26,20 @@ export const setUserId = async (userId: string): Promise<Result<void, ApiErrorRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateQueue.updateUserId(userId);
|
updateQueue.updateUserId(userId);
|
||||||
void updateQueue.processUpdates();
|
try {
|
||||||
return okVoid();
|
await updateQueue.processUpdates();
|
||||||
|
return okVoid();
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(
|
||||||
|
`Failed to process userId update: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||||
|
);
|
||||||
|
return err({
|
||||||
|
code: "network_error",
|
||||||
|
message: "Failed to sync userId",
|
||||||
|
responseMessage: error instanceof Error ? error.message : "Unknown error",
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const logout = (): Result<void> => {
|
export const logout = (): Result<void> => {
|
||||||
|
|||||||
Reference in New Issue
Block a user