Compare commits

...

5 Commits

Author SHA1 Message Date
pandeymangg
0233541287 adds security signup UI in the org settings 2025-12-25 13:23:07 +05:30
Dhruwang Jariwala
adf12f551d fix: Swedish translations (#7032) 2025-12-23 12:02:26 +00:00
Dhruwang Jariwala
3f2bddc358 feat: Russian translations (#7027) 2025-12-23 10:31:09 +00:00
Dhruwang Jariwala
ae6d1ac133 chore: improve wording in email text (Duplicate of #7003) (#7025)
Co-authored-by: Balázs Úr <balazs@urbalazs.hu>
Co-authored-by: Johannes <johannes@formbricks.com>
2025-12-23 09:56:53 +00:00
Dhruwang Jariwala
7c4569cd50 fix: file upload validation (#7028) 2025-12-23 09:36:45 +00:00
31 changed files with 3739 additions and 110 deletions

View File

@@ -18,7 +18,8 @@
"zh-Hant-TW",
"nl-NL",
"es-ES",
"sv-SE"
"sv-SE",
"ru-RU"
]
},
"version": 1.8

View File

@@ -446,14 +446,12 @@ checksums:
emails/forgot_password_email_text: 5100fa2fe2180ded9cb2d89b4f77d2e0
emails/hidden_field: 3ed5c58d0ed359e558cdf7bd33606d2d
emails/imprint: c4e5f2a1994d3cc5896b200709cc499c
emails/invite_accepted_email_heading: 6ff6dff269b0f1ac1b73912c9e344343
emails/invite_accepted_email_heading: 80763c6e4585cd57fa58e4d2d82e6500
emails/invite_accepted_email_subject: 4f5f2a68c98dd1dd01143fcae3be5562
emails/invite_accepted_email_text_par1: b27eadc4779c9fa477103d136a6acab9
emails/invite_accepted_email_text_par2: c77209b510baf0415264fdb5ab8076a8
emails/invite_accepted_email_text: 48d792826ab9a97eed27599c17ec70d5
emails/invite_email_button_label: 02099d40cd11e717c0431fa43e68272c
emails/invite_email_heading: 6ff6dff269b0f1ac1b73912c9e344343
emails/invite_email_text_par1: 70b976a3d4a5509f6d905f9f3f962ada
emails/invite_email_text_par2: 14da6da9fdbc21a1cb38988abac7932d
emails/invite_email_heading: d9f9b18e4de575980de3cde3e4ed08bf
emails/invite_email_text: 1499fa615105121a133440929b039a64
emails/invite_member_email_subject: 295e329b1642339dc7cc2b49a687e1f8
emails/new_email_verification_text: b7f00f47d04afa9e872176d9933f2d93
emails/number_variable: d4f2bbb1965c791cf9921a5112914f3f
@@ -1101,6 +1099,13 @@ checksums:
environments/settings/teams/please_fill_all_project_fields: 6712059df63c432ecd31f3c52b8e4d87
environments/settings/teams/read: 2494ca23d10e5b6381eb271aceeb5270
environments/settings/teams/read_write: 278a90dade128198d4c93ac00c345320
environments/settings/teams/security_updates_description: 17c49b565a7dde28b810f67af2e8db07
environments/settings/teams/security_updates_enroll: edcc8815899ece9209ce981c26c44df3
environments/settings/teams/security_updates_enrolled: 98863ec2d846b7a13ff1ed38ce1038fe
environments/settings/teams/security_updates_enrolled_description: d9c7605767af8f4d7265cba7dfba5f11
environments/settings/teams/security_updates_enrolled_successfully: 3bbb41fac1c04effec3af8ffbd8b72c5
environments/settings/teams/security_updates_enrolling: 15ca7daa32fb57e18a0a6357de26eb4b
environments/settings/teams/security_updates_title: 2f5f5f55bb9a325b5c8228bcad4f2784
environments/settings/teams/select_member: 7f4a38312aabbbe3fe92756b57bd5d75
environments/settings/teams/select_project: 6e4f4a24178660851d9ae0874706be9f
environments/settings/teams/team_admin: 5df68214685738029af678ae1d5912bb

View File

@@ -177,6 +177,7 @@ export const AVAILABLE_LOCALES: TUserLocale[] = [
"zh-Hans-CN",
"es-ES",
"sv-SE",
"ru-RU",
];
// Billing constants

View File

@@ -141,6 +141,7 @@ export const appLanguages = [
"nl-NL": "Engels (VS)",
"es-ES": "Inglés (EE.UU.)",
"sv-SE": "Engelska (USA)",
"ru-RU": "Английский (США)",
},
},
{
@@ -158,6 +159,7 @@ export const appLanguages = [
"nl-NL": "Duits",
"es-ES": "Alemán",
"sv-SE": "Tyska",
"ru-RU": "Немецкий",
},
},
{
@@ -175,6 +177,7 @@ export const appLanguages = [
"nl-NL": "Portugees (Brazilië)",
"es-ES": "Portugués (Brasil)",
"sv-SE": "Portugisiska (Brasilien)",
"ru-RU": "Португальский (Бразилия)",
},
},
{
@@ -192,6 +195,7 @@ export const appLanguages = [
"nl-NL": "Frans",
"es-ES": "Francés",
"sv-SE": "Franska",
"ru-RU": "Французский",
},
},
{
@@ -209,6 +213,7 @@ export const appLanguages = [
"nl-NL": "Chinees (Traditioneel)",
"es-ES": "Chino (Tradicional)",
"sv-SE": "Kinesiska (traditionell)",
"ru-RU": "Китайский (традиционный)",
},
},
{
@@ -226,6 +231,7 @@ export const appLanguages = [
"nl-NL": "Portugees (Portugal)",
"es-ES": "Portugués (Portugal)",
"sv-SE": "Portugisiska (Portugal)",
"ru-RU": "Португальский (Португалия)",
},
},
{
@@ -243,6 +249,7 @@ export const appLanguages = [
"nl-NL": "Roemeens",
"es-ES": "Rumano",
"sv-SE": "Rumänska",
"ru-RU": "Румынский",
},
},
{
@@ -260,6 +267,7 @@ export const appLanguages = [
"nl-NL": "Japans",
"es-ES": "Japonés",
"sv-SE": "Japanska",
"ru-RU": "Японский",
},
},
{
@@ -277,6 +285,7 @@ export const appLanguages = [
"nl-NL": "Chinees (Vereenvoudigd)",
"es-ES": "Chino (Simplificado)",
"sv-SE": "Kinesiska (förenklad)",
"ru-RU": "Китайский (упрощенный)",
},
},
{
@@ -294,6 +303,7 @@ export const appLanguages = [
"nl-NL": "Nederlands",
"es-ES": "Neerlandés",
"sv-SE": "Nederländska",
"ru-RU": "Голландский",
},
},
{
@@ -311,6 +321,7 @@ export const appLanguages = [
"nl-NL": "Spaans",
"es-ES": "Español",
"sv-SE": "Spanska",
"ru-RU": "Испанский",
},
},
{
@@ -328,6 +339,7 @@ export const appLanguages = [
"nl-NL": "Zweeds",
"es-ES": "Sueco",
"sv-SE": "Svenska",
"ru-RU": "Шведский",
},
},
];

