mirror of
https://github.com/logto-io/logto.git
synced 2025-03-10 22:22:45 -05:00
refactor(console): update featured plan content in tenant creation modal (#5418)
This commit is contained in:
parent
168ddc5927
commit
3df1994bb5
38 changed files with 480 additions and 130 deletions
|
@ -0,0 +1,33 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.list {
|
||||
flex: 1;
|
||||
margin-block: 0;
|
||||
padding-inline: 0;
|
||||
padding-bottom: _.unit(8);
|
||||
list-style: none;
|
||||
|
||||
> li {
|
||||
display: flex;
|
||||
font: var(--font-body-2);
|
||||
align-items: center;
|
||||
gap: _.unit(2);
|
||||
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
&.failed {
|
||||
color: var(--color-on-error-container);
|
||||
}
|
||||
|
||||
&.success {
|
||||
color: var(--color-on-success-container);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: _.unit(3);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import classNames from 'classnames';
|
||||
|
||||
import Failed from '@/assets/icons/failed.svg';
|
||||
import Success from '@/assets/icons/success.svg';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
import useFeaturedPlanContent from './use-featured-plan-content';
|
||||
|
||||
type Props = {
|
||||
planId: string;
|
||||
};
|
||||
|
||||
function FeaturedPlanContent({ planId }: Props) {
|
||||
const contentData = useFeaturedPlanContent(planId);
|
||||
|
||||
return (
|
||||
<ul className={styles.list}>
|
||||
{contentData.map(({ title, isAvailable }) => {
|
||||
return (
|
||||
<li key={title}>
|
||||
{isAvailable ? (
|
||||
<Success className={classNames(styles.icon, styles.success)} />
|
||||
) : (
|
||||
<Failed className={classNames(styles.icon, styles.failed)} />
|
||||
)}
|
||||
{title}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export default FeaturedPlanContent;
|
|
@ -0,0 +1,66 @@
|
|||
import { ReservedPlanId } from '@logto/schemas';
|
||||
import { cond } from '@silverhand/essentials';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type ContentData = {
|
||||
title: string;
|
||||
isAvailable: boolean;
|
||||
};
|
||||
|
||||
const useFeaturedPlanContent = (planId: string) => {
|
||||
const { t } = useTranslation(undefined, {
|
||||
keyPrefix: 'admin_console.upsell.featured_plan_content',
|
||||
});
|
||||
|
||||
const contentData: ContentData[] = useMemo(() => {
|
||||
const isFreePlan = planId === ReservedPlanId.Free;
|
||||
const planPhraseKey = isFreePlan ? 'free_plan' : 'pro_plan';
|
||||
|
||||
return [
|
||||
{
|
||||
title: t(`mau.${planPhraseKey}`, { ...cond(isFreePlan && { count: 50_000 }) }),
|
||||
isAvailable: true,
|
||||
},
|
||||
{
|
||||
title: t(`m2m.${planPhraseKey}`, { ...cond(isFreePlan && { count: 1 }) }),
|
||||
isAvailable: true,
|
||||
},
|
||||
{
|
||||
title: t('third_party_apps'),
|
||||
isAvailable: !isFreePlan,
|
||||
},
|
||||
{
|
||||
title: t('mfa'),
|
||||
isAvailable: !isFreePlan,
|
||||
},
|
||||
{
|
||||
title: t('sso'),
|
||||
isAvailable: !isFreePlan,
|
||||
},
|
||||
{
|
||||
title: t(`role_and_permissions.${planPhraseKey}`, {
|
||||
...cond(
|
||||
isFreePlan && {
|
||||
roleCount: 1,
|
||||
permissionCount: 1,
|
||||
}
|
||||
),
|
||||
}),
|
||||
isAvailable: true,
|
||||
},
|
||||
{
|
||||
title: t('organizations'),
|
||||
isAvailable: !isFreePlan,
|
||||
},
|
||||
{
|
||||
title: t('audit_logs', { count: isFreePlan ? 3 : 14 }),
|
||||
isAvailable: true,
|
||||
},
|
||||
];
|
||||
}, [t, planId]);
|
||||
|
||||
return contentData;
|
||||
};
|
||||
|
||||
export default useFeaturedPlanContent;
|
|
@ -1,14 +0,0 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
&.notCapable {
|
||||
color: var(--color-error);
|
||||
}
|
||||
|
||||
&.capable {
|
||||
color: var(--color-on-success-container);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
import { cond } from '@silverhand/essentials';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import Failed from '@/assets/icons/failed.svg';
|
||||
import Success from '@/assets/icons/success.svg';
|
||||
import QuotaListItem from '@/components/PlanQuotaList/QuotaListItem';
|
||||
import DynamicT from '@/ds-components/DynamicT';
|
||||
import Tag from '@/ds-components/Tag';
|
||||
import { type SubscriptionPlanQuota } from '@/types/subscriptions';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
type Props = {
|
||||
quotaKey: keyof SubscriptionPlanQuota;
|
||||
quotaValue: SubscriptionPlanQuota[keyof SubscriptionPlanQuota];
|
||||
isAddOnQuota: boolean;
|
||||
isComingSoonTagVisible: boolean;
|
||||
};
|
||||
|
||||
function FeaturedQuotaItem({ quotaKey, quotaValue, isAddOnQuota, isComingSoonTagVisible }: Props) {
|
||||
const isNotCapable = quotaValue === 0 || quotaValue === false;
|
||||
const Icon = isNotCapable ? Failed : Success;
|
||||
|
||||
return (
|
||||
<QuotaListItem
|
||||
quotaKey={quotaKey}
|
||||
quotaValue={quotaValue}
|
||||
isAddOn={isAddOnQuota}
|
||||
icon={
|
||||
<Icon
|
||||
className={classNames(styles.icon, isNotCapable ? styles.notCapable : styles.capable)}
|
||||
/>
|
||||
}
|
||||
suffix={cond(
|
||||
isComingSoonTagVisible && (
|
||||
<Tag>
|
||||
<DynamicT forKey="general.coming_soon" />
|
||||
</Tag>
|
||||
)
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default FeaturedQuotaItem;
|
|
@ -1,6 +0,0 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.featuredQuotaList {
|
||||
flex: 1;
|
||||
padding-bottom: _.unit(8);
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
import { ReservedPlanId } from '@logto/schemas';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import PlanQuotaList from '@/components/PlanQuotaList';
|
||||
import { comingSoonQuotaKeys } from '@/consts/plan-quotas';
|
||||
import { quotaItemAddOnPhrasesMap } from '@/consts/quota-item-phrases';
|
||||
import {
|
||||
type SubscriptionPlanQuotaEntries,
|
||||
type SubscriptionPlan,
|
||||
type SubscriptionPlanQuota,
|
||||
} from '@/types/subscriptions';
|
||||
|
||||
import FeaturedQuotaItem from './FeaturedQuotaItem';
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
const featuredQuotaKeys = new Set<keyof SubscriptionPlanQuota>([
|
||||
'mauLimit',
|
||||
'machineToMachineLimit',
|
||||
'thirdPartyApplicationsLimit',
|
||||
'rolesLimit',
|
||||
'scopesPerRoleLimit',
|
||||
'mfaEnabled',
|
||||
'ssoEnabled',
|
||||
'organizationsEnabled',
|
||||
'auditLogsRetentionDays',
|
||||
]);
|
||||
|
||||
type Props = {
|
||||
plan: SubscriptionPlan;
|
||||
};
|
||||
|
||||
function FeaturedPlanQuotaList({ plan }: Props) {
|
||||
const { id: planId, quota } = plan;
|
||||
|
||||
const featuredEntries = useMemo(
|
||||
() =>
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
(Object.entries(quota) as SubscriptionPlanQuotaEntries).filter(([key]) =>
|
||||
featuredQuotaKeys.has(key)
|
||||
),
|
||||
[quota]
|
||||
);
|
||||
|
||||
return (
|
||||
<PlanQuotaList
|
||||
className={styles.featuredQuotaList}
|
||||
entries={featuredEntries}
|
||||
itemRenderer={(quotaKey, quotaValue) => (
|
||||
<FeaturedQuotaItem
|
||||
key={quotaKey}
|
||||
quotaKey={quotaKey}
|
||||
quotaValue={quotaValue}
|
||||
isAddOnQuota={
|
||||
planId !== ReservedPlanId.Free && Boolean(quotaItemAddOnPhrasesMap[quotaKey])
|
||||
}
|
||||
isComingSoonTagVisible={comingSoonQuotaKeys.includes(quotaKey)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default FeaturedPlanQuotaList;
|
|
@ -14,7 +14,7 @@ import DynamicT from '@/ds-components/DynamicT';
|
|||
import TextLink from '@/ds-components/TextLink';
|
||||
import { type SubscriptionPlan } from '@/types/subscriptions';
|
||||
|
||||
import FeaturedPlanQuotaList from './FeaturedPlanQuotaList';
|
||||
import FeaturedPlanContent from './FeaturedPlanContent';
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
type Props = {
|
||||
|
@ -59,7 +59,7 @@ function PlanCardItem({ plan, onSelect }: Props) {
|
|||
</div>
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
<FeaturedPlanQuotaList plan={plan} />
|
||||
<FeaturedPlanContent planId={planId} />
|
||||
{isFreePlan && isFreeTenantExceeded && (
|
||||
<div className={classNames(styles.tip, styles.exceedFreeTenantsTip)}>
|
||||
{t('free_tenants_limit', { count: maxFreeTenantLimit })}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: 'Bis zu {{count, number}} MAU',
|
||||
pro_plan: 'Unbegrenzte MAU',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} Maschine-zu-Maschine',
|
||||
pro_plan: 'Zusätzliche Maschine-zu-Maschine',
|
||||
},
|
||||
third_party_apps: 'IdP für Drittanbieteranwendungen',
|
||||
mfa: 'Multi-Faktor-Authentifizierung',
|
||||
sso: 'Unternehmens-SSO',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} Rolle und {{permissionCount, number}} Berechtigung pro Rolle',
|
||||
pro_plan: 'Unbegrenzte Rollen und Berechtigungen pro Rolle',
|
||||
},
|
||||
organizations: 'Organisationen',
|
||||
audit_logs: 'Audit-Logs Speicherung: {{count, number}} Tage',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'Sie haben Ihr {{item}}-Quotenlimit überschritten. Logto wird Gebühren für die Nutzung über Ihr Quotenlimit hinaus hinzufügen. Die Abrechnung beginnt am Tag der Veröffentlichung des neuen Add-On-Preisdesigns. <a>Mehr erfahren</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: 'Up to {{count, number}} MAU',
|
||||
pro_plan: 'Unlimited MAU',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} machine-to-machine',
|
||||
pro_plan: 'Additional machine-to-machine',
|
||||
},
|
||||
third_party_apps: 'IdP for third-party applications',
|
||||
mfa: 'Multi-factor authentication',
|
||||
sso: 'Enterprise SSO',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} role and {{permissionCount, number}} permission per role',
|
||||
pro_plan: 'Unlimited roles and permissions per role',
|
||||
},
|
||||
organizations: 'Organizations',
|
||||
audit_logs: 'Audit logs retention: {{count, number}} days',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'You have surpassed your {{item}} quota limit. Logto will add charges for the usage beyond your quota limit. Charging will commence on the day the new add-on pricing design is released. <a>Learn more</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: 'Hasta {{count, number}} MAU',
|
||||
pro_plan: 'MAU ilimitados',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} de máquina a máquina',
|
||||
pro_plan: 'Máquina a máquina adicional',
|
||||
},
|
||||
third_party_apps: 'IdP para aplicaciones de terceros',
|
||||
mfa: 'Autenticación multifactor',
|
||||
sso: 'SSO empresarial',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} rol y {{permissionCount, number}} permiso por rol',
|
||||
pro_plan: 'Roles y permisos ilimitados por rol',
|
||||
},
|
||||
organizations: 'Organizaciones',
|
||||
audit_logs: 'Retención de registros de auditoría: {{count, number}} días',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'Has superado tu límite de cuota de {{item}}. Logto agregará cargos por el uso más allá de tu límite de cuota. La facturación comenzará el día en que se lance el nuevo diseño de precios del complemento. <a>Más información</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: "Jusqu'à {{count, number}} MAU",
|
||||
pro_plan: 'MAU illimités',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} machine à machine',
|
||||
pro_plan: 'Machine à machine supplémentaire',
|
||||
},
|
||||
third_party_apps: 'IdP pour les applications tierces',
|
||||
mfa: 'Authentification multi-facteurs',
|
||||
sso: 'SSO Entreprise',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} rôle et {{permissionCount, number}} permission par rôle',
|
||||
pro_plan: 'Rôles et permissions illimités par rôle',
|
||||
},
|
||||
organizations: 'Organisations',
|
||||
audit_logs: "Conservation des journaux d'audit: {{count, number}} jours",
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
"Vous avez dépassé votre limite de quota {{item}}. Logto ajoutera des frais pour l'utilisation au-delà de votre limite de quota. La facturation commencera le jour de la publication du nouveau design tarifaire de l'extension. <a>En savoir plus</a>",
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: 'Fino a {{count, number}} MAU',
|
||||
pro_plan: 'MAU illimitati',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} da macchina a macchina',
|
||||
pro_plan: 'Macchina a macchina aggiuntiva',
|
||||
},
|
||||
third_party_apps: 'IdP per applicazioni di terze parti',
|
||||
mfa: 'Autenticazione a più fattori',
|
||||
sso: 'SSO aziendale',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} ruolo e {{permissionCount, number}} permesso per ruolo',
|
||||
pro_plan: 'Ruoli e permessi illimitati per ruolo',
|
||||
},
|
||||
organizations: 'Organizzazioni',
|
||||
audit_logs: 'Conservazione dei log degli audit: {{count, number}} giorni',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
"Hai superato il limite di quota {{item}}. Logto aggiungerà addebiti per l'uso oltre il limite di quota. La fatturazione inizierà il giorno in cui verrà rilasciato il nuovo design dei prezzi dell'addon. <a>Ulteriori informazioni</a>",
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: '{{count, number}} MAUまで',
|
||||
pro_plan: 'MAU無制限',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}}機器間',
|
||||
pro_plan: '追加の機器間',
|
||||
},
|
||||
third_party_apps: 'サードパーティアプリケーションのIdP',
|
||||
mfa: 'マルチファクタ認証',
|
||||
sso: '企業SSO',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}}ロールと{{permissionCount, number}}ロールごとの権限',
|
||||
pro_plan: 'ロールごとの無制限の役割と権限',
|
||||
},
|
||||
organizations: '組織',
|
||||
audit_logs: '監査ログ保持: {{count, number}} 日間',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'{{item}} のクォータ制限を超えています。Logto はクォータ制限を超える利用に対して料金を追加します。新しいアドオン価格設計がリリースされる日から請求が開始されます。 <a>詳細</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: '{{count, number}} MAU까지',
|
||||
pro_plan: '무제한 MAU',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} 기기 간 통신',
|
||||
pro_plan: '추가 기기 간 통신',
|
||||
},
|
||||
third_party_apps: '타사 응용 프로그램을위한 IdP',
|
||||
mfa: '다중 인증',
|
||||
sso: '기업 SSO',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} 역할 및 {{permissionCount, number}} 역할당 권한',
|
||||
pro_plan: '역할당 무제한 역할 및 권한',
|
||||
},
|
||||
organizations: '조직',
|
||||
audit_logs: '감사 로그 보존: {{count, number}} 일',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'{{item}} 할당량 한도를 초과했습니다. Logto는 할당량을 초과하는 사용에 대한 요금을 추가합니다. 새로운 애드온 가격 디자인이 출시된 날부터 청구가 시작됩니다. <a>더 알아보기</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: 'Do {{count, number}} MAU',
|
||||
pro_plan: 'Nieograniczony MAU',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} urządzenia do urządzenia',
|
||||
pro_plan: 'Dodatkowe urządzenie do urządzenia',
|
||||
},
|
||||
third_party_apps: 'IdP dla aplikacji innych firm',
|
||||
mfa: 'Autoryzacja wieloskładnikowa',
|
||||
sso: 'SSO dla przedsiębiorstw',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} rola i {{permissionCount, number}} uprawnienie na rolę',
|
||||
pro_plan: 'Nieograniczone role i uprawnienia na rolę',
|
||||
},
|
||||
organizations: 'Organizacje',
|
||||
audit_logs: 'Przechowywanie dzienników audytu: {{count, number}} dni',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'Przekroczyłeś limit kwoty {{item}}. Logto doliczy opłaty za korzystanie poza limitem kwoty. Fakturowanie rozpocznie się w dniu wprowadzenia nowego projektu cenowego dodatku. <a>Dowiedz się więcej</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: 'Até {{count, number}} MAU',
|
||||
pro_plan: 'MAU ilimitados',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} de máquina para máquina',
|
||||
pro_plan: 'Máquina para máquina adicional',
|
||||
},
|
||||
third_party_apps: 'IdP para aplicativos de terceiros',
|
||||
mfa: 'Autenticação de vários fatores',
|
||||
sso: 'SSO empresarial',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} função e {{permissionCount, number}} permissão por função',
|
||||
pro_plan: 'Funções e permissões ilimitadas por função',
|
||||
},
|
||||
organizations: 'Organizações',
|
||||
audit_logs: 'Retenção de logs de auditoria: {{count, number}} dias',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'Você ultrapassou o limite de sua cota de {{item}}. O Logto adicionará cobranças pelo uso além do limite da cota. A cobrança começará no dia em que o novo design de preços do complemento for lançado. <a>Saiba mais</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: 'Até {{count, number}} MAU',
|
||||
pro_plan: 'MAU ilimitados',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} de máquina para máquina',
|
||||
pro_plan: 'Máquina para máquina adicional',
|
||||
},
|
||||
third_party_apps: 'IdP para aplicações de terceiros',
|
||||
mfa: 'Autenticação de vários fatores',
|
||||
sso: 'SSO empresarial',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} função e {{permissionCount, number}} permissão por função',
|
||||
pro_plan: 'Funções e permissões ilimitadas por função',
|
||||
},
|
||||
organizations: 'Organizações',
|
||||
audit_logs: 'Retenção de logs de auditoria: {{count, number}} dias',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'Você ultrapassou o limite de sua cota de {{item}}. O Logto adicionará cobranças pelo uso além do limite da cota. A cobrança começará no dia em que o novo design de preços do complemento for lançado. <a>Saiba mais</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: 'До {{count, number}} MAU',
|
||||
pro_plan: 'Неограниченные MAU',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} от устройства к устройству',
|
||||
pro_plan: 'Дополнительное устройство к устройству',
|
||||
},
|
||||
third_party_apps: 'IdP для сторонних приложений',
|
||||
mfa: 'Многофакторная аутентификация',
|
||||
sso: 'Корпоративный SSO',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} роль и {{permissionCount, number}} разрешение на роль',
|
||||
pro_plan: 'Неограниченные роли и разрешения на роль',
|
||||
},
|
||||
organizations: 'Организации',
|
||||
audit_logs: 'Хранение журналов аудита: {{count, number}} дней',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'Вы превысили лимит вашей квоты по {{item}}. Logto начнет взимать плату за использование сверх вашей квоты. Начисление начнется в день выпуска нового дизайна цен на дополнение. <a>Узнать больше</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: "{{count, number}} MAU'ya kadar",
|
||||
pro_plan: 'Sınırsız MAU',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} makineye makineye',
|
||||
pro_plan: 'Ek makineye makineye',
|
||||
},
|
||||
third_party_apps: 'Üçüncü taraf uygulamalar için IdP',
|
||||
mfa: 'Çok faktörlü kimlik doğrulama',
|
||||
sso: 'Kurumsal SSO',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} rol ve {{permissionCount, number}} izin başına rol',
|
||||
pro_plan: 'Rol başına sınırsız roller ve izinler',
|
||||
},
|
||||
organizations: 'Organizasyonlar',
|
||||
audit_logs: 'Denetim günlükleri saklama: {{count, number}} gün',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'{{item}} kota sınırını aştınız. Logto, kota sınırınızın ötesindeki kullanım için ücret ekleyecektir. Yeni ek paket fiyatlandırma tasarımı gününüzde başlayacaktır. <a>Daha fazla bilgi</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: '最多{{count, number}} MAU',
|
||||
pro_plan: '无限 MAU',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} 机器对机器',
|
||||
pro_plan: '额外的机器对机器',
|
||||
},
|
||||
third_party_apps: '第三方应用的 IdP',
|
||||
mfa: '多因素认证',
|
||||
sso: '企业单点登录',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} 角色和每个角色 {{permissionCount, number}} 权限',
|
||||
pro_plan: '无限角色和每个角色权限',
|
||||
},
|
||||
organizations: '组织',
|
||||
audit_logs: '审计日志保留:{{count, number}} 天',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'您已超过{{item}}配额限制。Logto将为超出配额限制的使用添加费用。计费将从新的附加定价设计发布当天开始。 <a>了解更多</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: '最多{{count, number}} MAU',
|
||||
pro_plan: '無限 MAU',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} 機器對機器',
|
||||
pro_plan: '額外的機器對機器',
|
||||
},
|
||||
third_party_apps: '第三方應用的 IdP',
|
||||
mfa: '多因素認證',
|
||||
sso: '企業單點登錄',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} 角色和每個角色 {{permissionCount, number}} 權限',
|
||||
pro_plan: '無限角色和每個角色權限',
|
||||
},
|
||||
organizations: '組織',
|
||||
audit_logs: '審計日誌保留:{{count, number}} 天',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'您已超出{{item}}配額限制。Logto將為超出配額限制的使用添加費用。計費將從新的附加定價設計發布當天開始。 <a>了解更多</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const featured_plan_content = {
|
||||
mau: {
|
||||
free_plan: '最多{{count, number}} MAU',
|
||||
pro_plan: '無限 MAU',
|
||||
},
|
||||
m2m: {
|
||||
free_plan: '{{count, number}} 機器對機器',
|
||||
pro_plan: '額外的機器對機器',
|
||||
},
|
||||
third_party_apps: '第三方應用的 IdP',
|
||||
mfa: '多因素認證',
|
||||
sso: '企業單點登錄',
|
||||
role_and_permissions: {
|
||||
free_plan: '{{roleCount, number}} 角色和每個角色 {{permissionCount, number}} 權限',
|
||||
pro_plan: '無限角色和每個角色權限',
|
||||
},
|
||||
organizations: '組織',
|
||||
audit_logs: '審計日誌保留:{{count, number}} 天',
|
||||
};
|
||||
|
||||
export default Object.freeze(featured_plan_content);
|
|
@ -1,3 +1,4 @@
|
|||
import featured_plan_content from './featured-plan-content.js';
|
||||
import paywall from './paywall.js';
|
||||
|
||||
const upsell = {
|
||||
|
@ -38,6 +39,7 @@ const upsell = {
|
|||
charge_notification_for_quota_limit:
|
||||
'您已超出{{item}}額度限制。Logto將為超出額度限制的使用添加費用。計費將從新的附加價格設計發布當天開始。 <a>了解更多</a>',
|
||||
paywall,
|
||||
featured_plan_content,
|
||||
};
|
||||
|
||||
export default Object.freeze(upsell);
|
||||
|
|
Loading…
Add table
Reference in a new issue