mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-25 03:10:22 -05:00
fix: update project config navbar + wording (#4918)
This commit is contained in:
+2
-2
@@ -27,7 +27,7 @@ export const EditAlerts = ({
|
||||
return (
|
||||
<>
|
||||
{memberships.map((membership) => (
|
||||
<>
|
||||
<div key={membership.organization.id}>
|
||||
<div className="mb-5 grid grid-cols-6 items-center space-x-3">
|
||||
<div className="col-span-3 flex items-center space-x-3">
|
||||
<UsersIcon className="h-6 w-7 text-slate-600" />
|
||||
@@ -110,7 +110,7 @@ export const EditAlerts = ({
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ export const EditWeeklySummary = ({ memberships, user, environmentId }: EditAler
|
||||
return (
|
||||
<>
|
||||
{memberships.map((membership) => (
|
||||
<>
|
||||
<div key={membership.organization.id}>
|
||||
<div className="mb-5 flex items-center space-x-3 text-sm font-medium">
|
||||
<UsersIcon className="h-6 w-7 text-slate-600" />
|
||||
|
||||
@@ -52,7 +52,7 @@ export const EditWeeklySummary = ({ memberships, user, environmentId }: EditAler
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -9,8 +9,10 @@ import { UpgradePrompt } from "@/modules/ui/components/upgrade-prompt";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { IS_FORMBRICKS_CLOUD } from "@formbricks/lib/constants";
|
||||
import { getOrganizationsWhereUserIsSingleOwner } from "@formbricks/lib/organization/service";
|
||||
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
|
||||
import {
|
||||
getOrganizationByEnvironmentId,
|
||||
getOrganizationsWhereUserIsSingleOwner,
|
||||
} from "@formbricks/lib/organization/service";
|
||||
import { getUser } from "@formbricks/lib/user/service";
|
||||
import { SettingsCard } from "../../components/SettingsCard";
|
||||
import { DeleteAccount } from "./components/DeleteAccount";
|
||||
@@ -71,7 +73,9 @@ const Page = async (props: { params: Promise<{ environmentId: string }> }) => {
|
||||
description={t("environments.settings.profile.two_factor_authentication_description")}
|
||||
buttons={[
|
||||
{
|
||||
text: t("common.start_free_trial"),
|
||||
text: IS_FORMBRICKS_CLOUD
|
||||
? t("common.start_free_trial")
|
||||
: t("common.request_trial_license"),
|
||||
href: IS_FORMBRICKS_CLOUD
|
||||
? `/environments/${params.environmentId}/settings/billing`
|
||||
: "https://formbricks.com/upgrade-self-hosting-license",
|
||||
|
||||
@@ -95,7 +95,7 @@ export const ContactsPage = async ({
|
||||
description={t("environments.contacts.unlock_contacts_description")}
|
||||
buttons={[
|
||||
{
|
||||
text: t("common.start_free_trial"),
|
||||
text: IS_FORMBRICKS_CLOUD ? t("common.start_free_trial") : t("common.request_trial_license"),
|
||||
href: IS_FORMBRICKS_CLOUD
|
||||
? `/environments/${params.environmentId}/settings/billing`
|
||||
: "https://formbricks.com/upgrade-self-hosting-license",
|
||||
|
||||
@@ -100,7 +100,7 @@ export const SegmentsPage = async ({
|
||||
description={t("environments.segments.unlock_segments_description")}
|
||||
buttons={[
|
||||
{
|
||||
text: t("common.start_free_trial"),
|
||||
text: IS_FORMBRICKS_CLOUD ? t("common.start_free_trial") : t("common.request_trial_license"),
|
||||
href: IS_FORMBRICKS_CLOUD
|
||||
? `/environments/${params.environmentId}/settings/billing`
|
||||
: "https://formbricks.com/upgrade-self-hosting-license",
|
||||
|
||||
@@ -11,7 +11,7 @@ export const LanguagesLoading = () => {
|
||||
const { t } = useTranslate();
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation activeId="languages" loading />
|
||||
</PageHeader>
|
||||
<SettingsCard
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import {
|
||||
getMultiLanguagePermission,
|
||||
getRoleManagementPermission,
|
||||
} from "@/modules/ee/license-check/lib/utils";
|
||||
import { getMultiLanguagePermission } from "@/modules/ee/license-check/lib/utils";
|
||||
import { EditLanguage } from "@/modules/ee/multi-language-surveys/components/edit-language";
|
||||
import { getProjectPermissionByUserId } from "@/modules/ee/teams/lib/roles";
|
||||
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
|
||||
@@ -12,7 +9,7 @@ import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper
|
||||
import { PageHeader } from "@/modules/ui/components/page-header";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { notFound } from "next/navigation";
|
||||
import { IS_FORMBRICKS_CLOUD } from "@formbricks/lib/constants";
|
||||
import { getMembershipByUserIdOrganizationId } from "@formbricks/lib/membership/service";
|
||||
import { getAccessFlags } from "@formbricks/lib/membership/utils";
|
||||
import { getOrganization } from "@formbricks/lib/organization/service";
|
||||
@@ -35,11 +32,6 @@ export const LanguagesPage = async (props: { params: Promise<{ environmentId: st
|
||||
}
|
||||
|
||||
const isMultiLanguageAllowed = await getMultiLanguagePermission(organization.billing.plan);
|
||||
if (!isMultiLanguageAllowed) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const canDoRoleManagement = await getRoleManagementPermission(organization.billing.plan);
|
||||
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
@@ -63,18 +55,20 @@ export const LanguagesPage = async (props: { params: Promise<{ environmentId: st
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<ProjectConfigNavigation
|
||||
environmentId={params.environmentId}
|
||||
activeId="languages"
|
||||
isMultiLanguageAllowed={isMultiLanguageAllowed}
|
||||
canDoRoleManagement={canDoRoleManagement}
|
||||
/>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation environmentId={params.environmentId} activeId="languages" />
|
||||
</PageHeader>
|
||||
<SettingsCard
|
||||
title={t("environments.project.languages.multi_language_surveys")}
|
||||
description={t("environments.project.languages.multi_language_surveys_description")}>
|
||||
<EditLanguage project={project} locale={user.locale} isReadOnly={isReadOnly} />
|
||||
<EditLanguage
|
||||
project={project}
|
||||
locale={user.locale}
|
||||
isReadOnly={isReadOnly}
|
||||
isMultiLanguageAllowed={isMultiLanguageAllowed}
|
||||
environmentId={params.environmentId}
|
||||
isFormbricksCloud={IS_FORMBRICKS_CLOUD}
|
||||
/>
|
||||
</SettingsCard>
|
||||
</PageContentWrapper>
|
||||
);
|
||||
|
||||
@@ -4,9 +4,9 @@ import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { Alert, AlertDescription } from "@/modules/ui/components/alert";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { ConfirmationModal } from "@/modules/ui/components/confirmation-modal";
|
||||
import { ModalButton, UpgradePrompt } from "@/modules/ui/components/upgrade-prompt";
|
||||
import { Language } from "@prisma/client";
|
||||
import { useTranslate } from "@tolgee/react";
|
||||
import { TFnType } from "@tolgee/react";
|
||||
import { TFnType, useTranslate } from "@tolgee/react";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
@@ -26,6 +26,9 @@ interface EditLanguageProps {
|
||||
project: TProject;
|
||||
locale: TUserLocale;
|
||||
isReadOnly: boolean;
|
||||
isMultiLanguageAllowed: boolean;
|
||||
environmentId: string;
|
||||
isFormbricksCloud: boolean;
|
||||
}
|
||||
|
||||
const checkIfDuplicateExists = (arr: string[]) => {
|
||||
@@ -57,7 +60,7 @@ const validateLanguages = (languages: Language[], t: TFnType) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the chosen alias matches an ISO identifier of a language that hasn’t been added
|
||||
// Check if the chosen alias matches an ISO identifier of a language that hasn't been added
|
||||
for (const alias of languageAliases) {
|
||||
if (iso639Languages.some((language) => language.alpha2 === alias && !languageCodes.includes(alias))) {
|
||||
toast.error(t("environments.project.languages.conflict_between_selected_alias_and_another_language"), {
|
||||
@@ -70,7 +73,14 @@ const validateLanguages = (languages: Language[], t: TFnType) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
export function EditLanguage({ project, locale, isReadOnly }: EditLanguageProps) {
|
||||
export function EditLanguage({
|
||||
project,
|
||||
locale,
|
||||
isReadOnly,
|
||||
isMultiLanguageAllowed,
|
||||
environmentId,
|
||||
isFormbricksCloud,
|
||||
}: EditLanguageProps) {
|
||||
const { t } = useTranslate();
|
||||
const [languages, setLanguages] = useState<Language[]>(project.languages);
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
@@ -150,6 +160,21 @@ export function EditLanguage({ project, locale, isReadOnly }: EditLanguageProps)
|
||||
setIsEditing(false);
|
||||
};
|
||||
|
||||
const buttons: [ModalButton, ModalButton] = [
|
||||
{
|
||||
text: isFormbricksCloud ? t("common.start_free_trial") : t("common.request_trial_license"),
|
||||
href: isFormbricksCloud
|
||||
? `/environments/${environmentId}/settings/billing`
|
||||
: "https://formbricks.com/upgrade-self-hosting-license",
|
||||
},
|
||||
{
|
||||
text: t("common.learn_more"),
|
||||
href: isFormbricksCloud
|
||||
? `/environments/${environmentId}/settings/billing`
|
||||
: "https://formbricks.com/learn-more-self-hosting-license",
|
||||
},
|
||||
];
|
||||
|
||||
const handleSaveChanges = async () => {
|
||||
if (!validateLanguages(languages, t)) return;
|
||||
await Promise.all(
|
||||
@@ -179,63 +204,75 @@ export function EditLanguage({ project, locale, isReadOnly }: EditLanguageProps)
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div className="space-y-4">
|
||||
{languages.length > 0 ? (
|
||||
<>
|
||||
<LanguageLabels />
|
||||
{languages.map((language, index) => (
|
||||
<LanguageRow
|
||||
index={index}
|
||||
isEditing={isEditing}
|
||||
key={language.id}
|
||||
language={language}
|
||||
locale={locale}
|
||||
onDelete={() => handleDeleteLanguage(language.id)}
|
||||
onLanguageChange={(newLanguage: Language) => {
|
||||
const updatedLanguages = [...languages];
|
||||
updatedLanguages[index] = newLanguage;
|
||||
setLanguages(updatedLanguages);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<p className="text-sm italic text-slate-500">
|
||||
{t("environments.project.languages.no_language_found")}
|
||||
</p>
|
||||
)}
|
||||
<AddLanguageButton onClick={handleAddLanguage} />
|
||||
</div>
|
||||
<EditSaveButtons
|
||||
isEditing={isEditing}
|
||||
onCancel={handleCancelChanges}
|
||||
disabled={isReadOnly}
|
||||
onEdit={() => {
|
||||
setIsEditing(true);
|
||||
}}
|
||||
onSave={handleSaveChanges}
|
||||
t={t}
|
||||
/>
|
||||
{isReadOnly && (
|
||||
<Alert variant="warning" className="mt-4">
|
||||
<AlertDescription>
|
||||
{t("common.only_owners_managers_and_manage_access_members_can_perform_this_action")}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<>
|
||||
{isMultiLanguageAllowed ? (
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div className="space-y-4">
|
||||
{languages.length > 0 ? (
|
||||
<>
|
||||
<LanguageLabels />
|
||||
{languages.map((language, index) => (
|
||||
<LanguageRow
|
||||
index={index}
|
||||
isEditing={isEditing}
|
||||
key={language.id}
|
||||
language={language}
|
||||
locale={locale}
|
||||
onDelete={() => handleDeleteLanguage(language.id)}
|
||||
onLanguageChange={(newLanguage: Language) => {
|
||||
const updatedLanguages = [...languages];
|
||||
updatedLanguages[index] = newLanguage;
|
||||
setLanguages(updatedLanguages);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<p className="text-sm italic text-slate-500">
|
||||
{t("environments.project.languages.no_language_found")}
|
||||
</p>
|
||||
)}
|
||||
<AddLanguageButton onClick={handleAddLanguage} />
|
||||
</div>
|
||||
<EditSaveButtons
|
||||
isEditing={isEditing}
|
||||
onCancel={handleCancelChanges}
|
||||
disabled={isReadOnly}
|
||||
onEdit={() => {
|
||||
setIsEditing(true);
|
||||
}}
|
||||
onSave={handleSaveChanges}
|
||||
t={t}
|
||||
/>
|
||||
{isReadOnly && (
|
||||
<Alert variant="warning" className="mt-4">
|
||||
<AlertDescription>
|
||||
{t("common.only_owners_managers_and_manage_access_members_can_perform_this_action")}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
<ConfirmationModal
|
||||
buttonText={t("environments.project.languages.remove_language")}
|
||||
isButtonDisabled={confirmationModal.isButtonDisabled}
|
||||
onConfirm={() => performLanguageDeletion(confirmationModal.languageId)}
|
||||
open={confirmationModal.isOpen}
|
||||
setOpen={() => {
|
||||
setConfirmationModal((prev) => ({ ...prev, isOpen: !prev.isOpen }));
|
||||
}}
|
||||
text={confirmationModal.text}
|
||||
title={t("environments.project.languages.remove_language")}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<UpgradePrompt
|
||||
title={t("environments.settings.general.use_multi_language_surveys_with_a_higher_plan")}
|
||||
description={t(
|
||||
"environments.settings.general.use_multi_language_surveys_with_a_higher_plan_description"
|
||||
)}
|
||||
buttons={buttons}
|
||||
/>
|
||||
)}
|
||||
<ConfirmationModal
|
||||
buttonText={t("environments.project.languages.remove_language")}
|
||||
isButtonDisabled={confirmationModal.isButtonDisabled}
|
||||
onConfirm={() => performLanguageDeletion(confirmationModal.languageId)}
|
||||
open={confirmationModal.isOpen}
|
||||
setOpen={() => {
|
||||
setConfirmationModal((prev) => ({ ...prev, isOpen: !prev.isOpen }));
|
||||
}}
|
||||
text={confirmationModal.text}
|
||||
title={t("environments.project.languages.remove_language")}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -230,7 +230,9 @@ export const MultiLanguageCard: FC<MultiLanguageCardProps> = ({
|
||||
description={t("environments.surveys.edit.upgrade_notice_description")}
|
||||
buttons={[
|
||||
{
|
||||
text: t("common.start_free_trial"),
|
||||
text: isFormbricksCloud
|
||||
? t("common.start_free_trial")
|
||||
: t("common.request_trial_license"),
|
||||
href: isFormbricksCloud
|
||||
? `/environments/${environmentId}/settings/billing`
|
||||
: "https://formbricks.com/docs/self-hosting/license#30-day-trial-license-request",
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
"use client";
|
||||
|
||||
import { ProjectConfigNavigation } from "@/modules/projects/settings/components/project-config-navigation";
|
||||
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
|
||||
import { PageHeader } from "@/modules/ui/components/page-header";
|
||||
import { useTranslate } from "@tolgee/react";
|
||||
|
||||
export const TeamsLoading = () => {
|
||||
const { t } = useTranslate();
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation activeId="teams" loading />
|
||||
</PageHeader>
|
||||
<div className="p-4">
|
||||
<div className="mb-4">
|
||||
<div className="h-6 w-1/3 animate-pulse rounded bg-slate-200" />
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
{[...Array(3)].map((_, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className="flex animate-pulse items-center space-x-4 rounded border border-slate-200 p-4">
|
||||
<div className="h-10 w-10 rounded-full bg-slate-300" />
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="h-4 w-3/4 rounded bg-slate-200" />
|
||||
<div className="h-4 w-1/2 rounded bg-slate-200" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</PageContentWrapper>
|
||||
);
|
||||
};
|
||||
@@ -1,8 +1,4 @@
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import {
|
||||
getMultiLanguagePermission,
|
||||
getRoleManagementPermission,
|
||||
} from "@/modules/ee/license-check/lib/utils";
|
||||
import { AccessView } from "@/modules/ee/teams/project-teams/components/access-view";
|
||||
import { ProjectConfigNavigation } from "@/modules/projects/settings/components/project-config-navigation";
|
||||
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
|
||||
@@ -37,9 +33,6 @@ export const ProjectTeams = async (props: { params: Promise<{ environmentId: str
|
||||
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
|
||||
const { isOwner, isManager } = getAccessFlags(currentUserMembership?.role);
|
||||
|
||||
const isMultiLanguageAllowed = await getMultiLanguagePermission(organization.billing.plan);
|
||||
const canDoRoleManagement = await getRoleManagementPermission(organization.billing.plan);
|
||||
|
||||
const teams = await getTeamsByProjectId(project.id);
|
||||
|
||||
if (!teams) {
|
||||
@@ -50,13 +43,8 @@ export const ProjectTeams = async (props: { params: Promise<{ environmentId: str
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<ProjectConfigNavigation
|
||||
environmentId={params.environmentId}
|
||||
activeId="teams"
|
||||
isMultiLanguageAllowed={isMultiLanguageAllowed}
|
||||
canDoRoleManagement={canDoRoleManagement}
|
||||
/>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation environmentId={params.environmentId} activeId="teams" />
|
||||
</PageHeader>
|
||||
<AccessView environmentId={params.environmentId} teams={teams} isOwnerOrManager={isOwnerOrManager} />
|
||||
</PageContentWrapper>
|
||||
|
||||
@@ -37,7 +37,7 @@ export const TeamsView = async ({
|
||||
|
||||
const buttons: [ModalButton, ModalButton] = [
|
||||
{
|
||||
text: t("common.start_free_trial"),
|
||||
text: IS_FORMBRICKS_CLOUD ? t("common.start_free_trial") : t("common.request_trial_license"),
|
||||
href: IS_FORMBRICKS_CLOUD
|
||||
? `/environments/${environmentId}/settings/billing`
|
||||
: "https://formbricks.com/docs/self-hosting/license#30-day-trial-license-request",
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ export const EmailCustomizationSettings = ({
|
||||
|
||||
const buttons: [ModalButton, ModalButton] = [
|
||||
{
|
||||
text: t("common.start_free_trial"),
|
||||
text: isFormbricksCloud ? t("common.start_free_trial") : t("common.request_trial_license"),
|
||||
href: isFormbricksCloud
|
||||
? `/environments/${environmentId}/settings/billing`
|
||||
: "https://formbricks.com/upgrade-self-hosting-license",
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ export const BrandingSettingsCard = async ({
|
||||
|
||||
const buttons: [ModalButton, ModalButton] = [
|
||||
{
|
||||
text: t("common.start_free_trial"),
|
||||
text: IS_FORMBRICKS_CLOUD ? t("common.start_free_trial") : t("common.request_trial_license"),
|
||||
href: IS_FORMBRICKS_CLOUD
|
||||
? `/environments/${environmentId}/settings/billing`
|
||||
: "https://formbricks.com/upgrade-self-hosting-license",
|
||||
|
||||
@@ -35,7 +35,7 @@ export const AppConnectionLoading = () => {
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation activeId="app-connection" loading />
|
||||
</PageHeader>
|
||||
<div className="mt-4 flex max-w-4xl animate-pulse items-center space-y-4 rounded-lg border bg-blue-50 p-6 text-sm text-blue-900 shadow-sm md:space-y-0 md:text-base"></div>
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { WidgetStatusIndicator } from "@/app/(app)/environments/[environmentId]/components/WidgetStatusIndicator";
|
||||
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
|
||||
import {
|
||||
getMultiLanguagePermission,
|
||||
getRoleManagementPermission,
|
||||
} from "@/modules/ee/license-check/lib/utils";
|
||||
import { EnvironmentIdField } from "@/modules/projects/settings/(setup)/components/environment-id-field";
|
||||
import { SetupInstructions } from "@/modules/projects/settings/(setup)/components/setup-instructions";
|
||||
import { ProjectConfigNavigation } from "@/modules/projects/settings/components/project-config-navigation";
|
||||
@@ -31,18 +27,10 @@ export const AppConnectionPage = async (props) => {
|
||||
throw new Error(t("common.organization_not_found"));
|
||||
}
|
||||
|
||||
const isMultiLanguageAllowed = await getMultiLanguagePermission(organization.billing.plan);
|
||||
const canDoRoleManagement = await getRoleManagementPermission(organization.billing.plan);
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<ProjectConfigNavigation
|
||||
environmentId={params.environmentId}
|
||||
activeId="app-connection"
|
||||
isMultiLanguageAllowed={isMultiLanguageAllowed}
|
||||
canDoRoleManagement={canDoRoleManagement}
|
||||
/>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation environmentId={params.environmentId} activeId="app-connection" />
|
||||
</PageHeader>
|
||||
<div className="space-y-4">
|
||||
<EnvironmentNotice environmentId={params.environmentId} subPageUrl="/project/app-connection" />
|
||||
|
||||
@@ -42,7 +42,7 @@ export const APIKeysLoading = () => {
|
||||
const { t } = useTranslate();
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation activeId="api-keys" loading />
|
||||
</PageHeader>
|
||||
<div className="mt-4 flex max-w-4xl animate-pulse items-center space-y-4 rounded-lg border bg-blue-50 p-6 text-sm text-blue-900 shadow-sm md:space-y-0 md:text-base"></div>
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import {
|
||||
getMultiLanguagePermission,
|
||||
getRoleManagementPermission,
|
||||
} from "@/modules/ee/license-check/lib/utils";
|
||||
import { getProjectPermissionByUserId } from "@/modules/ee/teams/lib/roles";
|
||||
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
|
||||
import { ProjectConfigNavigation } from "@/modules/projects/settings/components/project-config-navigation";
|
||||
@@ -53,18 +49,10 @@ export const APIKeysPage = async (props) => {
|
||||
|
||||
const isReadOnly = isMember && !hasManageAccess;
|
||||
|
||||
const isMultiLanguageAllowed = await getMultiLanguagePermission(organization.billing.plan);
|
||||
const canDoRoleManagement = await getRoleManagementPermission(organization.billing.plan);
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<ProjectConfigNavigation
|
||||
environmentId={params.environmentId}
|
||||
activeId="api-keys"
|
||||
isMultiLanguageAllowed={isMultiLanguageAllowed}
|
||||
canDoRoleManagement={canDoRoleManagement}
|
||||
/>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation environmentId={params.environmentId} activeId="api-keys" />
|
||||
</PageHeader>
|
||||
<EnvironmentNotice environmentId={environment.id} subPageUrl="/project/api-keys" />
|
||||
{environment.type === "development" ? (
|
||||
|
||||
@@ -8,17 +8,13 @@ import { usePathname } from "next/navigation";
|
||||
interface ProjectConfigNavigationProps {
|
||||
activeId: string;
|
||||
environmentId?: string;
|
||||
isMultiLanguageAllowed?: boolean;
|
||||
loading?: boolean;
|
||||
canDoRoleManagement?: boolean;
|
||||
}
|
||||
|
||||
export const ProjectConfigNavigation = ({
|
||||
activeId,
|
||||
environmentId,
|
||||
isMultiLanguageAllowed,
|
||||
loading,
|
||||
canDoRoleManagement,
|
||||
}: ProjectConfigNavigationProps) => {
|
||||
const { t } = useTranslate();
|
||||
const pathname = usePathname();
|
||||
@@ -43,7 +39,6 @@ export const ProjectConfigNavigation = ({
|
||||
label: t("common.survey_languages"),
|
||||
icon: <LanguagesIcon className="h-5 w-5" />,
|
||||
href: `/environments/${environmentId}/project/languages`,
|
||||
hidden: !isMultiLanguageAllowed,
|
||||
current: pathname?.includes("/languages"),
|
||||
},
|
||||
{
|
||||
@@ -70,8 +65,8 @@ export const ProjectConfigNavigation = ({
|
||||
{
|
||||
id: "teams",
|
||||
label: t("common.team_access"),
|
||||
icon: <UsersIcon className="h-5 w-5" />,
|
||||
href: `/environments/${environmentId}/project/teams`,
|
||||
hidden: !canDoRoleManagement,
|
||||
current: pathname?.includes("/teams"),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -28,7 +28,7 @@ export const GeneralSettingsLoading = () => {
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation activeId="general" loading />
|
||||
</PageHeader>
|
||||
{cards.map((card, index) => (
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import {
|
||||
getMultiLanguagePermission,
|
||||
getRoleManagementPermission,
|
||||
} from "@/modules/ee/license-check/lib/utils";
|
||||
import { getProjectPermissionByUserId } from "@/modules/ee/teams/lib/roles";
|
||||
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
|
||||
import { ProjectConfigNavigation } from "@/modules/projects/settings/components/project-config-navigation";
|
||||
@@ -51,21 +47,12 @@ export const GeneralSettingsPage = async (props: { params: Promise<{ environment
|
||||
|
||||
const isReadOnly = isMember && !hasManageAccess;
|
||||
|
||||
const isMultiLanguageAllowed = await getMultiLanguagePermission(organization.billing.plan);
|
||||
const canDoRoleManagement = await getRoleManagementPermission(organization.billing.plan);
|
||||
|
||||
const isOwnerOrManager = isOwner || isManager;
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
{/* </PageHeader><PageHeader pageTitle={t("common.configuration")}> */}
|
||||
<ProjectConfigNavigation
|
||||
environmentId={params.environmentId}
|
||||
activeId="general"
|
||||
isMultiLanguageAllowed={isMultiLanguageAllowed}
|
||||
canDoRoleManagement={canDoRoleManagement}
|
||||
/>
|
||||
<ProjectConfigNavigation environmentId={params.environmentId} activeId="general" />
|
||||
</PageHeader>
|
||||
<SettingsCard
|
||||
title={t("common.project_name")}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/ser
|
||||
import { getProjectByEnvironmentId } from "@formbricks/lib/project/service";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Config",
|
||||
title: "Configuration",
|
||||
};
|
||||
|
||||
export const ProjectSettingsLayout = async (props) => {
|
||||
|
||||
@@ -24,7 +24,7 @@ export const ProjectLookSettingsLoading = () => {
|
||||
const { t } = useTranslate();
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation activeId="look" loading />
|
||||
</PageHeader>
|
||||
<SettingsCard
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import {
|
||||
getMultiLanguagePermission,
|
||||
getRoleManagementPermission,
|
||||
getWhiteLabelPermission,
|
||||
} from "@/modules/ee/license-check/lib/utils";
|
||||
import { getWhiteLabelPermission } from "@/modules/ee/license-check/lib/utils";
|
||||
import { getProjectPermissionByUserId } from "@/modules/ee/teams/lib/roles";
|
||||
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
|
||||
import { BrandingSettingsCard } from "@/modules/ee/whitelabel/remove-branding/components/branding-settings-card";
|
||||
@@ -51,18 +47,10 @@ export const ProjectLookSettingsPage = async (props: { params: Promise<{ environ
|
||||
|
||||
const isReadOnly = isMember && !hasManageAccess;
|
||||
|
||||
const isMultiLanguageAllowed = await getMultiLanguagePermission(organization.billing.plan);
|
||||
const canDoRoleManagement = await getRoleManagementPermission(organization.billing.plan);
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<ProjectConfigNavigation
|
||||
environmentId={params.environmentId}
|
||||
activeId="look"
|
||||
isMultiLanguageAllowed={isMultiLanguageAllowed}
|
||||
canDoRoleManagement={canDoRoleManagement}
|
||||
/>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation environmentId={params.environmentId} activeId="look" />
|
||||
</PageHeader>
|
||||
<SettingsCard
|
||||
title={t("environments.project.look.theme")}
|
||||
|
||||
@@ -10,7 +10,7 @@ export const TagsLoading = () => {
|
||||
const { t } = useTranslate();
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation activeId="tags" />
|
||||
</PageHeader>
|
||||
<SettingsCard
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import {
|
||||
getMultiLanguagePermission,
|
||||
getRoleManagementPermission,
|
||||
} from "@/modules/ee/license-check/lib/utils";
|
||||
import { getProjectPermissionByUserId } from "@/modules/ee/teams/lib/roles";
|
||||
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
|
||||
import { ProjectConfigNavigation } from "@/modules/projects/settings/components/project-config-navigation";
|
||||
@@ -59,18 +55,10 @@ export const TagsPage = async (props) => {
|
||||
|
||||
const isReadOnly = isMember && !hasManageAccess;
|
||||
|
||||
const isMultiLanguageAllowed = await getMultiLanguagePermission(organization.billing.plan);
|
||||
const canDoRoleManagement = await getRoleManagementPermission(organization.billing.plan);
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle={t("common.configuration")}>
|
||||
<ProjectConfigNavigation
|
||||
environmentId={params.environmentId}
|
||||
activeId="tags"
|
||||
isMultiLanguageAllowed={isMultiLanguageAllowed}
|
||||
canDoRoleManagement={canDoRoleManagement}
|
||||
/>
|
||||
<PageHeader pageTitle={t("common.project_configuration")}>
|
||||
<ProjectConfigNavigation environmentId={params.environmentId} activeId="tags" />
|
||||
</PageHeader>
|
||||
<SettingsCard
|
||||
title={t("environments.project.tags.manage_tags")}
|
||||
|
||||
@@ -43,7 +43,7 @@ export const TargetingLockedCard = ({ isFormbricksCloud, environmentId }: Target
|
||||
description={t("environments.surveys.edit.unlock_targeting_description")}
|
||||
buttons={[
|
||||
{
|
||||
text: t("common.start_free_trial"),
|
||||
text: isFormbricksCloud ? t("common.start_free_trial") : t("common.request_trial_license"),
|
||||
href: isFormbricksCloud
|
||||
? `/environments/${environmentId}/settings/billing`
|
||||
: "https://formbricks.com/upgrade-self-hosting-license",
|
||||
|
||||
@@ -8,8 +8,8 @@ export const SlackIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}>
|
||||
<rect width="3" height="8" x="13" y="2" rx="1.5" />
|
||||
<path d="M19 8.5V10h1.5A1.5 1.5 0 1 0 19 8.5" />
|
||||
|
||||
@@ -16,77 +16,72 @@ interface SecondaryNavbarProps {
|
||||
export const SecondaryNavigation = ({ navigation, activeId, loading, ...props }: SecondaryNavbarProps) => {
|
||||
return (
|
||||
<div {...props}>
|
||||
<div className="grid h-10 w-full grid-cols-[auto,1fr]">
|
||||
<nav className="flex h-full min-w-full items-center space-x-4" aria-label="Tabs">
|
||||
{loading
|
||||
? navigation.map((navElem) => (
|
||||
<div className="group flex h-full flex-col" key={navElem.id}>
|
||||
<div
|
||||
aria-disabled="true"
|
||||
className={cn(
|
||||
navElem.id === activeId ? "font-semibold text-slate-900" : "text-slate-500",
|
||||
"flex h-full items-center px-3 text-sm font-medium",
|
||||
navElem.hidden && "hidden"
|
||||
)}
|
||||
aria-current={navElem.id === activeId ? "page" : undefined}>
|
||||
{navElem.label}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"bottom-0 mt-auto h-[2px] w-full rounded-t-lg transition-all duration-150 ease-in-out",
|
||||
navElem.id === activeId ? "bg-slate-300" : "bg-transparent group-hover:bg-slate-300",
|
||||
navElem.hidden && "hidden"
|
||||
)}
|
||||
/>
|
||||
<nav className="flex h-10 w-full items-center space-x-4" aria-label="Tabs">
|
||||
{loading
|
||||
? navigation.map((navElem) => (
|
||||
<div className="group flex h-full flex-col truncate" key={navElem.id}>
|
||||
<div
|
||||
aria-disabled="true"
|
||||
className={cn(
|
||||
navElem.id === activeId ? "font-semibold text-slate-900" : "text-slate-500",
|
||||
"flex h-full items-center truncate px-3 text-sm font-medium",
|
||||
navElem.hidden && "hidden"
|
||||
)}
|
||||
aria-current={navElem.id === activeId ? "page" : undefined}>
|
||||
{navElem.label}
|
||||
</div>
|
||||
))
|
||||
: navigation.map(
|
||||
(navElem) =>
|
||||
!navElem.hidden && (
|
||||
<div className="group flex h-full flex-col" key={navElem.id}>
|
||||
{navElem.href ? (
|
||||
<Link
|
||||
href={navElem.href}
|
||||
{...(navElem.onClick ? { onClick: navElem.onClick } : {})}
|
||||
className={cn(
|
||||
navElem.id === activeId
|
||||
? "font-semibold text-slate-900"
|
||||
: "text-slate-500 hover:text-slate-700",
|
||||
"flex h-full items-center px-3 text-sm font-medium",
|
||||
navElem.hidden && "hidden"
|
||||
)}
|
||||
aria-current={navElem.id === activeId ? "page" : undefined}>
|
||||
{navElem.label}
|
||||
</Link>
|
||||
) : (
|
||||
<button
|
||||
{...(navElem.onClick ? { onClick: navElem.onClick } : {})}
|
||||
className={cn(
|
||||
navElem.id === activeId
|
||||
? "font-semibold text-slate-900"
|
||||
: "text-slate-500 hover:text-slate-700",
|
||||
"grow items-center px-3 text-sm font-medium transition-all duration-150 ease-in-out",
|
||||
navElem.hidden && "hidden"
|
||||
)}
|
||||
aria-current={navElem.id === activeId ? "page" : undefined}>
|
||||
{navElem.label}
|
||||
</button>
|
||||
)}
|
||||
<div
|
||||
<div
|
||||
className={cn(
|
||||
"bottom-0 mt-auto h-[2px] w-full rounded-t-lg transition-all duration-150 ease-in-out",
|
||||
navElem.id === activeId ? "bg-slate-300" : "bg-transparent group-hover:bg-slate-300",
|
||||
navElem.hidden && "hidden"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
: navigation.map(
|
||||
(navElem) =>
|
||||
!navElem.hidden && (
|
||||
<div className="group flex h-full flex-col truncate" key={navElem.id}>
|
||||
{navElem.href ? (
|
||||
<Link
|
||||
href={navElem.href}
|
||||
{...(navElem.onClick ? { onClick: navElem.onClick } : {})}
|
||||
className={cn(
|
||||
"bottom-0 mt-auto h-[2px] w-full rounded-t-lg transition-all duration-150 ease-in-out",
|
||||
navElem.id === activeId
|
||||
? "bg-brand-dark"
|
||||
: "bg-transparent group-hover:bg-slate-300",
|
||||
? "font-semibold text-slate-900"
|
||||
: "text-slate-500 hover:text-slate-700",
|
||||
"flex h-full items-center px-3 text-sm font-medium",
|
||||
navElem.hidden && "hidden"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</nav>
|
||||
<div className="justify-self-end"></div>
|
||||
</div>
|
||||
aria-current={navElem.id === activeId ? "page" : undefined}>
|
||||
{navElem.label}
|
||||
</Link>
|
||||
) : (
|
||||
<button
|
||||
{...(navElem.onClick ? { onClick: navElem.onClick } : {})}
|
||||
className={cn(
|
||||
navElem.id === activeId
|
||||
? "font-semibold text-slate-900"
|
||||
: "text-slate-500 hover:text-slate-700",
|
||||
"grow items-center px-3 text-sm font-medium transition-all duration-150 ease-in-out",
|
||||
navElem.hidden && "hidden"
|
||||
)}
|
||||
aria-current={navElem.id === activeId ? "page" : undefined}>
|
||||
{navElem.label}
|
||||
</button>
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
"bottom-0 mt-auto h-[2px] w-full rounded-t-lg transition-all duration-150 ease-in-out",
|
||||
navElem.id === activeId ? "bg-brand-dark" : "bg-transparent group-hover:bg-slate-300",
|
||||
navElem.hidden && "hidden"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -310,6 +310,7 @@
|
||||
"remove": "Entfernen",
|
||||
"reorder_and_hide_columns": "Spalten neu anordnen und ausblenden",
|
||||
"report_survey": "Umfrage melden",
|
||||
"request_trial_license": "Test-Lizenz anfordern",
|
||||
"reset_to_default": "Auf Standard zurücksetzen",
|
||||
"response": "Antwort",
|
||||
"responses": "Antworten",
|
||||
@@ -1133,7 +1134,9 @@
|
||||
"resend_invitation_email": "Einladungsemail erneut senden",
|
||||
"share_invite_link": "Einladungslink teilen",
|
||||
"share_this_link_to_let_your_organization_member_join_your_organization": "Teile diesen Link, damit dein Organisationsmitglied deiner Organisation beitreten kann:",
|
||||
"test_email_sent_successfully": "Test-E-Mail erfolgreich gesendet"
|
||||
"test_email_sent_successfully": "Test-E-Mail erfolgreich gesendet",
|
||||
"use_multi_language_surveys_with_a_higher_plan": "Nutze mehrsprachige Umfragen mit einem höheren Plan",
|
||||
"use_multi_language_surveys_with_a_higher_plan_description": "Befrage deine Nutzer in verschiedenen Sprachen."
|
||||
},
|
||||
"notifications": {
|
||||
"auto_subscribe_to_new_surveys": "Neue Umfragenbenachrichtigungen abonnieren",
|
||||
@@ -1177,7 +1180,7 @@
|
||||
"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.",
|
||||
"security_description": "Verwalte dein Passwort und andere Sicherheitseinstellungen wie Zwei-Faktor-Authentifizierung (2FA).",
|
||||
"two_factor_authentication": "Zwei-Faktor-Authentifizierung",
|
||||
"two_factor_authentication_description": "Füge eine zusätzliche Sicherheitsebene zu deinem Konto hinzu, falls dein Passwort gestohlen wird.",
|
||||
"two_factor_authentication_enabled_please_enter_the_six_digit_code_from_your_authenticator_app": "Zwei-Faktor-Authentifizierung aktiviert. Bitte gib den sechsstelligen Code aus deiner Authentifizierungs-App ein.",
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
"product_not_found": "Product not found",
|
||||
"profile": "Profile",
|
||||
"project": "Project",
|
||||
"project_configuration": "Project's Configuration",
|
||||
"project_configuration": "Project Configuration",
|
||||
"project_id": "Project ID",
|
||||
"project_name": "Project Name",
|
||||
"project_not_found": "Project not found",
|
||||
@@ -310,6 +310,7 @@
|
||||
"remove": "Remove",
|
||||
"reorder_and_hide_columns": "Reorder and hide columns",
|
||||
"report_survey": "Report Survey",
|
||||
"request_trial_license": "Request trial license",
|
||||
"reset_to_default": "Reset to default",
|
||||
"response": "Response",
|
||||
"responses": "Responses",
|
||||
@@ -346,7 +347,7 @@
|
||||
"some_files_failed_to_upload": "Some files failed to upload",
|
||||
"something_went_wrong_please_try_again": "Something went wrong. Please try again.",
|
||||
"sort_by": "Sort by",
|
||||
"start_free_trial": "Start Free Trial",
|
||||
"start_free_trial": "Start free trial",
|
||||
"status": "Status",
|
||||
"step_by_step_manual": "Step by step manual",
|
||||
"styling": "Styling",
|
||||
@@ -1133,7 +1134,9 @@
|
||||
"resend_invitation_email": "Resend Invitation Email",
|
||||
"share_invite_link": "Share Invite Link",
|
||||
"share_this_link_to_let_your_organization_member_join_your_organization": "Share this link to let your organization member join your organization:",
|
||||
"test_email_sent_successfully": "Test email sent successfully"
|
||||
"test_email_sent_successfully": "Test email sent successfully",
|
||||
"use_multi_language_surveys_with_a_higher_plan": "Use multi-language surveys with a higher plan",
|
||||
"use_multi_language_surveys_with_a_higher_plan_description": "Survey your users in different languages."
|
||||
},
|
||||
"notifications": {
|
||||
"auto_subscribe_to_new_surveys": "Auto-subscribe to new surveys",
|
||||
@@ -1177,7 +1180,7 @@
|
||||
"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.",
|
||||
"security_description": "Manage your password and other security settings like two-factor authentication (2FA).",
|
||||
"two_factor_authentication": "Two factor authentication",
|
||||
"two_factor_authentication_description": "Add an extra layer of security to your account in case your password is stolen.",
|
||||
"two_factor_authentication_enabled_please_enter_the_six_digit_code_from_your_authenticator_app": "Two-factor authentication enabled. Please enter the six-digit code from your authenticator app.",
|
||||
|
||||
@@ -310,6 +310,7 @@
|
||||
"remove": "Retirer",
|
||||
"reorder_and_hide_columns": "Réorganiser et masquer des colonnes",
|
||||
"report_survey": "Rapport d'enquête",
|
||||
"request_trial_license": "Demander licence d'essai",
|
||||
"reset_to_default": "Réinitialiser par défaut",
|
||||
"response": "Réponse",
|
||||
"responses": "Réponses",
|
||||
@@ -1133,7 +1134,9 @@
|
||||
"resend_invitation_email": "Renvoyer l'e-mail d'invitation",
|
||||
"share_invite_link": "Partager le lien d'invitation",
|
||||
"share_this_link_to_let_your_organization_member_join_your_organization": "Partagez ce lien pour permettre à un membre de votre organisation de rejoindre votre organisation :",
|
||||
"test_email_sent_successfully": "E-mail de test envoyé avec succès"
|
||||
"test_email_sent_successfully": "E-mail de test envoyé avec succès",
|
||||
"use_multi_language_surveys_with_a_higher_plan": "Utiliser des sondages multilingues avec un plan supérieur",
|
||||
"use_multi_language_surveys_with_a_higher_plan_description": "Sondage vos utilisateurs dans différentes langues."
|
||||
},
|
||||
"notifications": {
|
||||
"auto_subscribe_to_new_surveys": "S'abonner automatiquement aux nouveaux sondages",
|
||||
@@ -1177,7 +1180,7 @@
|
||||
"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é.",
|
||||
"security_description": "Gérez votre mot de passe et d'autres paramètres de sécurité comme l'authentification à deux facteurs (2FA).",
|
||||
"two_factor_authentication": "Authentification à deux facteurs",
|
||||
"two_factor_authentication_description": "Ajoutez une couche de sécurité supplémentaire à votre compte au cas où votre mot de passe serait volé.",
|
||||
"two_factor_authentication_enabled_please_enter_the_six_digit_code_from_your_authenticator_app": "Authentification à deux facteurs activée. Veuillez entrer le code à six chiffres de votre application d'authentification.",
|
||||
|
||||
@@ -310,6 +310,7 @@
|
||||
"remove": "remover",
|
||||
"reorder_and_hide_columns": "Reordenar e ocultar colunas",
|
||||
"report_survey": "Relatório de Pesquisa",
|
||||
"request_trial_license": "Solicitar licença de teste",
|
||||
"reset_to_default": "Restaurar para o padrão",
|
||||
"response": "Resposta",
|
||||
"responses": "Respostas",
|
||||
@@ -346,7 +347,7 @@
|
||||
"some_files_failed_to_upload": "Alguns arquivos falharam ao enviar",
|
||||
"something_went_wrong_please_try_again": "Algo deu errado. Tente novamente.",
|
||||
"sort_by": "Ordenar por",
|
||||
"start_free_trial": "Iniciar Teste Grátis",
|
||||
"start_free_trial": "Iniciar teste grátis",
|
||||
"status": "status",
|
||||
"step_by_step_manual": "Manual passo a passo",
|
||||
"styling": "estilização",
|
||||
@@ -1133,7 +1134,9 @@
|
||||
"resend_invitation_email": "Reenviar E-mail de Convite",
|
||||
"share_invite_link": "Compartilhar Link de Convite",
|
||||
"share_this_link_to_let_your_organization_member_join_your_organization": "Compartilhe esse link para que o membro da sua organização possa entrar na sua organização:",
|
||||
"test_email_sent_successfully": "E-mail de teste enviado com sucesso"
|
||||
"test_email_sent_successfully": "E-mail de teste enviado com sucesso",
|
||||
"use_multi_language_surveys_with_a_higher_plan": "Use pesquisas multilingues com um plano superior",
|
||||
"use_multi_language_surveys_with_a_higher_plan_description": "Pesquise seus usuários em diferentes idiomas."
|
||||
},
|
||||
"notifications": {
|
||||
"auto_subscribe_to_new_surveys": "Inscrever-se automaticamente em novas pesquisas",
|
||||
@@ -1177,7 +1180,7 @@
|
||||
"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.",
|
||||
"security_description": "Gerencie sua senha e outras configurações de segurança como a autenticação de dois fatores (2FA).",
|
||||
"two_factor_authentication": "Autenticação de dois fatores",
|
||||
"two_factor_authentication_description": "Adicione uma camada extra de segurança à sua conta caso sua senha seja roubada.",
|
||||
"two_factor_authentication_enabled_please_enter_the_six_digit_code_from_your_authenticator_app": "Autenticação de dois fatores ativada. Por favor, insira o código de seis dígitos do seu app autenticador.",
|
||||
|
||||
@@ -310,6 +310,7 @@
|
||||
"remove": "Remover",
|
||||
"reorder_and_hide_columns": "Reordenar e ocultar colunas",
|
||||
"report_survey": "Relatório de Inquérito",
|
||||
"request_trial_license": "Solicitar licença de teste",
|
||||
"reset_to_default": "Repor para o padrão",
|
||||
"response": "Resposta",
|
||||
"responses": "Respostas",
|
||||
@@ -346,7 +347,7 @@
|
||||
"some_files_failed_to_upload": "Alguns ficheiros falharam ao carregar",
|
||||
"something_went_wrong_please_try_again": "Algo correu mal. Por favor, tente novamente.",
|
||||
"sort_by": "Ordenar por",
|
||||
"start_free_trial": "Iniciar Teste Grátis",
|
||||
"start_free_trial": "Iniciar teste grátis",
|
||||
"status": "Estado",
|
||||
"step_by_step_manual": "Manual passo a passo",
|
||||
"styling": "Estilo",
|
||||
@@ -1133,7 +1134,9 @@
|
||||
"resend_invitation_email": "Reenviar Email de Convite",
|
||||
"share_invite_link": "Partilhar Link de Convite",
|
||||
"share_this_link_to_let_your_organization_member_join_your_organization": "Partilhe este link para permitir que o membro da sua organização se junte à sua organização:",
|
||||
"test_email_sent_successfully": "Email de teste enviado com sucesso"
|
||||
"test_email_sent_successfully": "Email de teste enviado com sucesso",
|
||||
"use_multi_language_surveys_with_a_higher_plan": "Use inquéritos multilingues com um plano superior",
|
||||
"use_multi_language_surveys_with_a_higher_plan_description": "Inquira os seus utilizadores em diferentes idiomas."
|
||||
},
|
||||
"notifications": {
|
||||
"auto_subscribe_to_new_surveys": "Subscrever automaticamente a novos inquéritos",
|
||||
@@ -1177,7 +1180,7 @@
|
||||
"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.",
|
||||
"security_description": "Gerir a sua palavra-passe e outras definições de segurança como a autenticação de dois fatores (2FA).",
|
||||
"two_factor_authentication": "Autenticação de dois fatores",
|
||||
"two_factor_authentication_description": "Adicione uma camada extra de segurança à sua conta caso a sua palavra-passe seja roubada.",
|
||||
"two_factor_authentication_enabled_please_enter_the_six_digit_code_from_your_authenticator_app": "Autenticação de dois fatores ativada. Introduza o código de seis dígitos da sua aplicação de autenticação.",
|
||||
|
||||
@@ -310,6 +310,7 @@
|
||||
"remove": "移除",
|
||||
"reorder_and_hide_columns": "重新排序和隱藏欄位",
|
||||
"report_survey": "報告問卷",
|
||||
"request_trial_license": "申請試用授權",
|
||||
"reset_to_default": "重設為預設值",
|
||||
"response": "回應",
|
||||
"responses": "回應",
|
||||
@@ -1133,7 +1134,9 @@
|
||||
"resend_invitation_email": "重新發送邀請電子郵件",
|
||||
"share_invite_link": "分享邀請連結",
|
||||
"share_this_link_to_let_your_organization_member_join_your_organization": "分享此連結以讓您的組織成員加入您的組織:",
|
||||
"test_email_sent_successfully": "測試電子郵件已成功發送"
|
||||
"test_email_sent_successfully": "測試電子郵件已成功發送",
|
||||
"use_multi_language_surveys_with_a_higher_plan": "使用多語言問卷與更高方案",
|
||||
"use_multi_language_surveys_with_a_higher_plan_description": "用不同語言調查您的用戶。"
|
||||
},
|
||||
"notifications": {
|
||||
"auto_subscribe_to_new_surveys": "自動訂閱新問卷",
|
||||
@@ -1177,7 +1180,7 @@
|
||||
"remove_image": "移除圖片",
|
||||
"save_the_following_backup_codes_in_a_safe_place": "將下列備份碼儲存在安全的地方。",
|
||||
"scan_the_qr_code_below_with_your_authenticator_app": "使用您的驗證器應用程式掃描下方的 QR 碼。",
|
||||
"security_description": "管理您的密碼和其他安全性設定。",
|
||||
"security_description": "管理您的密碼和其他安全性設定,例如雙重驗證 (2FA)。",
|
||||
"two_factor_authentication": "雙重驗證",
|
||||
"two_factor_authentication_description": "在您的密碼被盜時,為您的帳戶新增額外的安全層。",
|
||||
"two_factor_authentication_enabled_please_enter_the_six_digit_code_from_your_authenticator_app": "已啟用雙重驗證。請輸入您驗證器應用程式中的六位數程式碼。",
|
||||
|
||||
Reference in New Issue
Block a user