View File

@@ -1,5 +1,5 @@
import { formatDistance, intlFormat } from "date-fns";
import { de, enUS, es, fr, ja, nl, pt, ptBR, ro, sv, zhCN, zhTW } from "date-fns/locale";
import { de, enUS, es, fr, ja, nl, pt, ptBR, ro, ru, sv, zhCN, zhTW } from "date-fns/locale";
import { TUserLocale } from "@formbricks/types/user";
export const convertDateString = (dateString: string | null) => {
@@ -107,6 +107,8 @@ const getLocaleForTimeSince = (locale: TUserLocale) => {
return zhCN;
case "es-ES":
return es;
case "ru-RU":
return ru;
}
};

View File

@@ -475,14 +475,12 @@
"forgot_password_email_text": "Du hast einen Link angefordert, um dein Passwort zu ändern. Du kannst dies tun, indem Du auf den untenstehenden Link klickst:",
"hidden_field": "Verstecktes Feld",
"imprint": "Impressum",
"invite_accepted_email_heading": "Hey",
"invite_accepted_email_heading": "Hey {inviterName}",
"invite_accepted_email_subject": "Du hast einen neuen Organisation-Mitglied!",
"invite_accepted_email_text_par1": "Wollte dir nur Bescheid geben, dass",
"invite_accepted_email_text_par2": "deine Einladung angenommen hat. Viel Spaß bei der Zusammenarbeit!",
"invite_accepted_email_text": "Nur zur Info: {inviteeName} hat deine Einladung angenommen. Viel Spaß bei der Zusammenarbeit!",
"invite_email_button_label": "Organisation beitreten",
"invite_email_heading": "Hey",
"invite_email_text_par1": "Dein Kollege",
"invite_email_text_par2": "hat Dich eingeladen, Formbricks zu nutzen. Um die Einladung anzunehmen, klicke bitte auf den untenstehenden Link:",
"invite_email_heading": "Hey {inviteeName}",
"invite_email_text": "Dein Kollege {inviterName} hat dich eingeladen, bei Formbricks mitzumachen. Um die Einladung anzunehmen, klicke bitte auf den Link unten:",
"invite_member_email_subject": "Du wurdest eingeladen, Formbricks zu nutzen!",
"new_email_verification_text": "Um Ihre neue E-Mail-Adresse zu bestätigen, klicken Sie bitte auf die Schaltfläche unten:",
"number_variable": "Zahlenvariable",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "Bitte fülle alle Felder aus, um ein neues Projekt hinzuzufügen.",
"read": "Lesen",
"read_write": "Lesen & Schreiben",
"security_updates_description": "Melden Sie sich für unsere Sicherheits-Mailingliste an, um informiert zu bleiben, falls Sicherheitslücken gefunden werden.",
"security_updates_enroll": "Jetzt anmelden",
"security_updates_enrolled": "Angemeldet",
"security_updates_enrolled_description": "Sie sind angemeldet, um Sicherheitsupdates unter {email} zu erhalten.",
"security_updates_enrolled_successfully": "Erfolgreich für Sicherheitsupdates angemeldet!",
"security_updates_enrolling": "Wird angemeldet...",
"security_updates_title": "Sicherheitsupdates",
"select_member": "Mitglied auswählen",
"select_project": "Projekt auswählen",
"team_admin": "Team-Admin",

View File

@@ -475,14 +475,12 @@
"forgot_password_email_text": "You have requested a link to change your password. You can do this by clicking the link below:",
"hidden_field": "Hidden field",
"imprint": "Imprint",
"invite_accepted_email_heading": "Hey",
"invite_accepted_email_heading": "Hey {inviterName}",
"invite_accepted_email_subject": "You've got a new organization member!",
"invite_accepted_email_text_par1": "Just letting you know that",
"invite_accepted_email_text_par2": "accepted your invitation. Have fun collaborating!",
"invite_accepted_email_text": "Just letting you know that {inviteeName} accepted your invitation. Have fun collaborating!",
"invite_email_button_label": "Join organization",
"invite_email_heading": "Hey",
"invite_email_text_par1": "Your colleague",
"invite_email_text_par2": "invited you to join them at Formbricks. To accept the invitation, please click the link below:",
"invite_email_heading": "Hey {inviteeName}",
"invite_email_text": "Your colleague {inviterName} invited you to join them at Formbricks. To accept the invitation, please click the link below:",
"invite_member_email_subject": "You're invited to collaborate on Formbricks!",
"new_email_verification_text": "To verify your new email address, please click the button below:",
"number_variable": "Number variable",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "Please fill all the fields to add a new project.",
"read": "Read",
"read_write": "Read & Write",
"security_updates_description": "Enroll to our Security Mailing List to stay informed if vulnerabilities are found.",
"security_updates_enroll": "Enroll now",
"security_updates_enrolled": "Enrolled",
"security_updates_enrolled_description": "You're enrolled to receive security updates at {email}.",
"security_updates_enrolled_successfully": "Successfully enrolled for security updates!",
"security_updates_enrolling": "Enrolling...",
"security_updates_title": "Security Updates",
"select_member": "Select member",
"select_project": "Select project",
"team_admin": "Team Admin",

View File

