0
Fork 0
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:
Xiao Yijun 2023-07-24 18:22:52 +08:00 committed by GitHub
parent 28634c5800
commit 36b5958935
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 263 additions and 147 deletions

View file

@ -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);
}
}}

View file

@ -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>

View file

@ -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;

View file

@ -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;
}
};

View file

@ -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',

View file

@ -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:
'Youre 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/>',

View file

@ -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/>',

View file

@ -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/>',

View file

@ -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/>',

View file

@ -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/>にダウングレードされました',

View file

@ -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/>으로 다운그레이드되었습니다.',

View file

@ -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/>',

View file

@ -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/>',

View file

@ -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/>',

View file

@ -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/>',

View file

@ -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/>',

View file

@ -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/>',

View file

@ -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/>',

View file

@ -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/>',