From f860d8d25d08968158cc9d01233d59f8b47ab07c Mon Sep 17 00:00:00 2001 From: Dhruwang Jariwala <67850763+Dhruwang@users.noreply.github.com> Date: Thu, 14 Aug 2025 21:18:05 +0530 Subject: [PATCH] fix: link preview settings tweaks (#6418) --- .../shareEmbedModal/link-settings-tab.tsx | 4 +- apps/web/locales/de-DE.json | 11 +--- apps/web/locales/en-US.json | 11 +--- apps/web/locales/fr-FR.json | 11 +--- apps/web/locales/pt-BR.json | 11 +--- apps/web/locales/pt-PT.json | 11 +--- apps/web/locales/ro-RO.json | 11 +--- apps/web/locales/zh-Hant-TW.json | 11 +--- .../survey/link/contact-survey/page.test.tsx | 4 +- .../survey/link/contact-survey/page.tsx | 4 +- .../survey/link/lib/metadata-utils.test.ts | 12 ++-- .../modules/survey/link/lib/metadata-utils.ts | 62 +++++++++---------- apps/web/modules/survey/link/metadata.test.ts | 4 +- apps/web/modules/survey/link/metadata.ts | 3 +- 14 files changed, 50 insertions(+), 120 deletions(-) diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/link-settings-tab.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/link-settings-tab.tsx index 4497fbdafd..7ffb9c03ec 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/link-settings-tab.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/link-settings-tab.tsx @@ -150,13 +150,13 @@ export const LinkSettingsTab = ({ isReadOnly, locale }: LinkSettingsTabProps) => name: "title", label: t("environments.surveys.share.link_settings.link_title"), description: t("environments.surveys.share.link_settings.link_title_description"), - placeholder: t("environments.surveys.share.link_settings.link_title_placeholder"), + placeholder: survey.name, }, { name: "description", label: t("environments.surveys.share.link_settings.link_description"), description: t("environments.surveys.share.link_settings.link_description_description"), - placeholder: t("environments.surveys.share.link_settings.link_description_placeholder"), + placeholder: "Please complete this survey.", }, ]; diff --git a/apps/web/locales/de-DE.json b/apps/web/locales/de-DE.json index c39014f3f2..3fe40fef6b 100644 --- a/apps/web/locales/de-DE.json +++ b/apps/web/locales/de-DE.json @@ -141,7 +141,6 @@ "apply_filters": "Filter anwenden", "are_you_sure": "Bist Du sicher?", "attributes": "Attribute", - "avatar": "Avatar", "back": "Zurück", "billing": "Abrechnung", "booked": "Gebucht", @@ -1111,9 +1110,7 @@ }, "profile": { "account_deletion_consequences_warning": "Was passiert, wenn Du das Konto löschst", - "avatar_update_failed": "Aktualisierung des Avatars fehlgeschlagen. Bitte versuche es erneut.", "backup_code": "Backup-Code", - "change_image": "Bild ändern", "confirm_delete_account": "Lösche dein Konto mit all deinen persönlichen Informationen und Daten", "confirm_delete_my_account": "Konto löschen", "confirm_your_current_password_to_get_started": "Bestätige dein aktuelles Passwort, um loszulegen.", @@ -1124,17 +1121,13 @@ "email_change_initiated": "Deine Anfrage zur Änderung der E-Mail wurde eingeleitet.", "enable_two_factor_authentication": "Zwei-Faktor-Authentifizierung aktivieren", "enter_the_code_from_your_authenticator_app_below": "Gib den Code aus deiner Authentifizierungs-App unten ein.", - "file_size_must_be_less_than_10mb": "Dateigröße muss weniger als 10MB sein.", - "invalid_file_type": "Ungültiger Dateityp. Nur JPEG-, PNG- und WEBP-Dateien sind erlaubt.", "lost_access": "Zugriff verloren", "or_enter_the_following_code_manually": "Oder gib den folgenden Code manuell ein:", - "organization_identification": "Hilf deiner Organisation, Dich auf Formbricks zu identifizieren", "organizations_delete_message": "Du bist der einzige Besitzer dieser Organisationen, also werden sie auch gelöscht.", "permanent_removal_of_all_of_your_personal_information_and_data": "Dauerhafte Entfernung all deiner persönlichen Informationen und Daten", "personal_information": "Persönliche Informationen", "please_enter_email_to_confirm_account_deletion": "Bitte gib {email} in das folgende Feld ein, um die endgültige Löschung deines Kontos zu bestätigen:", "profile_updated_successfully": "Dein Profil wurde erfolgreich aktualisiert", - "remove_image": "Bild entfernen", "save_the_following_backup_codes_in_a_safe_place": "Speichere die folgenden Backup-Codes an einem sicheren Ort.", "scan_the_qr_code_below_with_your_authenticator_app": "Scanne den QR-Code unten mit deiner Authentifizierungs-App.", "security_description": "Verwalte dein Passwort und andere Sicherheitseinstellungen wie Zwei-Faktor-Authentifizierung (2FA).", @@ -1144,10 +1137,8 @@ "two_factor_code": "Zwei-Faktor-Code", "unlock_two_factor_authentication": "Zwei-Faktor-Authentifizierung mit einem höheren Plan freischalten", "update_personal_info": "Persönliche Daten aktualisieren", - "upload_image": "Bild hochladen", "warning_cannot_delete_account": "Du bist der einzige Besitzer dieser Organisation. Bitte übertrage das Eigentum zuerst an ein anderes Mitglied.", - "warning_cannot_undo": "Das kann nicht rückgängig gemacht werden", - "you_must_select_a_file": "Du musst eine Datei auswählen." + "warning_cannot_undo": "Das kann nicht rückgängig gemacht werden" }, "teams": { "add_members_description": "Füge Mitglieder zum Team hinzu und bestimme ihre Rolle.", diff --git a/apps/web/locales/en-US.json b/apps/web/locales/en-US.json index 17efae6545..877ce7c762 100644 --- a/apps/web/locales/en-US.json +++ b/apps/web/locales/en-US.json @@ -141,7 +141,6 @@ "apply_filters": "Apply filters", "are_you_sure": "Are you sure?", "attributes": "Attributes", - "avatar": "Avatar", "back": "Back", "billing": "Billing", "booked": "Booked", @@ -1111,9 +1110,7 @@ }, "profile": { "account_deletion_consequences_warning": "Account deletion consequences", - "avatar_update_failed": "Avatar update failed. Please try again.", "backup_code": "Backup Code", - "change_image": "Change image", "confirm_delete_account": "Delete your account with all of your personal information and data", "confirm_delete_my_account": "Delete My Account", "confirm_your_current_password_to_get_started": "Confirm your current password to get started.", @@ -1124,17 +1121,13 @@ "email_change_initiated": "Your email change request has been initiated.", "enable_two_factor_authentication": "Enable two factor authentication", "enter_the_code_from_your_authenticator_app_below": "Enter the code from your authenticator app below.", - "file_size_must_be_less_than_10mb": "File size must be less than 10MB.", - "invalid_file_type": "Invalid file type. Only JPEG, PNG, and WEBP files are allowed.", "lost_access": "Lost access", "or_enter_the_following_code_manually": "Or enter the following code manually:", - "organization_identification": "Assist your organization in identifying you on Formbricks", "organizations_delete_message": "You are the only owner of these organizations, so they will be deleted as well.", "permanent_removal_of_all_of_your_personal_information_and_data": "Permanent removal of all of your personal information and data", "personal_information": "Personal information", "please_enter_email_to_confirm_account_deletion": "Please enter {email} in the following field to confirm the definitive deletion of your account:", "profile_updated_successfully": "Your profile was updated successfully", - "remove_image": "Remove image", "save_the_following_backup_codes_in_a_safe_place": "Save the following backup codes in a safe place.", "scan_the_qr_code_below_with_your_authenticator_app": "Scan the QR code below with your authenticator app.", "security_description": "Manage your password and other security settings like two-factor authentication (2FA).", @@ -1144,10 +1137,8 @@ "two_factor_code": "Two-Factor Code", "unlock_two_factor_authentication": "Unlock two-factor authentication with a higher plan", "update_personal_info": "Update your personal information", - "upload_image": "Upload image", "warning_cannot_delete_account": "You are the only owner of this organization. Please transfer ownership to another member first.", - "warning_cannot_undo": "This cannot be undone", - "you_must_select_a_file": "You must select a file." + "warning_cannot_undo": "This cannot be undone" }, "teams": { "add_members_description": "Add members to the team and determine their role.", diff --git a/apps/web/locales/fr-FR.json b/apps/web/locales/fr-FR.json index db6c01cb44..e09cb93c20 100644 --- a/apps/web/locales/fr-FR.json +++ b/apps/web/locales/fr-FR.json @@ -141,7 +141,6 @@ "apply_filters": "Appliquer des filtres", "are_you_sure": "Es-tu sûr ?", "attributes": "Attributs", - "avatar": "Avatar", "back": "Retour", "billing": "Facturation", "booked": "Réservé", @@ -1111,9 +1110,7 @@ }, "profile": { "account_deletion_consequences_warning": "Conséquences de la suppression de compte", - "avatar_update_failed": "La mise à jour de l'avatar a échoué. Veuillez réessayer.", "backup_code": "Code de sauvegarde", - "change_image": "Changer l'image", "confirm_delete_account": "Supprimez votre compte avec toutes vos informations personnelles et données.", "confirm_delete_my_account": "Supprimer mon compte", "confirm_your_current_password_to_get_started": "Confirmez votre mot de passe actuel pour commencer.", @@ -1124,17 +1121,13 @@ "email_change_initiated": "Votre demande de changement d'email a été initiée.", "enable_two_factor_authentication": "Activer l'authentification à deux facteurs", "enter_the_code_from_your_authenticator_app_below": "Entrez le code de votre application d'authentification ci-dessous.", - "file_size_must_be_less_than_10mb": "La taille du fichier doit être inférieure à 10 Mo.", - "invalid_file_type": "Type de fichier invalide. Seuls les fichiers JPEG, PNG et WEBP sont autorisés.", "lost_access": "Accès perdu", "or_enter_the_following_code_manually": "Ou entrez le code suivant manuellement :", - "organization_identification": "Aidez votre organisation à vous identifier sur Formbricks", "organizations_delete_message": "Tu es le seul propriétaire de ces organisations, elles seront aussi supprimées.", "permanent_removal_of_all_of_your_personal_information_and_data": "Suppression permanente de toutes vos informations et données personnelles.", "personal_information": "Informations personnelles", "please_enter_email_to_confirm_account_deletion": "Veuillez entrer {email} dans le champ suivant pour confirmer la suppression définitive de votre compte :", "profile_updated_successfully": "Votre profil a été mis à jour avec succès.", - "remove_image": "Supprimer l'image", "save_the_following_backup_codes_in_a_safe_place": "Enregistrez les codes de sauvegarde suivants dans un endroit sûr.", "scan_the_qr_code_below_with_your_authenticator_app": "Scannez le code QR ci-dessous avec votre application d'authentification.", "security_description": "Gérez votre mot de passe et d'autres paramètres de sécurité comme l'authentification à deux facteurs (2FA).", @@ -1144,10 +1137,8 @@ "two_factor_code": "Code à deux facteurs", "unlock_two_factor_authentication": "Débloquez l'authentification à deux facteurs avec une offre supérieure", "update_personal_info": "Mettez à jour vos informations personnelles", - "upload_image": "Télécharger l'image", "warning_cannot_delete_account": "Tu es le seul propriétaire de cette organisation. Transfère la propriété à un autre membre d'abord.", - "warning_cannot_undo": "Ceci ne peut pas être annulé", - "you_must_select_a_file": "Vous devez sélectionner un fichier." + "warning_cannot_undo": "Ceci ne peut pas être annulé" }, "teams": { "add_members_description": "Ajoutez des membres à l'équipe et déterminez leur rôle.", diff --git a/apps/web/locales/pt-BR.json b/apps/web/locales/pt-BR.json index 1d0772ef42..dde37596f1 100644 --- a/apps/web/locales/pt-BR.json +++ b/apps/web/locales/pt-BR.json @@ -141,7 +141,6 @@ "apply_filters": "Aplicar filtros", "are_you_sure": "Certeza?", "attributes": "atributos", - "avatar": "Avatar", "back": "Voltar", "billing": "Faturamento", "booked": "Reservado", @@ -1111,9 +1110,7 @@ }, "profile": { "account_deletion_consequences_warning": "Consequências da exclusão da conta", - "avatar_update_failed": "Falha ao atualizar o avatar. Por favor, tente novamente.", "backup_code": "Código de Backup", - "change_image": "Mudar imagem", "confirm_delete_account": "Apague sua conta com todas as suas informações pessoais e dados", "confirm_delete_my_account": "Excluir Minha Conta", "confirm_your_current_password_to_get_started": "Confirme sua senha atual para começar.", @@ -1124,17 +1121,13 @@ "email_change_initiated": "Sua solicitação de alteração de e-mail foi iniciada.", "enable_two_factor_authentication": "Ativar autenticação de dois fatores", "enter_the_code_from_your_authenticator_app_below": "Digite o código do seu app autenticador abaixo.", - "file_size_must_be_less_than_10mb": "O tamanho do arquivo deve ser menor que 10MB.", - "invalid_file_type": "Tipo de arquivo inválido. Só são permitidos arquivos JPEG, PNG e WEBP.", "lost_access": "Perdi o acesso", "or_enter_the_following_code_manually": "Ou insira o seguinte código manualmente:", - "organization_identification": "Ajude sua organização a te identificar no Formbricks", "organizations_delete_message": "Você é o único dono dessas organizações, então elas também serão apagadas.", "permanent_removal_of_all_of_your_personal_information_and_data": "Remoção permanente de todas as suas informações e dados pessoais", "personal_information": "Informações pessoais", "please_enter_email_to_confirm_account_deletion": "Por favor, insira {email} no campo abaixo para confirmar a exclusão definitiva da sua conta:", "profile_updated_successfully": "Seu perfil foi atualizado com sucesso", - "remove_image": "Remover imagem", "save_the_following_backup_codes_in_a_safe_place": "Guarde os seguintes códigos de backup em um lugar seguro.", "scan_the_qr_code_below_with_your_authenticator_app": "Escaneie o código QR abaixo com seu app autenticador.", "security_description": "Gerencie sua senha e outras configurações de segurança como a autenticação de dois fatores (2FA).", @@ -1144,10 +1137,8 @@ "two_factor_code": "Código de Dois Fatores", "unlock_two_factor_authentication": "Desbloqueia a autenticação de dois fatores com um plano melhor", "update_personal_info": "Atualize suas informações pessoais", - "upload_image": "Enviar imagem", "warning_cannot_delete_account": "Você é o único dono desta organização. Transfere a propriedade para outra pessoa primeiro.", - "warning_cannot_undo": "Isso não pode ser desfeito", - "you_must_select_a_file": "Você tem que selecionar um arquivo." + "warning_cannot_undo": "Isso não pode ser desfeito" }, "teams": { "add_members_description": "Adicione membros à equipe e determine sua função.", diff --git a/apps/web/locales/pt-PT.json b/apps/web/locales/pt-PT.json index dd7345cb2e..edce6ab083 100644 --- a/apps/web/locales/pt-PT.json +++ b/apps/web/locales/pt-PT.json @@ -141,7 +141,6 @@ "apply_filters": "Aplicar filtros", "are_you_sure": "Tem a certeza?", "attributes": "Atributos", - "avatar": "Avatar", "back": "Voltar", "billing": "Faturação", "booked": "Reservado", @@ -1111,9 +1110,7 @@ }, "profile": { "account_deletion_consequences_warning": "Consequências da eliminação da conta", - "avatar_update_failed": "Falha na atualização do avatar. Por favor, tente novamente.", "backup_code": "Código de Backup", - "change_image": "Alterar imagem", "confirm_delete_account": "Eliminar a sua conta com todas as suas informações e dados pessoais", "confirm_delete_my_account": "Eliminar a Minha Conta", "confirm_your_current_password_to_get_started": "Confirme a sua palavra-passe atual para começar.", @@ -1124,17 +1121,13 @@ "email_change_initiated": "O seu pedido de alteração de email foi iniciado.", "enable_two_factor_authentication": "Ativar autenticação de dois fatores", "enter_the_code_from_your_authenticator_app_below": "Introduza o código da sua aplicação de autenticação abaixo.", - "file_size_must_be_less_than_10mb": "O tamanho do ficheiro deve ser inferior a 10MB.", - "invalid_file_type": "Tipo de ficheiro inválido. Apenas são permitidos ficheiros JPEG, PNG e WEBP.", "lost_access": "Perdeu o acesso", "or_enter_the_following_code_manually": "Ou insira o seguinte código manualmente:", - "organization_identification": "Ajude a sua organização a identificá-lo no Formbricks", "organizations_delete_message": "É o único proprietário destas organizações, por isso também serão eliminadas.", "permanent_removal_of_all_of_your_personal_information_and_data": "Remoção permanente de todas as suas informações e dados pessoais", "personal_information": "Informações pessoais", "please_enter_email_to_confirm_account_deletion": "Por favor, insira {email} no campo seguinte para confirmar a eliminação definitiva da sua conta:", "profile_updated_successfully": "O seu perfil foi atualizado com sucesso", - "remove_image": "Remover imagem", "save_the_following_backup_codes_in_a_safe_place": "Guarde os seguintes códigos de backup num local seguro.", "scan_the_qr_code_below_with_your_authenticator_app": "Digitalize o código QR abaixo com a sua aplicação de autenticação.", "security_description": "Gerir a sua palavra-passe e outras definições de segurança, como a autenticação de dois fatores (2FA).", @@ -1144,10 +1137,8 @@ "two_factor_code": "Código de Dois Fatores", "unlock_two_factor_authentication": "Desbloqueie a autenticação de dois fatores com um plano superior", "update_personal_info": "Atualize as suas informações pessoais", - "upload_image": "Carregar imagem", "warning_cannot_delete_account": "É o único proprietário desta organização. Transfira a propriedade para outro membro primeiro.", - "warning_cannot_undo": "Isto não pode ser desfeito", - "you_must_select_a_file": "Deve selecionar um ficheiro." + "warning_cannot_undo": "Isto não pode ser desfeito" }, "teams": { "add_members_description": "Adicionar membros à equipa e determinar o seu papel.", diff --git a/apps/web/locales/ro-RO.json b/apps/web/locales/ro-RO.json index a2c55d26a7..af02242cb4 100644 --- a/apps/web/locales/ro-RO.json +++ b/apps/web/locales/ro-RO.json @@ -141,7 +141,6 @@ "apply_filters": "Aplică filtre", "are_you_sure": "Ești sigur?", "attributes": "Atribute", - "avatar": "Avatar", "back": "Înapoi", "billing": "Facturare", "booked": "Rezervat", @@ -1111,9 +1110,7 @@ }, "profile": { "account_deletion_consequences_warning": "Consecințele ștergerii contului", - "avatar_update_failed": "Actualizarea avatarului a eșuat. Vă rugăm să încercați din nou.", "backup_code": "Cod de rezervă", - "change_image": "Schimbă imaginea", "confirm_delete_account": "Șterge contul tău cu toate informațiile personale și datele tale", "confirm_delete_my_account": "Șterge Contul Meu", "confirm_your_current_password_to_get_started": "Confirmaţi parola curentă pentru a începe.", @@ -1124,17 +1121,13 @@ "email_change_initiated": "Cererea dvs. de schimbare a e-mailului a fost inițiată.", "enable_two_factor_authentication": "Activează autentificarea în doi pași", "enter_the_code_from_your_authenticator_app_below": "Introduceți codul din aplicația dvs. de autentificare mai jos.", - "file_size_must_be_less_than_10mb": "Dimensiunea fișierului trebuie să fie mai mică de 10MB.", - "invalid_file_type": "Tip de fișier invalid. Sunt permise numai fișiere JPEG, PNG și WEBP.", "lost_access": "Acces pierdut", "or_enter_the_following_code_manually": "Sau introduceți manual următorul cod:", - "organization_identification": "Ajutați organizația să vă identifice pe Formbricks", "organizations_delete_message": "Ești singurul proprietar al acestor organizații, deci ele vor fi șterse și ele.", "permanent_removal_of_all_of_your_personal_information_and_data": "Ștergerea permanentă a tuturor informațiilor și datelor tale personale", "personal_information": "Informații personale", "please_enter_email_to_confirm_account_deletion": "Vă rugăm să introduceți {email} în câmpul următor pentru a confirma ștergerea definitivă a contului dumneavoastră:", "profile_updated_successfully": "Profilul dvs. a fost actualizat cu succes", - "remove_image": "Șterge imaginea", "save_the_following_backup_codes_in_a_safe_place": "Salvează următoarele coduri de rezervă într-un loc sigur.", "scan_the_qr_code_below_with_your_authenticator_app": "Scanați codul QR de mai jos cu aplicația dvs. de autentificare.", "security_description": "Gestionează parola și alte setări de securitate, precum autentificarea în doi pași (2FA).", @@ -1144,10 +1137,8 @@ "two_factor_code": "Codul cu doi factori", "unlock_two_factor_authentication": "Deblocați autentificarea în doi pași cu un plan superior", "update_personal_info": "Actualizează informațiile tale personale", - "upload_image": "Încărcați imagine", "warning_cannot_delete_account": "Ești singurul proprietar al acestei organizații. Te rugăm să transferi proprietatea către un alt membru mai întâi.", - "warning_cannot_undo": "Aceasta nu poate fi anulată", - "you_must_select_a_file": "Trebuie să selectați un fișier." + "warning_cannot_undo": "Aceasta nu poate fi anulată" }, "teams": { "add_members_description": "Adaugă membri în echipă și stabilește rolul lor.", diff --git a/apps/web/locales/zh-Hant-TW.json b/apps/web/locales/zh-Hant-TW.json index 73eb4fc6a8..8fc715d0bb 100644 --- a/apps/web/locales/zh-Hant-TW.json +++ b/apps/web/locales/zh-Hant-TW.json @@ -141,7 +141,6 @@ "apply_filters": "套用篩選器", "are_you_sure": "您確定嗎?", "attributes": "屬性", - "avatar": "頭像", "back": "返回", "billing": "帳單", "booked": "已預訂", @@ -1111,9 +1110,7 @@ }, "profile": { "account_deletion_consequences_warning": "帳戶刪除後果", - "avatar_update_failed": "頭像更新失敗。請再試一次。", "backup_code": "備份碼", - "change_image": "變更圖片", "confirm_delete_account": "刪除您的帳戶以及您的所有個人資訊和資料", "confirm_delete_my_account": "刪除我的帳戶", "confirm_your_current_password_to_get_started": "確認您目前的密碼以開始使用。", @@ -1124,17 +1121,13 @@ "email_change_initiated": "您的 email 更改請求已啟動。", "enable_two_factor_authentication": "啟用雙重驗證", "enter_the_code_from_your_authenticator_app_below": "在下方輸入您驗證器應用程式中的程式碼。", - "file_size_must_be_less_than_10mb": "檔案大小必須小於 10MB。", - "invalid_file_type": "無效的檔案類型。僅允許 JPEG、PNG 和 WEBP 檔案。", "lost_access": "無法存取", "or_enter_the_following_code_manually": "或手動輸入下列程式碼:", - "organization_identification": "協助您的組織在 Formbricks 上識別您", "organizations_delete_message": "您是這些組織的唯一擁有者,因此它們也 將被刪除。", "permanent_removal_of_all_of_your_personal_information_and_data": "永久移除您的所有個人資訊和資料", "personal_information": "個人資訊", "please_enter_email_to_confirm_account_deletion": "請在以下欄位中輸入 '{'email'}' 以確認永久刪除您的帳戶:", "profile_updated_successfully": "您的個人資料已成功更新", - "remove_image": "移除圖片", "save_the_following_backup_codes_in_a_safe_place": "將下列備份碼儲存在安全的地方。", "scan_the_qr_code_below_with_your_authenticator_app": "使用您的驗證器應用程式掃描下方的 QR 碼。", "security_description": "管理您的密碼和其他安全性設定,例如雙重驗證 (2FA)。", @@ -1144,10 +1137,8 @@ "two_factor_code": "雙重驗證碼", "unlock_two_factor_authentication": "使用更高等級的方案解鎖雙重驗證", "update_personal_info": "更新您的個人資訊", - "upload_image": "上傳圖片", "warning_cannot_delete_account": "您是此組織的唯一擁有者。請先將所有權轉讓給其他成員。", - "warning_cannot_undo": "此操作無法復原", - "you_must_select_a_file": "您必須選取檔案。" + "warning_cannot_undo": "此操作無法復原" }, "teams": { "add_members_description": "將成員新增至團隊並確定其角色。", diff --git a/apps/web/modules/survey/link/contact-survey/page.test.tsx b/apps/web/modules/survey/link/contact-survey/page.test.tsx index 585730e80a..c6cec23bc1 100644 --- a/apps/web/modules/survey/link/contact-survey/page.test.tsx +++ b/apps/web/modules/survey/link/contact-survey/page.test.tsx @@ -92,7 +92,7 @@ describe("contact-survey page", () => { params: Promise.resolve({ jwt: "token" }), searchParams: Promise.resolve({}), }); - expect(meta).toEqual({ title: "Survey", description: "Complete this survey" }); + expect(meta).toEqual({ title: "Survey", description: "Please complete this survey." }); }); test("generateMetadata returns default when verify throws", async () => { @@ -103,7 +103,7 @@ describe("contact-survey page", () => { params: Promise.resolve({ jwt: "token" }), searchParams: Promise.resolve({}), }); - expect(meta).toEqual({ title: "Survey", description: "Complete this survey" }); + expect(meta).toEqual({ title: "Survey", description: "Please complete this survey." }); }); test("generateMetadata returns basic metadata when token valid", async () => { diff --git a/apps/web/modules/survey/link/contact-survey/page.tsx b/apps/web/modules/survey/link/contact-survey/page.tsx index 063b48db04..ec86d6a77a 100644 --- a/apps/web/modules/survey/link/contact-survey/page.tsx +++ b/apps/web/modules/survey/link/contact-survey/page.tsx @@ -31,7 +31,7 @@ export const generateMetadata = async (props: ContactSurveyPageProps): Promise { expect(getSurvey).toHaveBeenCalledWith(mockSurveyId); expect(result).toEqual({ title: "Survey", - description: "Complete this survey", + description: "Please complete this survey.", survey: null, ogImage: undefined, }); @@ -108,10 +108,9 @@ describe("Metadata Utils", () => { const result = await getBasicSurveyMetadata(mockSurveyId); expect(getSurvey).toHaveBeenCalledWith(mockSurveyId); - expect(getProjectByEnvironmentId).toHaveBeenCalledWith(mockEnvironmentId); expect(result).toEqual({ - title: "Welcome Headline | Test Project", - description: "Complete this survey", + title: "Welcome Headline", + description: "Please complete this survey.", survey: mockSurvey, ogImage: undefined, }); @@ -129,13 +128,12 @@ describe("Metadata Utils", () => { } as TSurvey; vi.mocked(getSurvey).mockResolvedValue(mockSurvey); - vi.mocked(getProjectByEnvironmentId).mockResolvedValue({ name: "Test Project" } as any); const result = await getBasicSurveyMetadata(mockSurveyId); expect(result).toEqual({ - title: "Test Survey | Test Project", - description: "Complete this survey", + title: "Test Survey", + description: "Please complete this survey.", survey: mockSurvey, ogImage: undefined, }); diff --git a/apps/web/modules/survey/link/lib/metadata-utils.ts b/apps/web/modules/survey/link/lib/metadata-utils.ts index cf6acc434c..c9bb5327ec 100644 --- a/apps/web/modules/survey/link/lib/metadata-utils.ts +++ b/apps/web/modules/survey/link/lib/metadata-utils.ts @@ -1,8 +1,8 @@ import { IS_FORMBRICKS_CLOUD } from "@/lib/constants"; import { getPublicDomain } from "@/lib/getPublicUrl"; +import { getLocalizedValue } from "@/lib/i18n/utils"; import { COLOR_DEFAULTS } from "@/lib/styling/constants"; import { getSurvey } from "@/modules/survey/lib/survey"; -import { getProjectByEnvironmentId } from "@/modules/survey/link/lib/project"; import { Metadata } from "next"; type TBasicSurveyMetadata = { @@ -12,22 +12,16 @@ type TBasicSurveyMetadata = { ogImage?: string; }; -/** - * Utility function to encode name for URL usage - */ -export const getNameForURL = (url: string) => url.replace(/ /g, "%20"); +export const getNameForURL = (value: string) => encodeURIComponent(value); -/** - * Utility function to encode brand color for URL usage - */ -export const getBrandColorForURL = (url: string) => url.replace(/#/g, "%23"); +export const getBrandColorForURL = (value: string) => encodeURIComponent(value); /** * Get basic survey metadata (title and description) based on link metadata, welcome card or survey name */ export const getBasicSurveyMetadata = async ( surveyId: string, - languageCode?: string + languageCode = "default" ): Promise => { const survey = await getSurvey(surveyId); @@ -35,7 +29,7 @@ export const getBasicSurveyMetadata = async ( if (!survey) { return { title: "Survey", - description: "Complete this survey", + description: "Please complete this survey.", survey: null, ogImage: undefined, }; @@ -43,38 +37,35 @@ export const getBasicSurveyMetadata = async ( const metadata = survey.metadata; const welcomeCard = survey.welcomeCard; + const useDefaultLanguageCode = + languageCode === "default" || + survey.languages.find((lang) => lang.language.code === languageCode)?.default; // Determine language code to use for metadata - const langCode = languageCode || "default"; + const langCode = useDefaultLanguageCode ? "default" : languageCode; // Set title - priority: custom link metadata > welcome card > survey name - let title = "Survey"; - if (metadata.title?.[langCode]) { - title = metadata.title[langCode]; - } else if (welcomeCard.enabled && welcomeCard.headline?.default) { - title = welcomeCard.headline.default; - } else { - title = survey.name; - } + const titleFromMetadata = metadata?.title + ? getLocalizedValue(metadata.title, langCode) || metadata.title.default + : undefined; + const titleFromWelcome = + welcomeCard?.enabled && welcomeCard.headline + ? getLocalizedValue(welcomeCard.headline, langCode) || welcomeCard.headline.default + : undefined; + let title = titleFromMetadata || titleFromWelcome || survey.name; // Set description - priority: custom link metadata > welcome card > default - let description = "Complete this survey"; - if (metadata.description?.[langCode]) { - description = metadata.description[langCode]; - } + const descriptionFromMetadata = metadata?.description + ? getLocalizedValue(metadata.description, langCode) || metadata.description.default + : undefined; + let description = descriptionFromMetadata || "Please complete this survey."; // Get OG image from link metadata if available const { ogImage } = metadata; - // Add product name in title if it's Formbricks cloud and not using custom metadata - if (!metadata.title?.[langCode]) { + if (!titleFromMetadata) { if (IS_FORMBRICKS_CLOUD) { title = `${title} | Formbricks`; - } else { - const project = await getProjectByEnvironmentId(survey.environmentId); - if (project) { - title = `${title} | ${project.name}`; - } } } @@ -89,10 +80,13 @@ export const getBasicSurveyMetadata = async ( /** * Generate Open Graph metadata for survey */ -export const getSurveyOpenGraphMetadata = (surveyId: string, surveyName: string): Metadata => { - const brandColor = getBrandColorForURL(COLOR_DEFAULTS.brandColor); // Default color +export const getSurveyOpenGraphMetadata = ( + surveyId: string, + surveyName: string, + surveyBrandColor?: string +): Metadata => { const encodedName = getNameForURL(surveyName); - + const brandColor = getBrandColorForURL(surveyBrandColor ?? COLOR_DEFAULTS.brandColor); const ogImgURL = `/api/v1/client/og?brandColor=${brandColor}&name=${encodedName}`; return { diff --git a/apps/web/modules/survey/link/metadata.test.ts b/apps/web/modules/survey/link/metadata.test.ts index 0ca428b19e..00ff1385cd 100644 --- a/apps/web/modules/survey/link/metadata.test.ts +++ b/apps/web/modules/survey/link/metadata.test.ts @@ -20,7 +20,7 @@ vi.mock("./lib/metadata-utils", () => ({ describe("getMetadataForLinkSurvey", () => { const mockSurveyId = "survey-123"; const mockSurveyName = "Test Survey"; - const mockDescription = "Complete this survey"; + const mockDescription = "Please complete this survey."; const mockOgImageUrl = "https://example.com/custom-image.png"; beforeEach(() => { @@ -60,7 +60,7 @@ describe("getMetadataForLinkSurvey", () => { expect(getSurveyMetadata).toHaveBeenCalledWith(mockSurveyId); expect(getBasicSurveyMetadata).toHaveBeenCalledWith(mockSurveyId, undefined); - expect(getSurveyOpenGraphMetadata).toHaveBeenCalledWith(mockSurveyId, mockSurveyName); + expect(getSurveyOpenGraphMetadata).toHaveBeenCalledWith(mockSurveyId, mockSurveyName, undefined); expect(result).toEqual({ title: mockSurveyName, diff --git a/apps/web/modules/survey/link/metadata.ts b/apps/web/modules/survey/link/metadata.ts index 3b63212249..bed68ac462 100644 --- a/apps/web/modules/survey/link/metadata.ts +++ b/apps/web/modules/survey/link/metadata.ts @@ -15,9 +15,10 @@ export const getMetadataForLinkSurvey = async ( // Get enhanced metadata that includes custom link metadata const { title, description, ogImage } = await getBasicSurveyMetadata(surveyId, languageCode); + const surveyBrandColor = survey.styling?.brandColor?.light; // Use the shared function for creating the base metadata but override with custom data - const baseMetadata = getSurveyOpenGraphMetadata(survey.id, title); + const baseMetadata = getSurveyOpenGraphMetadata(survey.id, title, surveyBrandColor); // Override with the custom image URL if (baseMetadata.openGraph) {