@@ -475,14 +475,12 @@
"forgot_password_email_text": "Has solicitado un enlace para cambiar tu contraseña. Puedes hacerlo haciendo clic en el enlace a continuación:",
"hidden_field": "Campo oculto",
"imprint": "Aviso legal",
"invite_accepted_email_heading": "Hola",
"invite_accepted_email_heading": "Hola, {inviterName}",
"invite_accepted_email_subject": "¡Tienes un nuevo miembro en la organización!",
"invite_accepted_email_text_par1": "Solo para informarte que",
"invite_accepted_email_text_par2": "ha aceptado tu invitación. ¡Diviértete colaborando!",
"invite_accepted_email_text": "Te informamos que {inviteeName} ha aceptado tu invitación. ¡Que disfrutéis colaborando!",
"invite_email_button_label": "Unirse a la organización",
"invite_email_heading": "Hola",
"invite_email_text_par1": "Tu colega",
"invite_email_text_par2": "te ha invitado a unirte a Formbricks. Para aceptar la invitación, por favor haz clic en el enlace a continuación:",
"invite_email_heading": "Hola, {inviteeName}",
"invite_email_text": "Tu compañero {inviterName} te ha invitado a unirte a Formbricks. Para aceptar la invitación, haz clic en el enlace que aparece a continuación:",
"invite_member_email_subject": "¡Estás invitado a colaborar en Formbricks!",
"new_email_verification_text": "Para verificar tu nueva dirección de correo electrónico, por favor haz clic en el botón a continuación:",
"number_variable": "Variable numérica",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "Por favor, rellena todos los campos para añadir un nuevo proyecto.",
"read": "Lectura",
"read_write": "Lectura y escritura",
"security_updates_description": "Inscríbete en nuestra lista de correo de seguridad para mantenerte informado si se encuentran vulnerabilidades.",
"security_updates_enroll": "Inscribirse ahora",
"security_updates_enrolled": "Inscrito",
"security_updates_enrolled_description": "Estás inscrito para recibir actualizaciones de seguridad en {email}.",
"security_updates_enrolled_successfully": "Te has inscrito correctamente para recibir actualizaciones de seguridad.",
"security_updates_enrolling": "Inscribiendo...",
"security_updates_title": "Actualizaciones de seguridad",
"select_member": "Seleccionar miembro",
"select_project": "Seleccionar proyecto",
"team_admin": "Administrador de equipo",

View File

@@ -474,15 +474,13 @@
"forgot_password_email_subject": "Réinitialise ton mot de passe Formbricks",
"forgot_password_email_text": "Vous avez demandé un lien pour changer votre mot de passe. Vous pouvez le faire en cliquant sur le lien ci-dessous :",
"hidden_field": "Champ caché",
"imprint": "Empreinte",
"invite_accepted_email_heading": "Salut",
"imprint": "Impressum",
"invite_accepted_email_heading": "Salut {inviterName}",
"invite_accepted_email_subject": "Vous avez un nouveau membre dans votre organisation !",
"invite_accepted_email_text_par1": "Je te fais savoir que",
"invite_accepted_email_text_par2": "accepté votre invitation. Amusez-vous bien à collaborer !",
"invite_accepted_email_text": "Juste pour te faire savoir que {inviteeName} a accepté ton invitation. Amusez-vous bien à collaborer!",
"invite_email_button_label": "Rejoindre l'organisation",
"invite_email_heading": "Salut",
"invite_email_text_par1": "Votre collègue",
"invite_email_text_par2": "vous a invité à les rejoindre sur Formbricks. Pour accepter l'invitation, veuillez cliquer sur le lien ci-dessous :",
"invite_email_heading": "Salut {inviteeName}",
"invite_email_text": "Ton collègue {inviterName} t'a invité à le rejoindre sur Formbricks. Pour accepter l'invitation, clique sur le lien ci-dessous:",
"invite_member_email_subject": "Vous avez été invité à collaborer sur Formbricks !",
"new_email_verification_text": "Pour confirmer votre nouvelle adresse e-mail, veuillez cliquer sur le bouton ci-dessous :",
"number_variable": "Variable numérique",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "Veuillez remplir tous les champs pour ajouter un nouveau projet.",
"read": "Lire",
"read_write": "Lire et Écrire",
"security_updates_description": "Inscrivez-vous à notre liste de diffusion sécurité pour être informé si des vulnérabilités sont découvertes.",
"security_updates_enroll": "S'inscrire maintenant",
"security_updates_enrolled": "Inscrit",
"security_updates_enrolled_description": "Vous êtes inscrit pour recevoir les mises à jour de sécurité à {email}.",
"security_updates_enrolled_successfully": "Inscription aux mises à jour de sécurité réussie!",
"security_updates_enrolling": "Inscription en cours...",
"security_updates_title": "Mises à jour de sécurité",
"select_member": "Sélectionner membre",
"select_project": "Sélectionner projet",
"team_admin": "Administrateur d'équipe",

View File

@@ -475,14 +475,12 @@
"forgot_password_email_text": "パスワード変更のリンクがリクエストされました。以下のリンクをクリックして変更できます。",
"hidden_field": "非表示フィールド",
"imprint": "企業情報",
"invite_accepted_email_heading": "こんにちは",
"invite_accepted_email_heading": "{inviterName}さん",
"invite_accepted_email_subject": "新しい組織メンバーが加わりました!",
"invite_accepted_email_text_par1": "お知らせですが、",
"invite_accepted_email_text_par2": "があなたの招待を承認しました。コラボレーションを楽しんでください!",
"invite_accepted_email_text": "{inviteeName}さんがあなたの招待を承認しました。コラボレーションをお楽しみください!",
"invite_email_button_label": "組織に参加",
"invite_email_heading": "こんにちは",
"invite_email_text_par1": "あなたの同僚の",
"invite_email_text_par2": "が、Formbricksへの参加をあなたに招待しました。招待を承認するには、以下のリンクをクリックしてください。",
"invite_email_heading": "{inviteeName}さん",
"invite_email_text": "同僚の{inviterName}さんがFormbricksへの参加を招待しています。招待を承認するには、以下のリンクをクリックしてください",
"invite_member_email_subject": "Formbricksでのコラボレーションに招待されました",
"new_email_verification_text": "新しいメールアドレスを認証するには、以下のボタンをクリックしてください。",
"number_variable": "数値変数",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "新しいプロジェクトを追加するには、すべてのフィールドを記入してください。",
"read": "読み取り",
"read_write": "読み書き",
"security_updates_description": "脆弱性が発見された際に通知を受け取るため、セキュリティメーリングリストに登録してください。",
"security_updates_enroll": "今すぐ登録",
"security_updates_enrolled": "登録済み",
"security_updates_enrolled_description": "{email}でセキュリティアップデートを受信するよう登録されています。",
"security_updates_enrolled_successfully": "セキュリティアップデートの登録が完了しました",
"security_updates_enrolling": "登録中...",
"security_updates_title": "セキュリティアップデート",
"select_member": "メンバーを選択",
"select_project": "プロジェクトを選択",
"team_admin": "チーム管理者",

