mirror of
https://github.com/logto-io/logto.git
synced 2025-04-07 23:01:25 -05:00
feat(console): display not eligible reminder for plan switching (#4216)
This commit is contained in:
parent
28634c5800
commit
36b5958935
20 changed files with 263 additions and 147 deletions
|
@ -1,4 +1,4 @@
|
|||
import { useContext } from 'react';
|
||||
import { useContext, useMemo } from 'react';
|
||||
|
||||
import { toastResponseError } from '@/cloud/hooks/use-cloud-api';
|
||||
import { subscriptionPage } from '@/consts/pages';
|
||||
|
@ -6,8 +6,12 @@ import { ReservedPlanId } from '@/consts/subscriptions';
|
|||
import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||
import DynamicT from '@/ds-components/DynamicT';
|
||||
import InlineNotification from '@/ds-components/InlineNotification';
|
||||
import { useConfirmModal } from '@/hooks/use-confirm-modal';
|
||||
import useSubscribe from '@/hooks/use-subscribe';
|
||||
import useSubscriptionPlans from '@/hooks/use-subscription-plans';
|
||||
import NotEligibleSwitchPlanModalContent from '@/pages/TenantSettings/components/NotEligibleSwitchPlanModalContent';
|
||||
import { type SubscriptionPlan } from '@/types/subscriptions';
|
||||
import { isExceededQuotaLimitError } from '@/utils/subscription';
|
||||
|
||||
type Props = {
|
||||
activeUsers: number;
|
||||
|
@ -18,12 +22,21 @@ type Props = {
|
|||
function MauLimitExceededNotification({ activeUsers, currentPlan, className }: Props) {
|
||||
const { currentTenantId } = useContext(TenantsContext);
|
||||
const { subscribe } = useSubscribe();
|
||||
const { show } = useConfirmModal();
|
||||
const { data: subscriptionPlans } = useSubscriptionPlans();
|
||||
const proPlan = useMemo(
|
||||
() => subscriptionPlans?.find(({ id }) => id === ReservedPlanId.pro),
|
||||
[subscriptionPlans]
|
||||
);
|
||||
|
||||
const {
|
||||
quota: { mauLimit },
|
||||
} = currentPlan;
|
||||
|
||||
if (
|
||||
mauLimit === null || // Unlimited
|
||||
activeUsers < mauLimit
|
||||
activeUsers < mauLimit ||
|
||||
!proPlan
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
@ -36,11 +49,21 @@ function MauLimitExceededNotification({ activeUsers, currentPlan, className }: P
|
|||
onClick={async () => {
|
||||
try {
|
||||
await subscribe({
|
||||
planId: ReservedPlanId.pro,
|
||||
planId: proPlan.id,
|
||||
tenantId: currentTenantId,
|
||||
callbackPage: subscriptionPage,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
if (await isExceededQuotaLimitError(error)) {
|
||||
await show({
|
||||
ModalContent: () => <NotEligibleSwitchPlanModalContent targetPlan={proPlan} />,
|
||||
title: 'subscription.not_eligible_modal.upgrade_title',
|
||||
confirmButtonText: 'general.got_it',
|
||||
confirmButtonType: 'primary',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
void toastResponseError(error);
|
||||
}
|
||||
}}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { ResponseError } from '@withtyped/client';
|
||||
import { useContext } from 'react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
|
||||
import { responseErrorBodyGuard, toastResponseError } from '@/cloud/hooks/use-cloud-api';
|
||||
import { toastResponseError } from '@/cloud/hooks/use-cloud-api';
|
||||
import PlanName from '@/components/PlanName';
|
||||
import { contactEmailLink } from '@/consts';
|
||||
import { subscriptionPage } from '@/consts/pages';
|
||||
|
@ -13,11 +12,11 @@ import Button from '@/ds-components/Button';
|
|||
import Spacer from '@/ds-components/Spacer';
|
||||
import { useConfirmModal } from '@/hooks/use-confirm-modal';
|
||||
import useSubscribe from '@/hooks/use-subscribe';
|
||||
import NotEligibleSwitchPlanModalContent from '@/pages/TenantSettings/components/NotEligibleSwitchPlanModalContent';
|
||||
import { type SubscriptionPlan } from '@/types/subscriptions';
|
||||
import { isDowngradePlan } from '@/utils/subscription';
|
||||
import { isDowngradePlan, isExceededQuotaLimitError } from '@/utils/subscription';
|
||||
|
||||
import DowngradeConfirmModalContent from '../DowngradeConfirmModalContent';
|
||||
import NotEligibleDowngradeModalContent from '../NotEligibleDowngradeModalContent';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
|
@ -37,64 +36,62 @@ function SwitchPlanActionBar({
|
|||
const { subscribe, cancelSubscription } = useSubscribe();
|
||||
const { show } = useConfirmModal();
|
||||
|
||||
const handleDownGrade = async (targetPlan: SubscriptionPlan) => {
|
||||
const { id: planId, name } = targetPlan;
|
||||
try {
|
||||
if (planId === ReservedPlanId.free) {
|
||||
await cancelSubscription(currentTenantId);
|
||||
onSubscriptionUpdated();
|
||||
toast.success(
|
||||
<Trans components={{ name: <PlanName name={name} /> }}>{t('downgrade_success')}</Trans>
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await subscribe({
|
||||
tenantId: currentTenantId,
|
||||
planId,
|
||||
isDowngrade: true,
|
||||
callbackPage: subscriptionPage,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
/**
|
||||
* Note: this is a temporary solution to handle the case when the user tries to downgrade but the quota limit is exceeded.
|
||||
* Need a better solution to handle this case by sharing the error type between the console and cloud. - LOG-6608
|
||||
*/
|
||||
if (error instanceof ResponseError) {
|
||||
const parsed = responseErrorBodyGuard.safeParse(await error.response.json());
|
||||
if (parsed.success && parsed.data.message.includes('Exceeded quota limit')) {
|
||||
await show({
|
||||
ModalContent: () => <NotEligibleDowngradeModalContent targetPlan={targetPlan} />,
|
||||
title: 'subscription.downgrade_modal.not_eligible',
|
||||
confirmButtonText: 'general.got_it',
|
||||
confirmButtonType: 'primary',
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void toastResponseError(error);
|
||||
}
|
||||
};
|
||||
|
||||
const onDowngradeClick = async (targetPlanId: string) => {
|
||||
const handleSubscribe = async (targetPlanId: string, isDowngrade: boolean) => {
|
||||
const currentPlan = subscriptionPlans.find(({ id }) => id === currentSubscriptionPlanId);
|
||||
const targetPlan = subscriptionPlans.find(({ id }) => id === targetPlanId);
|
||||
if (!currentPlan || !targetPlan) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [result] = await show({
|
||||
ModalContent: () => (
|
||||
<DowngradeConfirmModalContent currentPlan={currentPlan} targetPlan={targetPlan} />
|
||||
),
|
||||
title: 'subscription.downgrade_modal.title',
|
||||
confirmButtonText: 'subscription.downgrade_modal.downgrade',
|
||||
size: 'large',
|
||||
});
|
||||
if (isDowngrade) {
|
||||
const [result] = await show({
|
||||
ModalContent: () => (
|
||||
<DowngradeConfirmModalContent currentPlan={currentPlan} targetPlan={targetPlan} />
|
||||
),
|
||||
title: 'subscription.downgrade_modal.title',
|
||||
confirmButtonText: 'subscription.downgrade_modal.downgrade',
|
||||
size: 'large',
|
||||
});
|
||||
|
||||
if (result) {
|
||||
await handleDownGrade(targetPlan);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (targetPlanId === ReservedPlanId.free) {
|
||||
await cancelSubscription(currentTenantId);
|
||||
onSubscriptionUpdated();
|
||||
toast.success(
|
||||
<Trans components={{ name: <PlanName name={targetPlan.name} /> }}>
|
||||
{t('downgrade_success')}
|
||||
</Trans>
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await subscribe({
|
||||
tenantId: currentTenantId,
|
||||
planId: targetPlanId,
|
||||
isDowngrade,
|
||||
callbackPage: subscriptionPage,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
if (await isExceededQuotaLimitError(error)) {
|
||||
await show({
|
||||
ModalContent: () => (
|
||||
<NotEligibleSwitchPlanModalContent targetPlan={targetPlan} isDowngrade={isDowngrade} />
|
||||
),
|
||||
title: isDowngrade
|
||||
? 'subscription.not_eligible_modal.downgrade_title'
|
||||
: 'subscription.not_eligible_modal.upgrade_title',
|
||||
confirmButtonText: 'general.got_it',
|
||||
confirmButtonType: 'primary',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
void toastResponseError(error);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -117,22 +114,8 @@ function SwitchPlanActionBar({
|
|||
}
|
||||
type={isDowngrade ? 'default' : 'primary'}
|
||||
disabled={isCurrentPlan}
|
||||
onClick={async () => {
|
||||
if (isDowngrade) {
|
||||
await onDowngradeClick(planId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await subscribe({
|
||||
tenantId: currentTenantId,
|
||||
planId,
|
||||
callbackPage: subscriptionPage,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
void toastResponseError(error);
|
||||
}
|
||||
onClick={() => {
|
||||
void handleSubscribe(planId, isDowngrade);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -20,10 +20,13 @@ const excludedQuotaKeys = new Set<keyof SubscriptionPlanQuota>([
|
|||
|
||||
type Props = {
|
||||
targetPlan: SubscriptionPlan;
|
||||
isDowngrade?: boolean;
|
||||
};
|
||||
|
||||
function NotEligibleDowngradeModalContent({ targetPlan }: Props) {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
function NotEligibleSwitchPlanModalContent({ targetPlan, isDowngrade = false }: Props) {
|
||||
const { t } = useTranslation(undefined, {
|
||||
keyPrefix: 'admin_console.subscription.not_eligible_modal',
|
||||
});
|
||||
|
||||
const { name, quota } = targetPlan;
|
||||
|
||||
|
@ -40,7 +43,7 @@ function NotEligibleDowngradeModalContent({ targetPlan }: Props) {
|
|||
name: <PlanName name={name} />,
|
||||
}}
|
||||
>
|
||||
{t('subscription.downgrade_modal.not_eligible_description')}
|
||||
{t(isDowngrade ? 'downgrade_description' : 'upgrade_description')}
|
||||
</Trans>
|
||||
</div>
|
||||
<ul className={styles.list}>
|
||||
|
@ -68,7 +71,7 @@ function NotEligibleDowngradeModalContent({ targetPlan }: Props) {
|
|||
),
|
||||
}}
|
||||
>
|
||||
{t('subscription.downgrade_modal.a_maximum_of')}
|
||||
{t('a_maximum_of')}
|
||||
</Trans>
|
||||
) : (
|
||||
<DynamicT
|
||||
|
@ -84,10 +87,10 @@ function NotEligibleDowngradeModalContent({ targetPlan }: Props) {
|
|||
a: <ContactUsPhraseLink />,
|
||||
}}
|
||||
>
|
||||
{t('subscription.downgrade_modal.help_tip')}
|
||||
{t(isDowngrade ? 'downgrade_help_tip' : 'upgrade_help_tip')}
|
||||
</Trans>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default NotEligibleDowngradeModalContent;
|
||||
export default NotEligibleSwitchPlanModalContent;
|
|
@ -1,5 +1,7 @@
|
|||
import { ResponseError } from '@withtyped/client';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { responseErrorBodyGuard } from '@/cloud/hooks/use-cloud-api';
|
||||
import { type SubscriptionPlanResponse } from '@/cloud/types/router';
|
||||
import {
|
||||
communitySupportEnabledMap,
|
||||
|
@ -52,3 +54,21 @@ export const getLatestUnpaidInvoice = (invoices: Invoice[]) =>
|
|||
new Date(invoiceB.createdAt).getTime() - new Date(invoiceA.createdAt).getTime()
|
||||
)
|
||||
.find(({ status }) => status === 'uncollectible');
|
||||
|
||||
/**
|
||||
* Note: this is a temporary solution to handle the case when the user tries to downgrade but the quota limit is exceeded.
|
||||
* Need a better solution to handle this case by sharing the error type between the console and cloud. - LOG-6608
|
||||
*/
|
||||
export const isExceededQuotaLimitError = async (error: unknown) => {
|
||||
if (!(error instanceof ResponseError)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const responseBody = await error.response.json();
|
||||
const { message } = responseErrorBodyGuard.parse(responseBody);
|
||||
return message.includes('Exceeded quota limit');
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -51,11 +51,17 @@ const subscription = {
|
|||
before: 'Vorher: <name/>',
|
||||
after: 'Nachher: <name />',
|
||||
downgrade: 'Herabstufen',
|
||||
not_eligible: 'Sie sind nicht berechtigt für eine Herabstufung',
|
||||
not_eligible_description:
|
||||
'Stellen Sie sicher, dass Sie die folgenden Kriterien erfüllen, bevor Sie auf <name/> herabstufen.',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: 'Downgrade nicht möglich',
|
||||
downgrade_description:
|
||||
'Stellen Sie sicher, dass Sie die folgenden Kriterien erfüllen, bevor Sie auf <name/> downgraden.',
|
||||
downgrade_help_tip: 'Hilfe beim Downgrade benötigt? <a>Kontaktieren Sie uns</a>.',
|
||||
upgrade_title: 'Upgrade nicht möglich',
|
||||
upgrade_description:
|
||||
'Sie verwenden derzeit mehr als das von <name /> zugelassene Kontingent. Stellen Sie sicher, dass Sie die folgenden Kriterien erfüllen, bevor Sie auf <name/> upgraden.',
|
||||
upgrade_help_tip: 'Hilfe beim Upgrade benötigt? <a>Kontaktieren Sie uns</a>.',
|
||||
a_maximum_of: 'Maximal <item/>',
|
||||
help_tip: 'Benötigen Sie Hilfe beim Herabstufen? <a>Kontaktieren Sie uns</a>.',
|
||||
},
|
||||
upgrade_success: 'Erfolgreich auf <name/> hochgestuft',
|
||||
downgrade_success: 'Erfolgreich auf <name/> herabgestuft',
|
||||
|
|
|
@ -51,11 +51,17 @@ const subscription = {
|
|||
before: 'Before: <name/>',
|
||||
after: 'After: <name />',
|
||||
downgrade: 'Downgrade',
|
||||
not_eligible: 'You are not eligible for downgrade',
|
||||
not_eligible_description:
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: 'You are not eligible for downgrade',
|
||||
downgrade_description:
|
||||
'Make sure you meet the following criteria before downgrading to the <name/>.',
|
||||
downgrade_help_tip: 'Need help downgrading? <a>Contact us</a>.',
|
||||
upgrade_title: 'You are not eligible for upgrade',
|
||||
upgrade_description:
|
||||
'You’re currently using more than what the <name /> allows. Before you consider upgrading to the <name />, make sure you meet the following criteria before upgrading.',
|
||||
upgrade_help_tip: 'Need help upgrading? <a>Contact us</a>.',
|
||||
a_maximum_of: 'A maximum of <item/>',
|
||||
help_tip: 'Need help downgrading? <a>Contact us</a>.',
|
||||
},
|
||||
upgrade_success: 'Successfully upgraded to <name/>',
|
||||
downgrade_success: 'Successfully downgraded to <name/>',
|
||||
|
|
|
@ -53,11 +53,17 @@ const subscription = {
|
|||
before: 'Antes: <name/>',
|
||||
after: 'Después: <name/>',
|
||||
downgrade: 'Degradar',
|
||||
not_eligible: 'No cumple con los requisitos para degradar',
|
||||
not_eligible_description:
|
||||
'Asegúrese de cumplir con los siguientes criterios antes de degradar a <name/>.',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: 'No es posible el cambio a un plan inferior',
|
||||
downgrade_description:
|
||||
'Asegúrese de cumplir con los siguientes criterios antes de cambiar al plan <name/>.',
|
||||
downgrade_help_tip: '¿Necesitas ayuda para cambiar de plan? <a>Contáctenos</a>.',
|
||||
upgrade_title: 'No es posible el cambio a un plan superior',
|
||||
upgrade_description:
|
||||
'Actualmente está utilizando más de lo permitido por el plan <name />. Asegúrese de cumplir con los siguientes criterios antes de considerar el cambio al plan <name/>.',
|
||||
upgrade_help_tip: '¿Necesitas ayuda para cambiar de plan? <a>Contáctenos</a>.',
|
||||
a_maximum_of: 'Un máximo de <item/>',
|
||||
help_tip: 'Necesitas ayuda para degradar? <a>Contáctenos</a>.',
|
||||
},
|
||||
upgrade_success: 'Actualizado con éxito a <name/>',
|
||||
downgrade_success: 'Degradado con éxito a <name/>',
|
||||
|
|
|
@ -45,9 +45,7 @@ const subscription = {
|
|||
uncollectible: 'En souffrance',
|
||||
},
|
||||
},
|
||||
|
||||
quota_item,
|
||||
|
||||
downgrade_modal: {
|
||||
title: 'Êtes-vous sûr de vouloir passer à un Plan Inférieur?',
|
||||
description:
|
||||
|
@ -55,11 +53,17 @@ const subscription = {
|
|||
before: 'Avant: <name/>',
|
||||
after: 'Après: <name />',
|
||||
downgrade: 'Passer à un Plan Inférieur',
|
||||
not_eligible: "Vous n'êtes pas éligible pour passer à un Plan Inférieur",
|
||||
not_eligible_description:
|
||||
'Veuillez vous assurer de répondre aux critères suivants avant de passer au <name/>. ',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: "Vous n'êtes pas éligible pour une rétrogradation",
|
||||
downgrade_description:
|
||||
'Assurez-vous de remplir les critères suivants avant de rétrograder vers le plan <name/>.',
|
||||
downgrade_help_tip: "Besoin d'aide pour rétrograder ? <a>Contactez-nous</a>.",
|
||||
upgrade_title: "Vous n'êtes pas éligible pour une mise à niveau",
|
||||
upgrade_description:
|
||||
'Vous utilisez actuellement plus que ce que permet le plan <name />. Avant de considérer une mise à niveau vers le plan <name/>, assurez-vous de remplir les critères suivants.',
|
||||
upgrade_help_tip: "Besoin d'aide pour la mise à niveau ? <a>Contactez-nous</a>.",
|
||||
a_maximum_of: 'Un maximum de <item/>',
|
||||
help_tip: "Besoin d'aide pour rétrograder ? <a>Contactez-nous</a>.",
|
||||
},
|
||||
upgrade_success: 'Passé avec succès à <name/>',
|
||||
downgrade_success: 'Rétrogradé avec succès à <name/>',
|
||||
|
|
|
@ -52,11 +52,17 @@ const subscription = {
|
|||
before: 'Prima: <name/>',
|
||||
after: 'Dopo: <name />',
|
||||
downgrade: 'Degrado',
|
||||
not_eligible: 'Non sei idoneo al degrado',
|
||||
not_eligible_description:
|
||||
'Assicurati di soddisfare i seguenti criteri prima di degradare a <name/>.',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: 'Non sei idoneo per il downgrade',
|
||||
downgrade_description:
|
||||
'Assicurati di soddisfare i seguenti criteri prima di eseguire il downgrade al piano <name/>.',
|
||||
downgrade_help_tip: 'Hai bisogno di aiuto per il downgrade? <a>Contattaci</a>.',
|
||||
upgrade_title: "Non sei idoneo per l'upgrade",
|
||||
upgrade_description:
|
||||
"Attualmente stai utilizzando più di quanto consentito dal piano <name />. Prima di considerare l'upgrade al piano <name/>, assicurati di soddisfare i seguenti criteri.",
|
||||
upgrade_help_tip: "Hai bisogno di aiuto per l'upgrade? <a>Contattaci</a>.",
|
||||
a_maximum_of: 'Un massimo di <item/>',
|
||||
help_tip: 'Hai bisogno di aiuto per il degrado? <a>Contattaci</a>.',
|
||||
},
|
||||
upgrade_success: 'Aggiornamento effettuato con successo a <name/>',
|
||||
downgrade_success: 'Degrado effettuato con successo a <name/>',
|
||||
|
|
|
@ -52,11 +52,17 @@ const subscription = {
|
|||
before: '前: <name/>',
|
||||
after: '後: <name/>',
|
||||
downgrade: 'ダウングレード',
|
||||
not_eligible: 'ダウングレードできません',
|
||||
not_eligible_description:
|
||||
'<name/>にダウングレードする前に、以下の基準を満たしていることを確認してください。',
|
||||
a_maximum_of: '最大 <item/>',
|
||||
help_tip: 'ダウングレードのヘルプが必要ですか? <a>お問い合わせ</a>。',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: 'ダウングレードの対象外です',
|
||||
downgrade_description:
|
||||
'<name/>へダウングレードする前に、以下の条件を満たしていることを確認してください。',
|
||||
downgrade_help_tip: 'ダウングレードのヘルプが必要ですか?<a>お問い合わせください</a>。',
|
||||
upgrade_title: 'アップグレードの対象外です',
|
||||
upgrade_description:
|
||||
'<name />が許可する量を超えて使用しています。 <name />へのアップグレードを検討する前に、以下の条件を満たしていることを確認してください。',
|
||||
upgrade_help_tip: 'アップグレードのヘルプが必要ですか?<a>お問い合わせください</a>。',
|
||||
a_maximum_of: '<item/>の最大数',
|
||||
},
|
||||
upgrade_success: '正常に<name/>にアップグレードされました',
|
||||
downgrade_success: '正常に<name/>にダウングレードされました',
|
||||
|
|
|
@ -51,11 +51,16 @@ const subscription = {
|
|||
before: '이전: <name />',
|
||||
after: '이후: <name />',
|
||||
downgrade: '다운그레이드',
|
||||
not_eligible: '다운그레이드할 수 없습니다.',
|
||||
not_eligible_description:
|
||||
'<name />으로 다운그레이드하기 전에 다음 기준을 충족하는지 확인하세요.',
|
||||
a_maximum_of: '<item /> 최대',
|
||||
help_tip: '다운그레이드 도움이 필요하신가요? <a>문의하기</a>.',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: '다운그레이드할 수 없습니다',
|
||||
downgrade_description: '<name/>로 다운그레이드하기 전에 다음 기준을 충족하는지 확인하세요.',
|
||||
downgrade_help_tip: '다운그레이드 도움이 필요하세요? <a>문의하세요</a>.',
|
||||
upgrade_title: '업그레이드할 수 없습니다',
|
||||
upgrade_description:
|
||||
'<name />이(가) 허용하는 양을 현재 사용 중입니다. <name />로 업그레이드를 고려하기 전에 다음 기준을 충족하는지 확인하세요.',
|
||||
upgrade_help_tip: '업그레이드 도움이 필요하세요? <a>문의하세요</a>.',
|
||||
a_maximum_of: '<item/> 최대 한도',
|
||||
},
|
||||
upgrade_success: '성공적으로 <name/>으로 업그레이드되었습니다.',
|
||||
downgrade_success: '성공적으로 <name/>으로 다운그레이드되었습니다.',
|
||||
|
|
|
@ -52,11 +52,17 @@ const subscription = {
|
|||
before: 'Przed: <name/>',
|
||||
after: 'Po: <name />',
|
||||
downgrade: 'Zdegradować',
|
||||
not_eligible: 'Nie spełniasz wymogów do zdegradowania',
|
||||
not_eligible_description:
|
||||
'Upewnij się, że spełniasz następujące kryteria przed dokonaniem degradacji do <name/>. ',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: 'Nie spełniasz warunków do zmniejszenia',
|
||||
downgrade_description:
|
||||
'Upewnij się, że spełniasz następujące kryteria przed zmniejszeniem do <name/>.',
|
||||
downgrade_help_tip: 'Potrzebna pomoc przy zmniejszaniu? <a>Skontaktuj się z nami</a>.',
|
||||
upgrade_title: 'Nie spełniasz warunków do zwiększenia',
|
||||
upgrade_description:
|
||||
'Obecnie używasz więcej niż to, co pozwala <name />. Przed rozważeniem zwiększenia do <name/>, upewnij się, że spełniasz następujące kryteria.',
|
||||
upgrade_help_tip: 'Potrzebna pomoc przy zwiększaniu? <a>Skontaktuj się z nami</a>.',
|
||||
a_maximum_of: 'Maksymalnie <item/>',
|
||||
help_tip: 'Potrzebujesz pomocy przy zdegradowaniu? <a>Skontaktuj się z nami</a>.',
|
||||
},
|
||||
upgrade_success: 'Pomyślnie uaktualniono do <name/>',
|
||||
downgrade_success: 'Pomyślnie zdegradowano do <name/>',
|
||||
|
|
|
@ -43,9 +43,7 @@ const subscription = {
|
|||
uncollectible: 'Vencida',
|
||||
},
|
||||
},
|
||||
|
||||
quota_item,
|
||||
|
||||
downgrade_modal: {
|
||||
title: 'Tem certeza de que deseja fazer downgrade?',
|
||||
description:
|
||||
|
@ -53,11 +51,17 @@ const subscription = {
|
|||
before: 'Antes: <name/>',
|
||||
after: 'Depois: <name />',
|
||||
downgrade: 'Downgrade',
|
||||
not_eligible: 'Não é elegível para downgrade',
|
||||
not_eligible_description:
|
||||
'Certifique-se de atender aos seguintes critérios antes de fazer downgrade para o <name/>.',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: 'Você não é elegível para fazer downgrade',
|
||||
downgrade_description:
|
||||
'Certifique-se de atender aos seguintes critérios antes de fazer o downgrade para o plano <name/>.',
|
||||
downgrade_help_tip: 'Precisa de ajuda com o downgrade? <a>Contate-nos</a>.',
|
||||
upgrade_title: 'Você não é elegível para fazer upgrade',
|
||||
upgrade_description:
|
||||
'Atualmente, você está usando mais do que o permitido pelo plano <name/>. Antes de considerar o upgrade para o plano <name/>, certifique-se de atender aos seguintes critérios.',
|
||||
upgrade_help_tip: 'Precisa de ajuda com o upgrade? <a>Contate-nos</a>.',
|
||||
a_maximum_of: 'Um máximo de <item/>',
|
||||
help_tip: 'Precisa de ajuda para fazer o downgrade? <a>Contate-nos</a>.',
|
||||
},
|
||||
upgrade_success: 'Atualizado com sucesso para <name/>',
|
||||
downgrade_success: 'Downgrade realizado com sucesso para <name/>',
|
||||
|
|
|
@ -52,11 +52,17 @@ const subscription = {
|
|||
before: 'Antes: <name/>',
|
||||
after: 'Depois: <name />',
|
||||
downgrade: 'Downgrade',
|
||||
not_eligible: 'Você não é elegível para fazer o downgrade',
|
||||
not_eligible_description:
|
||||
'Verifique se você atende aos seguintes critérios antes de fazer o downgrade para o <name/>.',
|
||||
a_maximum_of: 'No máximo <item/>',
|
||||
help_tip: 'Precisa de ajuda para fazer o downgrade? <a>Entre em contato conosco</a>.',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: 'Não é possível fazer downgrade',
|
||||
downgrade_description:
|
||||
'Certifique-se de cumprir os seguintes critérios antes de efetuar o downgrade para o plano <name/>.',
|
||||
downgrade_help_tip: 'Precisa de ajuda com o downgrade? <a>Contacte-nos</a>.',
|
||||
upgrade_title: 'Não é possível fazer upgrade',
|
||||
upgrade_description:
|
||||
'Atualmente está a utilizar mais do que o permitido pelo plano <name/>. Antes de considerar o upgrade para o plano <name/>, certifique-se de cumprir os seguintes critérios.',
|
||||
upgrade_help_tip: 'Precisa de ajuda com o upgrade? <a>Contacte-nos</a>.',
|
||||
a_maximum_of: 'Um máximo de <item/>',
|
||||
},
|
||||
upgrade_success: 'Atualizou com sucesso para <name/>',
|
||||
downgrade_success: 'Downgrade concluído com sucesso para <name/>',
|
||||
|
|
|
@ -51,11 +51,17 @@ const subscription = {
|
|||
before: 'Позднее: <name/>',
|
||||
after: 'После: <name />',
|
||||
downgrade: 'Понизить уровень',
|
||||
not_eligible: 'Вы не имеете права на понижение уровня',
|
||||
not_eligible_description:
|
||||
'Убедитесь, что вы соответствуете следующим критериям, прежде чем понизить до <name/>.',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: 'Вы не можете понизить уровень тарифа',
|
||||
downgrade_description:
|
||||
'Перед понижением до тарифа <name/>, убедитесь, что соответствуете следующим критериям.',
|
||||
downgrade_help_tip: 'Нужна помощь в понижении? <a>Свяжитесь с нами</a>.',
|
||||
upgrade_title: 'Вы не можете повысить уровень тарифа',
|
||||
upgrade_description:
|
||||
'В настоящее время вы используете более того, что позволяет тариф <name />. Перед рассмотрением перехода на тариф <name/>, убедитесь, что соответствуете следующим критериям.',
|
||||
upgrade_help_tip: 'Нужна помощь в повышении? <a>Свяжитесь с нами</a>.',
|
||||
a_maximum_of: 'Максимум <item/>',
|
||||
help_tip: 'Нужна помощь в понижении уровня? <a>Свяжитесь с нами</a>.',
|
||||
},
|
||||
upgrade_success: 'Успешно повышен до <name/>',
|
||||
downgrade_success: 'Успешно понижен до <name/>',
|
||||
|
|
|
@ -52,11 +52,19 @@ const subscription = {
|
|||
before: 'Önce: <name/>',
|
||||
after: 'Sonra: <name />',
|
||||
downgrade: 'Düşür',
|
||||
not_eligible: 'Düşürme için uygun değilsiniz',
|
||||
not_eligible_description:
|
||||
"Aşağıdaki kriterleri karşıladığınızdan emin olun <name/>'ye düşürmeden önce.",
|
||||
a_maximum_of: 'En fazla <item/>',
|
||||
help_tip: 'Düşürme için yardıma mı ihtiyacınız var? <a>Bizimle iletişime geçin</a>.',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: 'Düşürme için uygun değilsiniz',
|
||||
downgrade_description:
|
||||
'<name/> planına düşürmeden önce aşağıdaki kriterleri sağladığınızdan emin olun.',
|
||||
downgrade_help_tip:
|
||||
'Düşürme konusunda yardıma mı ihtiyacınız var? <a>Bizimle iletişime geçin</a>.',
|
||||
upgrade_title: 'Yükseltme için uygun değilsiniz',
|
||||
upgrade_description:
|
||||
'Şu anda <name /> izin verilen miktarın üzerinde kullanıyorsunuz. <name /> planına yükseltmeyi düşünmeden önce aşağıdaki kriterleri sağladığınızdan emin olun.',
|
||||
upgrade_help_tip:
|
||||
'Yükseltme konusunda yardıma mı ihtiyacınız var? <a>Bizimle iletişime geçin</a>.',
|
||||
a_maximum_of: '<item/> için maksimum',
|
||||
},
|
||||
upgrade_success: 'Successfully upgraded to <name/>',
|
||||
downgrade_success: 'Successfully downgraded to <name/>',
|
||||
|
|
|
@ -50,10 +50,16 @@ const subscription = {
|
|||
before: '之前:<name/>',
|
||||
after: '之后:<name />',
|
||||
downgrade: '降级',
|
||||
not_eligible: '您不符合降级条件',
|
||||
not_eligible_description: '在降级到 <name/> 之前,请确保满足以下条件。',
|
||||
a_maximum_of: '最多<item/>个',
|
||||
help_tip: '需要帮助降级?<a>联系我们</a>。',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: '您不符合降级条件',
|
||||
downgrade_description: '降级到<name/>前,请确保满足以下条件。',
|
||||
downgrade_help_tip: '需要降级帮助?<a>联系我们</a>。',
|
||||
upgrade_title: '您不符合升级条件',
|
||||
upgrade_description:
|
||||
'您目前使用的内容超过了<name />允许的范围。在考虑升级到<name/>之前,请确保满足以下条件。',
|
||||
upgrade_help_tip: '需要升级帮助?<a>联系我们</a>。',
|
||||
a_maximum_of: '最多<item/>',
|
||||
},
|
||||
upgrade_success: '成功升级到 <name/>',
|
||||
downgrade_success: '成功降级到 <name/>',
|
||||
|
|
|
@ -49,10 +49,16 @@ const subscription = {
|
|||
before: '之前:<name/>',
|
||||
after: '之後:<name/>',
|
||||
downgrade: '降級',
|
||||
not_eligible: '您不符合降級的資格',
|
||||
not_eligible_description: '在降級到<name/>之前,請確保符合以下標準。',
|
||||
a_maximum_of: '最多:<item/>',
|
||||
help_tip: '需要協助降級嗎?<a>聯繫我們</a>。',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: '您不符合降級條件',
|
||||
downgrade_description: '降級到<name/>前,請確保符合以下條件。',
|
||||
downgrade_help_tip: '需要降級幫助?<a>聯絡我們</a>。',
|
||||
upgrade_title: '您不符合升級條件',
|
||||
upgrade_description:
|
||||
'您目前使用的內容超過了<name />允許的範圍。在考慮升級到<name/>之前,請確保符合以下條件。',
|
||||
upgrade_help_tip: '需要升級幫助?<a>聯絡我們</a>。',
|
||||
a_maximum_of: '最多<item/>',
|
||||
},
|
||||
upgrade_success: '升級成功至<name/>',
|
||||
downgrade_success: '成功降級至<name/>',
|
||||
|
|
|
@ -49,10 +49,16 @@ const subscription = {
|
|||
before: '在此之前:<name/>',
|
||||
after: '在此之後:<name/>',
|
||||
downgrade: '降級',
|
||||
not_eligible: '您不符合降級資格',
|
||||
not_eligible_description: '在降級到 <name/> 之前,請確保符合以下條件。',
|
||||
a_maximum_of: '最大數量<item/>',
|
||||
help_tip: '需要協助降級嗎?<a>聯繫我們</a>。',
|
||||
},
|
||||
not_eligible_modal: {
|
||||
downgrade_title: '您不符合降級條件',
|
||||
downgrade_description: '降級到<name/>前,請確保符合以下條件。',
|
||||
downgrade_help_tip: '需要降級幫助?<a>聯絡我們</a>。',
|
||||
upgrade_title: '您不符合升級條件',
|
||||
upgrade_description:
|
||||
'您目前使用的內容超過了<name />允許的範圍。在考慮升級到<name/>之前,請確保符合以下條件。',
|
||||
upgrade_help_tip: '需要升級幫助?<a>聯絡我們</a>。',
|
||||
a_maximum_of: '最多<item/>',
|
||||
},
|
||||
upgrade_success: '已成功升級到 <name/>',
|
||||
downgrade_success: '已成功降級到 <name/>',
|
||||
|
|
Loading…
Add table
Reference in a new issue