View File

@@ -475,14 +475,12 @@
"forgot_password_email_text": "U heeft een link aangevraagd om uw wachtwoord te wijzigen. Dit kunt u doen door op onderstaande link te klikken:",
"hidden_field": "Verborgen veld",
"imprint": "Afdruk",
"invite_accepted_email_heading": "Hoi",
"invite_accepted_email_heading": "Hé {inviterName}",
"invite_accepted_email_subject": "Je hebt een nieuw organisatielid!",
"invite_accepted_email_text_par1": "Laat het je gewoon weten",
"invite_accepted_email_text_par2": "heeft uw uitnodiging geaccepteerd. Veel plezier met samenwerken!",
"invite_accepted_email_text": "We wilden je even laten weten dat {inviteeName} je uitnodiging heeft geaccepteerd. Veel plezier met samenwerken!",
"invite_email_button_label": "Sluit je aan bij de organisatie",
"invite_email_heading": "Hoi",
"invite_email_text_par1": "Jouw collega",
"invite_email_text_par2": "nodigde je uit om je bij Formbricks aan te sluiten. Om de uitnodiging te accepteren, klikt u op de onderstaande link:",
"invite_email_heading": "Hé {inviteeName}",
"invite_email_text": "Je collega {inviterName} heeft je uitgenodigd om samen te werken bij Formbricks. Klik op onderstaande link om de uitnodiging te accepteren:",
"invite_member_email_subject": "Je bent uitgenodigd om samen te werken aan Formbricks!",
"new_email_verification_text": "Om uw nieuwe e-mailadres te verifiëren, klikt u op de onderstaande knop:",
"number_variable": "Numerieke variabele",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "Vul alle velden in om een nieuw project toe te voegen.",
"read": "Lezen",
"read_write": "Lezen en schrijven",
"security_updates_description": "Schrijf je in voor onze beveiligingsmailinglijst om op de hoogte te blijven als er kwetsbaarheden worden gevonden.",
"security_updates_enroll": "Nu inschrijven",
"security_updates_enrolled": "Ingeschreven",
"security_updates_enrolled_description": "Je bent ingeschreven om beveiligingsupdates te ontvangen op {email}.",
"security_updates_enrolled_successfully": "Succesvol ingeschreven voor beveiligingsupdates!",
"security_updates_enrolling": "Bezig met inschrijven...",
"security_updates_title": "Beveiligingsupdates",
"select_member": "Selecteer lid",
"select_project": "Selecteer project",
"team_admin": "Teambeheerder",

View File

@@ -474,15 +474,13 @@
"forgot_password_email_subject": "Redefinir sua senha Formbricks",
"forgot_password_email_text": "Você pediu um link pra trocar sua senha. Você pode fazer isso clicando no link abaixo:",
"hidden_field": "Campo oculto",
"imprint": "impressão",
"invite_accepted_email_heading": "E aí",
"imprint": "Impressum",
"invite_accepted_email_heading": "Olá, {inviterName}",
"invite_accepted_email_subject": "Você tem um novo membro na sua organização!",
"invite_accepted_email_text_par1": "Só pra te avisar que",
"invite_accepted_email_text_par2": "aceitou seu convite. Divirta-se colaborando!",
"invite_accepted_email_text": "Só para você saber que {inviteeName} aceitou seu convite. Divirta-se colaborando!",
"invite_email_button_label": "Entrar na organização",
"invite_email_heading": "E aí",
"invite_email_text_par1": "Seu colega",
"invite_email_text_par2": "te convidou para se juntar a eles na Formbricks. Para aceitar o convite, por favor clique no link abaixo:",
"invite_email_heading": "Olá, {inviteeName}",
"invite_email_text": "Seu colega {inviterName} convidou você para se juntar a ele no Formbricks. Para aceitar o convite, clique no link abaixo:",
"invite_member_email_subject": "Você foi convidado a colaborar no Formbricks!",
"new_email_verification_text": "Para verificar seu novo endereço de e-mail, clique no botão abaixo:",
"number_variable": "Variável numérica",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "Por favor, preencha todos os campos para adicionar um novo projeto.",
"read": "Leitura",
"read_write": "Leitura & Escrita",
"security_updates_description": "Inscreva-se na nossa lista de e-mails de segurança para ser informado caso vulnerabilidades sejam encontradas.",
"security_updates_enroll": "Inscrever-se agora",
"security_updates_enrolled": "Inscrito",
"security_updates_enrolled_description": "Você está inscrito para receber atualizações de segurança em {email}.",
"security_updates_enrolled_successfully": "Inscrito com sucesso para atualizações de segurança!",
"security_updates_enrolling": "Inscrevendo...",
"security_updates_title": "Atualizações de segurança",
"select_member": "Selecionar membro",
"select_project": "Selecionar projeto",
"team_admin": "Administrador da equipe",

View File

@@ -475,14 +475,12 @@
"forgot_password_email_text": "Solicitou um link para alterar a sua palavra-passe. Pode fazê-lo clicando no link abaixo:",
"hidden_field": "Campo oculto",
"imprint": "Impressão",
"invite_accepted_email_heading": "Olá",
"invite_accepted_email_heading": "Olá {inviterName}",
"invite_accepted_email_subject": "Tem um novo membro na organização!",
"invite_accepted_email_text_par1": "Só para te informar que",
"invite_accepted_email_text_par2": "aceitou o seu convite. Divirta-se a colaborar!",
"invite_accepted_email_text": "Só para informar que {inviteeName} aceitou o teu convite. Divirtam-se a colaborar!",
"invite_email_button_label": "Junte-se à organização",
"invite_email_heading": "Olá",
"invite_email_text_par1": "O seu colega",
"invite_email_text_par2": "convidou-o a juntar-se a eles no Formbricks. Para aceitar o convite, por favor clique no link abaixo:",
"invite_email_heading": "Olá {inviteeName}",
"invite_email_text": "O teu colega {inviterName} convidou-te para te juntares a ele no Formbricks. Para aceitar o convite, clica na ligação abaixo:",
"invite_member_email_subject": "Está convidado a colaborar no Formbricks!",
"new_email_verification_text": "Para verificar o seu novo endereço de email, por favor clique no botão abaixo:",
"number_variable": "Variável numérica",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "Por favor, preencha todos os campos para adicionar um novo projeto.",
"read": "Ler",
"read_write": "Ler e Escrever",
"security_updates_description": "Inscreva-se na nossa lista de correio de segurança para se manter informado caso sejam encontradas vulnerabilidades.",
"security_updates_enroll": "Inscrever agora",
"security_updates_enrolled": "Inscrito",
"security_updates_enrolled_description": "Está inscrito para receber atualizações de segurança em {email}.",
"security_updates_enrolled_successfully": "Inscrito com sucesso para atualizações de segurança!",
"security_updates_enrolling": "A inscrever...",
"security_updates_title": "Atualizações de segurança",
"select_member": "Selecionar membro",
"select_project": "Selecionar projeto",
"team_admin": "Administrador da Equipa",

View File

@@ -475,14 +475,12 @@
"forgot_password_email_text": "Ați solicitat un link pentru a vă schimba parola. Puteți face acest lucru făcând clic pe linkul de mai jos:",
"hidden_field": "Câmp ascuns",
"imprint": "Amprentă",
"invite_accepted_email_heading": "Salut",
"invite_accepted_email_heading": "Salut, {inviterName}",
"invite_accepted_email_subject": "Ai un nou membru în organizație!",
"invite_accepted_email_text_par1": "Doar te anunț că",
"invite_accepted_email_text_par2": "a acceptat invitația ta. Distracție plăcută colaborând!",
"invite_accepted_email_text": "Vrem doar să te anunțăm {inviteeName} a acceptat invitația ta. Spor la colaborare!",
"invite_email_button_label": "Alătură-te organizației",
"invite_email_heading": "Hei",
"invite_email_text_par1": "Colegul tău",
"invite_email_text_par2": "te-a invitat să li te alături la Formbricks. Pentru a accepta invitația, te rugăm să dai click pe linkul de mai jos:",
"invite_email_heading": "Salut, {inviteeName}",
"invite_email_text": "Colegul tău, {inviterName}, te-a invitat să i te alături pe Formbricks. Pentru a accepta invitația, te rugăm să dai click pe linkul de mai jos:",
"invite_member_email_subject": "Ești invitat să colaborezi pe Formbricks!",
"new_email_verification_text": "Pentru a verifica noua dumneavoastră adresă de email, vă rugăm să faceți clic pe butonul de mai jos:",
"number_variable": "Variabilă numerică",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "Vă rugăm să completați toate câmpurile pentru a adăuga un proiect nou.",
"read": "Citește",
"read_write": "Citire & Scriere",
"security_updates_description": "Înscrie-te la lista noastră de e-mailuri de securitate pentru a fi informat dacă sunt descoperite vulnerabilități.",
"security_updates_enroll": "Înscrie-te acum",
"security_updates_enrolled": "Înscris",
"security_updates_enrolled_description": "Ești înscris pentru a primi actualizări de securitate la {email}.",
"security_updates_enrolled_successfully": "Înscriere reușită pentru actualizările de securitate!",
"security_updates_enrolling": "Se înscrie...",
"security_updates_title": "Actualizări de securitate",
"select_member": "Selectează membrul",
"select_project": "Selectează proiectul",
"team_admin": "Administrator Echipe",

2960
apps/web/locales/ru-RU.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -475,14 +475,12 @@
"forgot_password_email_text": "Du har begärt en länk för att ändra ditt lösenord. Du kan göra detta genom att klicka på länken nedan:",
"hidden_field": "Dolt fält",
"imprint": "Impressum",
"invite_accepted_email_heading": "Hej",
"invite_accepted_email_heading": "Hej {inviterName}",
"invite_accepted_email_subject": "Du har fått en ny organisationsmedlem!",
"invite_accepted_email_text_par1": "Vi vill bara meddela dig att",
"invite_accepted_email_text_par2": "accepterade din inbjudan. Ha kul med samarbetet!",
"invite_accepted_email_text": "Vi vill bara meddela att {inviteeName} har accepterat din inbjudan. Ha det så kul med samarbetet!",
"invite_email_button_label": "Gå med i organisation",
"invite_email_heading": "Hej",
"invite_email_text_par1": "Din kollega",
"invite_email_text_par2": "bjöd in dig att gå med dem på Formbricks. För att acceptera inbjudan, vänligen klicka på länken nedan:",
"invite_email_heading": "Hej {inviteeName}",
"invite_email_text": "Din kollega {inviterName} har bjudit in dig att gå med dem på Formbricks. För att acceptera inbjudan, klicka på länken nedan:",
"invite_member_email_subject": "Du är inbjuden att samarbeta på Formbricks!",
"new_email_verification_text": "För att verifiera din nya e-postadress, vänligen klicka på knappen nedan:",
"number_variable": "Nummervariabel",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "Vänligen fyll i alla fält för att lägga till ett nytt projekt.",
"read": "Läs",
"read_write": "Läs och skriv",
"security_updates_description": "Anmäl dig till vår säkerhetsmejllista för att hålla dig informerad om sårbarheter upptäcks.",
"security_updates_enroll": "Anmäl dig nu",
"security_updates_enrolled": "Anmäld",
"security_updates_enrolled_description": "Du är anmäld för att ta emot säkerhetsuppdateringar på {email}.",
"security_updates_enrolled_successfully": "Du har anmälts för säkerhetsuppdateringar!",
"security_updates_enrolling": "Anmäler...",
"security_updates_title": "Säkerhetsuppdateringar",
"select_member": "Välj medlem",
"select_project": "Välj projekt",
"team_admin": "Teamadministratör",

View File

@@ -475,14 +475,12 @@
"forgot_password_email_text": "您 已 请求 一个 链接 来 更改 您的 密码。 您 可以 点击 下方 链接 完成 这个 操作:",
"hidden_field": "隐藏字段",
"imprint": "印记",
"invite_accepted_email_heading": "",
"invite_accepted_email_heading": "你好,{inviterName}",
"invite_accepted_email_subject": "你 有 一个 新 成员 进入 组织 了!",
"invite_accepted_email_text_par1": "只是 告诉 你",
"invite_accepted_email_text_par2": "接受了 你的 邀请。 合作 愉快!",
"invite_accepted_email_text": "{inviteeName} 已接受了你的邀请。祝你们合作愉快!",
"invite_email_button_label": "加入 组织",
"invite_email_heading": "",
"invite_email_text_par1": "您的 同事",
"invite_email_text_par2": "邀请您加入他们在 Formbricks 。要接受邀请,请点击下面的链接:",
"invite_email_heading": "你好,{inviteeName}",
"invite_email_text": "你的同事 {inviterName} 邀请你加入 Formbricks。要接受邀请请点击下方链接",
"invite_member_email_subject": "您 被 邀请 来 协作 于 Formbricks",
"new_email_verification_text": "要 验证 您 的 新 邮箱 地址 ,请 点击 下方 的 按钮 ",
"number_variable": "数字变量",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "请 填写 所有 字段 以 添加 新 项目。",
"read": "阅读",
"read_write": "读 & 写",
"security_updates_description": "加入我们的安全邮件列表,及时了解发现的安全漏洞信息。",
"security_updates_enroll": "立即加入",
"security_updates_enrolled": "已加入",
"security_updates_enrolled_description": "您已加入安全更新通知,相关信息将发送至 {email}。",
"security_updates_enrolled_successfully": "已成功加入安全更新通知!",
"security_updates_enrolling": "正在加入...",
"security_updates_title": "安全更新",
"select_member": "选择成员",
"select_project": "选择项目",
"team_admin": "团队管理员",

View File

@@ -475,14 +475,12 @@
"forgot_password_email_text": "您已請求變更密碼的連結。您可以點擊以下連結來執行此操作:",
"hidden_field": "隱藏欄位",
"imprint": "版本訊息",
"invite_accepted_email_heading": "嗨",
"invite_accepted_email_heading": "嗨{inviterName}",
"invite_accepted_email_subject": "您有一位新的組織成員!",
"invite_accepted_email_text_par1": "通知您,",
"invite_accepted_email_text_par2": "接受了您的邀請。合作愉快!",
"invite_accepted_email_text": "通知你,{inviteeName} 已經接受了你的邀請。祝你們合作愉快!",
"invite_email_button_label": "加入組織",
"invite_email_heading": "嗨",
"invite_email_text_par1": "的同事",
"invite_email_text_par2": "邀請您加入 Formbricks。若要接受邀請請點擊以下連結",
"invite_email_heading": "嗨{inviteeName}",
"invite_email_text": "的同事 {inviterName} 邀請你加入他們在 Formbricks。請點擊下方連結以接受邀請",
"invite_member_email_subject": "您被邀請協作 Formbricks",
"new_email_verification_text": "要驗證您的新電子郵件地址,請點擊下面的按鈕:",
"number_variable": "數字變數",
@@ -1182,6 +1180,13 @@
"please_fill_all_project_fields": "請填寫所有欄位以新增新專案。",
"read": "讀取",
"read_write": "讀取和寫入",
"security_updates_description": "加入我們的安全郵件名單,隨時掌握漏洞相關資訊。",
"security_updates_enroll": "立即加入",
"security_updates_enrolled": "已加入",
"security_updates_enrolled_description": "您已加入安全更新通知,將會寄送至 {email}。",
"security_updates_enrolled_successfully": "已成功加入安全更新通知!",
"security_updates_enrolling": "正在加入...",
"security_updates_title": "安全更新",
"select_member": "選擇成員",
"select_project": "選擇專案",
"team_admin": "團隊管理員",

View File

@@ -183,7 +183,7 @@ export async function PreviewEmailTemplate({
{ctaElement.buttonExternal && ctaElement.ctaButtonLabel && ctaElement.buttonUrl && (
<Container className="mx-0 mt-4 flex max-w-none items-center justify-end">
<EmailButton
className="text-question-color flex items-center rounded-md border-0 bg-transparent px-3 py-3 text-base font-medium leading-4 no-underline shadow-none"
className="text-question-color flex items-center rounded-md border-0 bg-transparent px-3 py-3 text-base leading-4 font-medium no-underline shadow-none"
href={ctaElement.buttonUrl}>
<Text className="inline">
{getLocalizedValue(ctaElement.ctaButtonLabel, defaultLanguageCode)}{" "}
@@ -306,13 +306,13 @@ export async function PreviewEmailTemplate({
{firstQuestion.choices.map((choice) =>
firstQuestion.allowMulti ? (
<Img
className="rounded-custom mb-3 mr-3 inline-block h-[150px] w-[250px]"
className="rounded-custom mr-3 mb-3 inline-block h-[150px] w-[250px]"
key={choice.id}
src={choice.imageUrl}
/>
) : (
<Link
className="rounded-custom mb-3 mr-3 inline-block h-[150px] w-[250px]"
className="rounded-custom mr-3 mb-3 inline-block h-[150px] w-[250px]"
href={`${urlWithPrefilling}${firstQuestion.id}=${choice.id}`}
key={choice.id}
target="_blank">
@@ -360,11 +360,11 @@ export async function PreviewEmailTemplate({
<Container className="mx-0">
<Section className="w-full table-auto">
<Row>
<Column className="w-40 break-words px-4 py-2" />
<Column className="w-40 px-4 py-2 break-words" />
{firstQuestion.columns.map((column) => {
return (
<Column
className="text-question-color max-w-40 break-words px-4 py-2 text-center"
className="text-question-color max-w-40 px-4 py-2 text-center break-words"
key={column.id}>
{getLocalizedValue(column.label, "default")}
</Column>
@@ -376,7 +376,7 @@ export async function PreviewEmailTemplate({
<Row
className={`${rowIndex % 2 === 0 ? "bg-input-color" : ""} rounded-custom`}
key={row.id}>
<Column className="w-40 break-words px-4 py-2">
<Column className="w-40 px-4 py-2 break-words">
{getLocalizedValue(row.label, "default")}
</Column>
{firstQuestion.columns.map((column) => {

View File

@@ -24,6 +24,7 @@ import {
getOrganizationOwnerCount,
} from "@/modules/organization/settings/teams/lib/membership";
import { deleteInvite, getInvite, inviteUser, resendInvite } from "./lib/invite";
import { enrollInSecurityUpdates } from "./lib/security-updates";
const ZDeleteInviteAction = z.object({
inviteId: ZUuid,
@@ -387,3 +388,39 @@ export const leaveOrganizationAction = authenticatedActionClient.schema(ZLeaveOr
}
)
);
const ZEnrollSecurityUpdatesAction = z.object({
organizationId: ZId,
});
export const enrollSecurityUpdatesAction = authenticatedActionClient
.schema(ZEnrollSecurityUpdatesAction)
.action(async ({ ctx, parsedInput }) => {
// Ensure this is only called for self-hosted instances
if (IS_FORMBRICKS_CLOUD) {
throw new OperationNotAllowedError(
"Security updates enrollment is only available for self-hosted instances"
);
}
// Only owners can enroll in security updates
await checkAuthorizationUpdated({
userId: ctx.user.id,
organizationId: parsedInput.organizationId,
access: [
{
type: "organization",
roles: ["owner"],
},
],
});
// Enroll with the current user's email
const result = await enrollInSecurityUpdates(ctx.user.email);
if (!result.success) {
throw new Error("Failed to enroll in security updates");
}
return { success: true };
});

View File

@@ -0,0 +1,98 @@
"use client";
import { ShieldCheckIcon } from "lucide-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-hot-toast";
import { useTranslation } from "react-i18next";
import { cn } from "@/lib/cn";
import { getFormattedErrorMessage } from "@/lib/utils/helper";
import { enrollSecurityUpdatesAction } from "@/modules/organization/settings/teams/actions";
import { TSecurityUpdatesStatus } from "@/modules/organization/settings/teams/lib/security-updates";
import { Button } from "@/modules/ui/components/button";
import { H4, P } from "@/modules/ui/components/typography";
interface SecurityUpdatesCardProps {
organizationId: string;
userEmail: string;
securityUpdatesStatus: TSecurityUpdatesStatus;
}
export const SecurityUpdatesCard = ({
organizationId,
userEmail,
securityUpdatesStatus,
}: SecurityUpdatesCardProps) => {
const router = useRouter();
const { t } = useTranslation();
const [isEnrolling, setIsEnrolling] = useState(false);
const handleEnroll = async () => {
setIsEnrolling(true);
try {
const result = await enrollSecurityUpdatesAction({ organizationId });
if (result?.data?.success) {
toast.success(t("environments.settings.teams.security_updates_enrolled_successfully"));
router.refresh();
} else {
const errorMessage = getFormattedErrorMessage(result);
toast.error(errorMessage);
}
} catch (error) {
toast.error(t("common.something_went_wrong_please_try_again"));
console.error(error);
} finally {
setIsEnrolling(false);
}
};
const isEnrolled = securityUpdatesStatus.enrolled;
return (
<div
className={cn(
"relative my-4 w-full max-w-4xl rounded-xl border bg-white shadow-sm",
isEnrolled ? "border-green-200 bg-green-50" : "border-slate-200"
)}>
<div className="flex items-start justify-between p-6">
<div className="flex items-start gap-4">
<div
className={cn(
"flex h-10 w-10 items-center justify-center rounded-full",
isEnrolled ? "bg-green-100" : "bg-slate-100"
)}>
<ShieldCheckIcon className={cn("h-5 w-5", isEnrolled ? "text-green-600" : "text-slate-600")} />
</div>
<div className="flex flex-col gap-1">
<H4 className="font-medium tracking-normal">
{t("environments.settings.teams.security_updates_title")}
</H4>
<P className="!mt-0 text-sm text-slate-500">
{isEnrolled
? t("environments.settings.teams.security_updates_enrolled_description", {
email: securityUpdatesStatus.email || userEmail,
})
: t("environments.settings.teams.security_updates_description")}
</P>
</div>
</div>
{!isEnrolled && (
<Button onClick={handleEnroll} disabled={isEnrolling} className="shrink-0">
{isEnrolling
? t("environments.settings.teams.security_updates_enrolling")
: t("environments.settings.teams.security_updates_enroll")}
</Button>
)}
{isEnrolled && (
<div className="flex items-center gap-2 rounded-full bg-green-100 px-3 py-1">
<div className="h-2 w-2 rounded-full bg-green-500" />
<span className="text-sm font-medium text-green-700">
{t("environments.settings.teams.security_updates_enrolled")}
</span>
</div>
)}
</div>
</div>
);
};

View File

@@ -0,0 +1,68 @@
"use server";
import { getInstanceId } from "@/lib/instance";
export type TSecurityUpdatesStatus = {
enrolled: boolean;
email?: string;
};
/**
* Checks if the current instance is enrolled in security updates.
*
* TODO: Replace with actual EE server call
* GET /security-updates/status?instanceId=xxx
*
* @returns The enrollment status and email if enrolled
*/
export const getSecurityUpdatesStatus = async (): Promise<TSecurityUpdatesStatus> => {
const instanceId = await getInstanceId();
if (!instanceId) {
return { enrolled: false };
}
// TODO: Replace with actual EE server call
// const response = await fetch(`${EE_SERVER_URL}/instances/${instanceId}/security-updates`);
// if (!response.ok) {
// return { enrolled: false };
// }
// return await response.json();
// Mock: Always return not enrolled for now
return { enrolled: false };
};
/**
* Enrolls the current instance in security updates.
*
* TODO: Replace with actual EE server call
* POST /security-updates/enroll { instanceId, email }
*
* @param email - The email address to receive security updates
* @returns Success status
*/
export const enrollInSecurityUpdates = async (email: string): Promise<{ success: boolean }> => {
const instanceId = await getInstanceId();
if (!instanceId) {
throw new Error("Instance ID not found");
}
// TODO: Replace with actual EE server call
// const response = await fetch(`${EE_SERVER_URL}/instances/${instanceId}/security-updates`, {
// method: "POST",
// headers: { "Content-Type": "application/json" },
// body: JSON.stringify({ instanceId, email }),
// });
//
// if (!response.ok) {
// throw new Error("Failed to enroll in security updates");
// }
//
// return await response.json();
// Mock: Always succeed for now
console.log(`[Mock] Enrolling instance ${instanceId} with email ${email}`);
return { success: true };
};

View File

@@ -1,20 +1,25 @@
import { OrganizationSettingsNavbar } from "@/app/(app)/environments/[environmentId]/settings/(organization)/components/OrganizationSettingsNavbar";
import { IS_FORMBRICKS_CLOUD, USER_MANAGEMENT_MINIMUM_ROLE } from "@/lib/constants";
import { getUserManagementAccess } from "@/lib/membership/utils";
import { getUser } from "@/lib/user/service";
import { getTranslate } from "@/lingodotdev/server";
import { getAccessControlPermission } from "@/modules/ee/license-check/lib/utils";
import { getTeamsWhereUserIsAdmin } from "@/modules/ee/teams/lib/roles";
import { TeamsView } from "@/modules/ee/teams/team-list/components/teams-view";
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
import { MembersView } from "@/modules/organization/settings/teams/components/members-view";
import { SecurityUpdatesCard } from "@/modules/organization/settings/teams/components/security-updates-card";
import { getSecurityUpdatesStatus } from "@/modules/organization/settings/teams/lib/security-updates";
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
import { PageHeader } from "@/modules/ui/components/page-header";
export const TeamsPage = async (props) => {
export const TeamsPage = async (props: { params: Promise<{ environmentId: string }> }) => {
const params = await props.params;
const t = await getTranslate();
const { session, currentUserMembership, organization } = await getEnvironmentAuth(params.environmentId);
const { session, currentUserMembership, organization, isOwner } = await getEnvironmentAuth(
params.environmentId
);
const isAccessControlAllowed = await getAccessControlPermission(organization.billing.plan);
@@ -32,6 +37,12 @@ export const TeamsPage = async (props) => {
const hasUserManagementAccess =
hasStandardUserManagementAccess || (isAccessControlAllowed && isTeamAdminUser);
// Fetch security updates status for self-hosted instances only (owners only)
const shouldShowSecurityUpdates = !IS_FORMBRICKS_CLOUD && isOwner;
const [securityUpdatesStatus, user] = shouldShowSecurityUpdates
? await Promise.all([getSecurityUpdatesStatus(), getUser(session.user.id)])
: [null, null];
return (
<PageContentWrapper>
<PageHeader pageTitle={t("environments.settings.general.organization_settings")}>
@@ -42,6 +53,15 @@ export const TeamsPage = async (props) => {
activeId="teams"
/>
</PageHeader>
{securityUpdatesStatus && user && (
<SecurityUpdatesCard
organizationId={organization.id}
userEmail={user.email}
securityUpdatesStatus={securityUpdatesStatus}
/>
)}
<MembersView
membershipRole={currentUserMembership?.role}
organization={organization}

View File

@@ -442,7 +442,4 @@ const sentryOptions = {
// Runtime Sentry reporting still depends on DSN being set via environment variables
const exportConfig = process.env.SENTRY_AUTH_TOKEN ? withSentryConfig(nextConfig, sentryOptions) : nextConfig;
console.log("BASE PATH", nextConfig.basePath);
export default exportConfig;

View File

@@ -221,6 +221,7 @@ vi.mock("@/lib/constants", () => ({
"zh-Hans-CN",
"es-ES",
"sv-SE",
"ru-RU",
],
DEFAULT_LOCALE: "en-US",
BREVO_API_KEY: "mock-brevo-api-key",

View File

@@ -21,13 +21,8 @@ export function InviteAcceptedEmail({
return (
<EmailTemplate t={t} {...legalProps}>
<Container>
<Heading>
{t("emails.invite_accepted_email_heading", { inviterName })} {inviterName}
</Heading>
<Text className="text-sm">
{t("emails.invite_accepted_email_text_par1", { inviteeName })} {inviteeName}{" "}
{t("emails.invite_accepted_email_text_par2")}
</Text>
<Heading>{t("emails.invite_accepted_email_heading", { inviterName })}</Heading>
<Text className="text-sm">{t("emails.invite_accepted_email_text", { inviteeName })}</Text>
<EmailFooter t={t} />
</Container>
</EmailTemplate>

View File

@@ -24,13 +24,8 @@ export function InviteEmail({
return (
<EmailTemplate t={t} {...legalProps}>
<Container>
<Heading>
{t("emails.invite_email_heading", { inviteeName })} {inviteeName}
</Heading>
<Text className="text-sm">
{t("emails.invite_email_text_par1", { inviterName })} {inviterName}{" "}
{t("emails.invite_email_text_par2")}
</Text>
<Heading>{t("emails.invite_email_heading", { inviteeName })}</Heading>
<Text className="text-sm">{t("emails.invite_email_text", { inviterName })}</Text>
<EmailButton href={verifyLink} label={t("emails.invite_email_button_label")} />
<EmailFooter t={t} />
</Container>

View File

@@ -10,11 +10,11 @@ interface ElementHeaderProps {
export function ElementHeader({ headline, subheader, className }: ElementHeaderProps): React.JSX.Element {
return (
<>
<Container className={cn("text-question-color m-0 block text-base font-semibold leading-6", className)}>
<Container className={cn("text-question-color m-0 block text-base leading-6 font-semibold", className)}>
<div dangerouslySetInnerHTML={{ __html: headline }} />
</Container>
{subheader && (
<Container className="text-question-color m-0 mt-2 block p-0 text-sm font-normal leading-6">
<Container className="text-question-color m-0 mt-2 block p-0 text-sm leading-6 font-normal">
<div dangerouslySetInnerHTML={{ __html: subheader }} />
</Container>
)}

File diff suppressed because it is too large Load Diff

View File

@@ -145,6 +145,7 @@ interface UploadAreaProps {
onDragOver: (e: React.DragEvent<HTMLLabelElement>) => void;
onDrop: (e: React.DragEvent<HTMLLabelElement>) => void;
showUploader: boolean;
uploadedFiles: UploadedFile[];
}
function UploadArea({
@@ -160,6 +161,7 @@ function UploadArea({
onDragOver,
onDrop,
showUploader,
uploadedFiles,
}: Readonly<UploadAreaProps>): React.JSX.Element | null {
if (!showUploader) {
return null;
@@ -201,7 +203,7 @@ function UploadArea({
accept={acceptAttribute}
onChange={onFileChange}
disabled={disabled}
required={required}
required={uploadedFiles.length > 0 ? false : required}
dir={dir}
aria-label="File upload"
aria-describedby={`${inputId}-label`}
@@ -323,6 +325,7 @@ function FileUpload({
onDragOver={handleDragOver}
onDrop={handleDrop}
showUploader={showUploader}
uploadedFiles={uploadedFiles}
/>
</div>
</div>

View File

@@ -13,6 +13,7 @@ export const ZUserLocale = z.enum([
"zh-Hans-CN",
"es-ES",
"sv-SE",
"ru-RU",
]);
export type TUserLocale = z.infer<typeof ZUserLocale>;