From f33ef7067f0a0e79ecc496e1a2d58f4faa7d29a1 Mon Sep 17 00:00:00 2001 From: Xiao Yijun Date: Mon, 25 Dec 2023 14:49:11 +0800 Subject: [PATCH] refactor(console): update featured plan quota list (#5147) --- .../FeaturedQuotaItem/index.module.scss | 14 ++++ .../FeaturedQuotaItem/index.tsx | 45 ++++++++++++ .../FeaturedPlanQuotaList/index.module.scss | 6 ++ .../FeaturedPlanQuotaList/index.tsx | 69 +++++++++++++++++++ .../PlanCardItem/index.tsx | 12 +--- .../PlanQuotaList/QuotaItem/index.module.scss | 34 --------- .../PlanQuotaList/QuotaItem/index.tsx | 65 ----------------- .../QuotaListItem/QuotaItemPhrase.tsx | 46 +++++++++++++ .../QuotaListItem/index.module.scss | 19 +++++ .../PlanQuotaList/QuotaListItem/index.tsx | 36 ++++++++++ .../PlanQuotaList/index.module.scss | 2 +- .../src/components/PlanQuotaList/index.tsx | 60 +++++----------- .../console/src/consts/quota-item-phrases.ts | 9 +++ .../DiffQuotaItem/index.module.scss | 12 ++++ .../PlanQuotaDiffCard/DiffQuotaItem/index.tsx | 37 ++++++++++ .../PlanQuotaDiffCard/index.tsx | 36 +++++++--- .../DowngradeConfirmModalContent/index.tsx | 6 +- .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 1 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + .../admin-console/subscription/quota-item.ts | 2 + 32 files changed, 374 insertions(+), 163 deletions(-) create mode 100644 packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/FeaturedQuotaItem/index.module.scss create mode 100644 packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/FeaturedQuotaItem/index.tsx create mode 100644 packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/index.module.scss create mode 100644 packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/index.tsx delete mode 100644 packages/console/src/components/PlanQuotaList/QuotaItem/index.module.scss delete mode 100644 packages/console/src/components/PlanQuotaList/QuotaItem/index.tsx create mode 100644 packages/console/src/components/PlanQuotaList/QuotaListItem/QuotaItemPhrase.tsx create mode 100644 packages/console/src/components/PlanQuotaList/QuotaListItem/index.module.scss create mode 100644 packages/console/src/components/PlanQuotaList/QuotaListItem/index.tsx create mode 100644 packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/DiffQuotaItem/index.module.scss create mode 100644 packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/DiffQuotaItem/index.tsx diff --git a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/FeaturedQuotaItem/index.module.scss b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/FeaturedQuotaItem/index.module.scss new file mode 100644 index 000000000..c83442efa --- /dev/null +++ b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/FeaturedQuotaItem/index.module.scss @@ -0,0 +1,14 @@ +@use '@/scss/underscore' as _; + +.icon { + width: 16px; + height: 16px; + + &.notCapable { + color: var(--color-error); + } + + &.capable { + color: var(--color-on-success-container); + } +} diff --git a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/FeaturedQuotaItem/index.tsx b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/FeaturedQuotaItem/index.tsx new file mode 100644 index 000000000..c55fbb63f --- /dev/null +++ b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/FeaturedQuotaItem/index.tsx @@ -0,0 +1,45 @@ +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 ( + + } + suffix={cond( + isComingSoonTagVisible && ( + + + + ) + )} + /> + ); +} + +export default FeaturedQuotaItem; diff --git a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/index.module.scss b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/index.module.scss new file mode 100644 index 000000000..0d8253f4c --- /dev/null +++ b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/index.module.scss @@ -0,0 +1,6 @@ +@use '@/scss/underscore' as _; + +.featuredQuotaList { + flex: 1; + padding-bottom: _.unit(8); +} diff --git a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/index.tsx b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/index.tsx new file mode 100644 index 000000000..a4b7e7834 --- /dev/null +++ b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanQuotaList/index.tsx @@ -0,0 +1,69 @@ +import { ReservedPlanId } from '@logto/schemas'; +import { condArray } from '@silverhand/essentials'; +import { useMemo } from 'react'; + +import PlanQuotaList from '@/components/PlanQuotaList'; +import { isDevFeaturesEnabled } from '@/consts/env'; +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([ + 'mauLimit', + 'machineToMachineLimit', + // Todo @xiaoyijun [Pricing] Remove feature flag + ...condArray(!isDevFeaturesEnabled && 'standardConnectorsLimit'), + '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 ( + ( + + )} + /> + ); +} + +export default FeaturedPlanQuotaList; diff --git a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/index.tsx b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/index.tsx index e453b88cc..ec096e950 100644 --- a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/index.tsx +++ b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/index.tsx @@ -6,10 +6,8 @@ import { Trans, useTranslation } from 'react-i18next'; import ArrowRight from '@/assets/icons/arrow-right.svg'; import PlanDescription from '@/components/PlanDescription'; import PlanName from '@/components/PlanName'; -import PlanQuotaList from '@/components/PlanQuotaList'; import { pricingLink } from '@/consts'; import { isDevFeaturesEnabled } from '@/consts/env'; -import { comingSoonQuotaKeys } from '@/consts/plan-quotas'; import { TenantsContext } from '@/contexts/TenantsProvider'; import Button from '@/ds-components/Button'; import DangerousRaw from '@/ds-components/DangerousRaw'; @@ -17,12 +15,12 @@ import DynamicT from '@/ds-components/DynamicT'; import TextLink from '@/ds-components/TextLink'; import { type SubscriptionPlanQuota, type SubscriptionPlan } from '@/types/subscriptions'; +import FeaturedPlanQuotaList from './FeaturedPlanQuotaList'; import * as styles from './index.module.scss'; const featuredQuotaKeys: Array = [ 'mauLimit', 'machineToMachineLimit', - 'standardConnectorsLimit', 'rolesLimit', 'scopesPerRoleLimit', 'mfaEnabled', @@ -90,13 +88,7 @@ function PlanCardItem({ plan, onSelect }: Props) {
- + {isFreePlan && isFreeTenantExceeded && (
{t('free_tenants_limit', { count: maxFreeTenantLimit })} diff --git a/packages/console/src/components/PlanQuotaList/QuotaItem/index.module.scss b/packages/console/src/components/PlanQuotaList/QuotaItem/index.module.scss deleted file mode 100644 index 243f1f652..000000000 --- a/packages/console/src/components/PlanQuotaList/QuotaItem/index.module.scss +++ /dev/null @@ -1,34 +0,0 @@ -@use '@/scss/underscore' as _; - -.item { - margin-left: _.unit(4); - font: var(--font-body-2); - - &.withIcon { - list-style-type: none; - margin-left: unset; - } - - .itemContent { - display: flex; - align-items: center; - gap: _.unit(2); - - .icon { - width: 16px; - height: 16px; - - &.notCapable { - color: var(--color-error); - } - - &.capable { - color: var(--color-on-success-container); - } - } - - .lineThrough { - text-decoration: line-through; - } - } -} diff --git a/packages/console/src/components/PlanQuotaList/QuotaItem/index.tsx b/packages/console/src/components/PlanQuotaList/QuotaItem/index.tsx deleted file mode 100644 index 940a928a7..000000000 --- a/packages/console/src/components/PlanQuotaList/QuotaItem/index.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { conditional } from '@silverhand/essentials'; -import classNames from 'classnames'; -import { useTranslation } from 'react-i18next'; - -import DescendArrow from '@/assets/icons/descend-arrow.svg'; -import Failed from '@/assets/icons/failed.svg'; -import Success from '@/assets/icons/success.svg'; -import { - quotaItemUnlimitedPhrasesMap, - quotaItemPhrasesMap, - quotaItemLimitedPhrasesMap, -} from '@/consts/quota-item-phrases'; -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 = { - hasIcon?: boolean; - quotaKey: keyof SubscriptionPlanQuota; - quotaValue: SubscriptionPlanQuota[keyof SubscriptionPlanQuota]; - isDiffItem?: boolean; - isComingSoonTagVisible?: boolean; -}; - -function QuotaItem({ hasIcon, quotaKey, quotaValue, isDiffItem, isComingSoonTagVisible }: Props) { - const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.subscription.quota_item' }); - const isUnlimited = quotaValue === null; - const isNotCapable = quotaValue === 0 || quotaValue === false; - const isLimited = Boolean(quotaValue); - - const Icon = isNotCapable ? Failed : isDiffItem ? DescendArrow : Success; - - return ( -
  • - - {hasIcon && ( - - )} - - {isUnlimited && <>{t(quotaItemUnlimitedPhrasesMap[quotaKey])}} - {isNotCapable && <>{t(quotaItemPhrasesMap[quotaKey])}} - {isLimited && ( - <> - {t( - quotaItemLimitedPhrasesMap[quotaKey], - conditional(typeof quotaValue === 'number' && { count: quotaValue }) ?? {} - )} - - )} - - {isComingSoonTagVisible && ( - - - - )} - -
  • - ); -} - -export default QuotaItem; diff --git a/packages/console/src/components/PlanQuotaList/QuotaListItem/QuotaItemPhrase.tsx b/packages/console/src/components/PlanQuotaList/QuotaListItem/QuotaItemPhrase.tsx new file mode 100644 index 000000000..d51024c72 --- /dev/null +++ b/packages/console/src/components/PlanQuotaList/QuotaListItem/QuotaItemPhrase.tsx @@ -0,0 +1,46 @@ +import { cond } from '@silverhand/essentials'; + +import { + quotaItemUnlimitedPhrasesMap, + quotaItemPhrasesMap, + quotaItemLimitedPhrasesMap, + quotaItemAddOnPhrasesMap, +} from '@/consts/quota-item-phrases'; +import DynamicT from '@/ds-components/DynamicT'; +import { type SubscriptionPlanQuota } from '@/types/subscriptions'; + +const quotaItemPhraseKeyPrefix = 'subscription.quota_item'; + +type Props = { + quotaKey: keyof SubscriptionPlanQuota; + quotaValue: SubscriptionPlanQuota[keyof SubscriptionPlanQuota]; + isAddOn?: boolean; +}; + +function QuotaItemPhrase({ quotaKey, quotaValue, isAddOn = false }: Props) { + const isUnlimited = quotaValue === null; + const isNotCapable = quotaValue === 0 || quotaValue === false; + const isLimited = Boolean(quotaValue); + + const limitedPhraseKey = + cond(isAddOn && quotaItemAddOnPhrasesMap[quotaKey]) ?? quotaItemLimitedPhrasesMap[quotaKey]; + + const phraseKey = + cond(isUnlimited && quotaItemUnlimitedPhrasesMap[quotaKey]) ?? + cond(isNotCapable && quotaItemPhrasesMap[quotaKey]) ?? + cond(isLimited && limitedPhraseKey); + + if (!phraseKey) { + // Should not happen + return null; + } + + return ( + + ); +} + +export default QuotaItemPhrase; diff --git a/packages/console/src/components/PlanQuotaList/QuotaListItem/index.module.scss b/packages/console/src/components/PlanQuotaList/QuotaListItem/index.module.scss new file mode 100644 index 000000000..674629374 --- /dev/null +++ b/packages/console/src/components/PlanQuotaList/QuotaListItem/index.module.scss @@ -0,0 +1,19 @@ +@use '@/scss/underscore' as _; + +.quotaListItem { + font: var(--font-body-2); + // Add a margin to the left for the list item marker + margin-left: _.unit(4); + + .content { + display: flex; + align-items: center; + gap: _.unit(2); + } + + &.withIcon { + list-style-type: none; + // Unset a margin to the left for the list item marker + margin-left: unset; + } +} diff --git a/packages/console/src/components/PlanQuotaList/QuotaListItem/index.tsx b/packages/console/src/components/PlanQuotaList/QuotaListItem/index.tsx new file mode 100644 index 000000000..36bc96aa0 --- /dev/null +++ b/packages/console/src/components/PlanQuotaList/QuotaListItem/index.tsx @@ -0,0 +1,36 @@ +import classNames from 'classnames'; +import { type ReactNode } from 'react'; + +import { type SubscriptionPlanQuota } from '@/types/subscriptions'; + +import QuotaItemPhrase from './QuotaItemPhrase'; +import * as styles from './index.module.scss'; + +type Props = { + quotaKey: keyof SubscriptionPlanQuota; + quotaValue: SubscriptionPlanQuota[keyof SubscriptionPlanQuota]; + icon?: ReactNode; + suffix?: ReactNode; + isAddOn?: boolean; + phraseClassName?: string; +}; + +function QuotaListItem({ icon, suffix, phraseClassName, ...rest }: Props) { + return ( +
  • + {/** + * Add a `span` as a wrapper to apply the flex layout to the content. + * If we apply the flex layout to the `li` directly, the `li` circle bullet will disappear. + */} + + {icon} + + + + {suffix} + +
  • + ); +} + +export default QuotaListItem; diff --git a/packages/console/src/components/PlanQuotaList/index.module.scss b/packages/console/src/components/PlanQuotaList/index.module.scss index 1695e5396..b54b8d3bf 100644 --- a/packages/console/src/components/PlanQuotaList/index.module.scss +++ b/packages/console/src/components/PlanQuotaList/index.module.scss @@ -1,6 +1,6 @@ @use '@/scss/underscore' as _; -.list { +.planQuotaList { margin-block: 0; padding-inline: 0; diff --git a/packages/console/src/components/PlanQuotaList/index.tsx b/packages/console/src/components/PlanQuotaList/index.tsx index 98562e8fc..5672db829 100644 --- a/packages/console/src/components/PlanQuotaList/index.tsx +++ b/packages/console/src/components/PlanQuotaList/index.tsx @@ -1,5 +1,5 @@ import classNames from 'classnames'; -import { useMemo } from 'react'; +import { useMemo, type ReactNode } from 'react'; import { planQuotaItemOrder } from '@/consts/plan-quotas'; import { @@ -8,55 +8,31 @@ import { } from '@/types/subscriptions'; import { sortBy } from '@/utils/sort'; -import QuotaItem from './QuotaItem'; import * as styles from './index.module.scss'; type Props = { - quota: Partial; - featuredQuotaKeys?: Array; - comingSoonQuotaKeys?: Array; + entries: SubscriptionPlanQuotaEntries; + itemRenderer: ( + quotaKey: keyof SubscriptionPlanQuota, + quotaValue: SubscriptionPlanQuota[keyof SubscriptionPlanQuota] + ) => ReactNode; className?: string; - isDiff?: boolean; - hasIcon?: boolean; }; -function PlanQuotaList({ - quota, - featuredQuotaKeys, - comingSoonQuotaKeys, - isDiff, - hasIcon, - className, -}: Props) { - const items = useMemo(() => { - // eslint-disable-next-line no-restricted-syntax - const entries = Object.entries(quota) as SubscriptionPlanQuotaEntries; - - const featuredEntries = featuredQuotaKeys - ? entries.filter(([key]) => featuredQuotaKeys.includes(key)) - : entries; - - return featuredEntries - .slice() - .sort(([preQuotaKey], [nextQuotaKey]) => - sortBy(planQuotaItemOrder)(preQuotaKey, nextQuotaKey) - ); - }, [quota, featuredQuotaKeys]); +function PlanQuotaList({ entries, itemRenderer, className }: Props) { + const sortedEntries = useMemo( + () => + entries + .slice() + .sort(([preQuotaKey], [nextQuotaKey]) => + sortBy(planQuotaItemOrder)(preQuotaKey, nextQuotaKey) + ), + [entries] + ); return ( -
      - {items.map(([quotaKey, quotaValue]) => ( - - ))} +
        + {sortedEntries.map(([quotaKey, quotaValue]) => itemRenderer(quotaKey, quotaValue))}
      ); } diff --git a/packages/console/src/consts/quota-item-phrases.ts b/packages/console/src/consts/quota-item-phrases.ts index b81d04635..6967e8a40 100644 --- a/packages/console/src/consts/quota-item-phrases.ts +++ b/packages/console/src/consts/quota-item-phrases.ts @@ -105,3 +105,12 @@ export const quotaItemNotEligiblePhrasesMap: Record< organizationsEnabled: 'organizations_enabled.not_eligible', ssoEnabled: 'sso_enabled.not_eligible', }; + +export const quotaItemAddOnPhrasesMap: Partial< + Record< + keyof SubscriptionPlanQuota, + TFuncKey<'translation', 'admin_console.subscription.quota_item'> + > +> = { + machineToMachineLimit: 'machine_to_machine_limit.add_on', +}; diff --git a/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/DiffQuotaItem/index.module.scss b/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/DiffQuotaItem/index.module.scss new file mode 100644 index 000000000..a5f8a27c0 --- /dev/null +++ b/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/DiffQuotaItem/index.module.scss @@ -0,0 +1,12 @@ +.icon { + width: 16px; + height: 16px; + + &.notCapable { + color: var(--color-error); + } +} + +.lineThrough { + text-decoration: line-through; +} diff --git a/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/DiffQuotaItem/index.tsx b/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/DiffQuotaItem/index.tsx new file mode 100644 index 000000000..508ad9a65 --- /dev/null +++ b/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/DiffQuotaItem/index.tsx @@ -0,0 +1,37 @@ +import { cond } from '@silverhand/essentials'; +import classNames from 'classnames'; + +import DescendArrow from '@/assets/icons/descend-arrow.svg'; +import Failed from '@/assets/icons/failed.svg'; +import QuotaListItem from '@/components/PlanQuotaList/QuotaListItem'; +import { type SubscriptionPlanQuota } from '@/types/subscriptions'; + +import * as styles from './index.module.scss'; + +type Props = { + quotaKey: keyof SubscriptionPlanQuota; + quotaValue: SubscriptionPlanQuota[keyof SubscriptionPlanQuota]; + isForDowngradeTargetPlan?: boolean; +}; + +function DiffQuotaItem({ quotaKey, quotaValue, isForDowngradeTargetPlan }: Props) { + const isNotCapable = quotaValue === 0 || quotaValue === false; + const DowngradeStatusIcon = isNotCapable ? Failed : DescendArrow; + + return ( + + ) + )} + phraseClassName={cond(isNotCapable && styles.lineThrough)} + /> + ); +} + +export default DiffQuotaItem; diff --git a/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/index.tsx b/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/index.tsx index 6b20e404a..f7dac01e7 100644 --- a/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/index.tsx +++ b/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/index.tsx @@ -1,22 +1,23 @@ -import { Trans, useTranslation } from 'react-i18next'; +import { Trans } from 'react-i18next'; import PlanName from '@/components/PlanName'; import PlanQuotaList from '@/components/PlanQuotaList'; -import { type SubscriptionPlanQuota } from '@/types/subscriptions'; +import DynamicT from '@/ds-components/DynamicT'; +import { + type SubscriptionPlanQuotaEntries, + type SubscriptionPlanQuota, +} from '@/types/subscriptions'; +import DiffQuotaItem from './DiffQuotaItem'; import * as styles from './index.module.scss'; type Props = { planName: string; quotaDiff: Partial; - isTarget?: boolean; + isDowngradeTargetPlan?: boolean; }; -function PlanQuotaDiffCard({ planName, quotaDiff, isTarget = false }: Props) { - const { t } = useTranslation(undefined, { - keyPrefix: 'admin_console.subscription.downgrade_modal', - }); - +function PlanQuotaDiffCard({ planName, quotaDiff, isDowngradeTargetPlan = false }: Props) { return (
      @@ -25,10 +26,25 @@ function PlanQuotaDiffCard({ planName, quotaDiff, isTarget = false }: Props) { name: , }} > - {t(isTarget ? 'after' : 'before')} +
      - + ( + + )} + />
      ); } diff --git a/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/index.tsx b/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/index.tsx index 1dd925855..57468f709 100644 --- a/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/index.tsx +++ b/packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/index.tsx @@ -57,7 +57,11 @@ function DowngradeConfirmModalContent({ currentPlan, targetPlan }: Props) {
    - +
    ); diff --git a/packages/phrases/src/locales/de/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/de/translation/admin-console/subscription/quota-item.ts index 802c649ef..78f105579 100644 --- a/packages/phrases/src/locales/de/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/de/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} Maschine-zu-Maschine-Apps', unlimited: 'Unbegrenzte Maschine-zu-Maschine-Apps', not_eligible: 'Entferne deine Maschine-zu-Maschine-Apps', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'API-Ressourcen', diff --git a/packages/phrases/src/locales/en/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/en/translation/admin-console/subscription/quota-item.ts index 860daf002..7f57e5bcb 100644 --- a/packages/phrases/src/locales/en/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/en/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,7 @@ const quota_item = { limited_other: '{{count, number}} machine to machine apps', unlimited: 'Unlimited machine to machine apps', not_eligible: 'Remove your machine to machine apps', + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'API resources', diff --git a/packages/phrases/src/locales/es/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/es/translation/admin-console/subscription/quota-item.ts index 94873be46..a0b16bbc5 100644 --- a/packages/phrases/src/locales/es/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/es/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} aplicaciones de dispositivo a dispositivo', unlimited: 'Aplicaciones de dispositivo a dispositivo ilimitadas', not_eligible: 'Elimine sus aplicaciones de dispositivo a dispositivo', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'Recursos de API', diff --git a/packages/phrases/src/locales/fr/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/fr/translation/admin-console/subscription/quota-item.ts index c35c5ebbf..419e98709 100644 --- a/packages/phrases/src/locales/fr/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/fr/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} applications machine à machine', unlimited: 'Illimité applications machine à machine', not_eligible: 'Supprimez vos applications machine à machine', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'Ressources API', diff --git a/packages/phrases/src/locales/it/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/it/translation/admin-console/subscription/quota-item.ts index cf70565b9..af9bdd164 100644 --- a/packages/phrases/src/locales/it/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/it/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} applicazioni Machine-to-Machine', unlimited: 'Applicazioni Machine-to-Machine illimitate', not_eligible: 'Rimuovi le tue applicazioni Machine-to-Machine', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'Risorse API', diff --git a/packages/phrases/src/locales/ja/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/ja/translation/admin-console/subscription/quota-item.ts index 019875f54..6a4d759e4 100644 --- a/packages/phrases/src/locales/ja/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/ja/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} マシン間アプリケーション', unlimited: '無制限のマシン間アプリケーション', not_eligible: 'マシン間アプリケーションを削除してください', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'APIリソース', diff --git a/packages/phrases/src/locales/ko/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/ko/translation/admin-console/subscription/quota-item.ts index 187483bb7..b25a325e1 100644 --- a/packages/phrases/src/locales/ko/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/ko/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} 기계 간 앱', unlimited: '제한 없는 기계 간 앱', not_eligible: '기계 간 앱을 제거하십시오', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'API 리소스', diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/subscription/quota-item.ts index d36335ee8..462b5e996 100644 --- a/packages/phrases/src/locales/pl-pl/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} aplikacje machine to machine', unlimited: 'Nieograniczona liczba aplikacji machine to machine', not_eligible: 'Usuń swoje aplikacje machine to machine', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'Zasoby API', diff --git a/packages/phrases/src/locales/pt-br/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/pt-br/translation/admin-console/subscription/quota-item.ts index 759fd9c98..17d64a47e 100644 --- a/packages/phrases/src/locales/pt-br/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/pt-br/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} aplicações de máquina a máquina', unlimited: 'Aplicações de máquina a máquina ilimitadas', not_eligible: 'Remova suas aplicações de máquina a máquina', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'Recursos da API', diff --git a/packages/phrases/src/locales/pt-pt/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/pt-pt/translation/admin-console/subscription/quota-item.ts index 12c7b1a65..d2455304b 100644 --- a/packages/phrases/src/locales/pt-pt/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/pt-pt/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} aplicações de máquina para máquina', unlimited: 'Aplicações de máquina para máquina ilimitadas', not_eligible: 'Remover as tuas aplicações de máquina para máquina', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'Recursos de API', diff --git a/packages/phrases/src/locales/ru/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/ru/translation/admin-console/subscription/quota-item.ts index 69a640c79..a4cf139a2 100644 --- a/packages/phrases/src/locales/ru/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/ru/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} приложения для машин ко машине', unlimited: 'Неограниченное количество приложений для машин ко машине', not_eligible: 'Удалите свои приложения для машин ко машине', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'API ресурсы', diff --git a/packages/phrases/src/locales/tr-tr/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/tr-tr/translation/admin-console/subscription/quota-item.ts index 43f9ebaac..5bf96769e 100644 --- a/packages/phrases/src/locales/tr-tr/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/tr-tr/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} makineye makine uygulamalar', unlimited: 'Sınırsız makineye makine uygulamalar', not_eligible: 'Makineye makine uygulamalarınızı kaldırın', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'API kaynakları', diff --git a/packages/phrases/src/locales/zh-cn/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/zh-cn/translation/admin-console/subscription/quota-item.ts index 027a3ef70..e536d307e 100644 --- a/packages/phrases/src/locales/zh-cn/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/zh-cn/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} 个机器到机器应用', unlimited: '无限制机器到机器应用', not_eligible: '移除你的机器到机器应用', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'API 资源', diff --git a/packages/phrases/src/locales/zh-hk/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/zh-hk/translation/admin-console/subscription/quota-item.ts index 14b9e9d88..2afdebf60 100644 --- a/packages/phrases/src/locales/zh-hk/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/zh-hk/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} 個機器對機器應用程式', unlimited: '無限機器對機器應用程式', not_eligible: '刪除您的機器對機器應用程式', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'API 資源', diff --git a/packages/phrases/src/locales/zh-tw/translation/admin-console/subscription/quota-item.ts b/packages/phrases/src/locales/zh-tw/translation/admin-console/subscription/quota-item.ts index 8fe3cb1d4..af30b9e96 100644 --- a/packages/phrases/src/locales/zh-tw/translation/admin-console/subscription/quota-item.ts +++ b/packages/phrases/src/locales/zh-tw/translation/admin-console/subscription/quota-item.ts @@ -32,6 +32,8 @@ const quota_item = { limited_other: '{{count, number}} 機器對機器應用程式', unlimited: '不限機器對機器應用程式數', not_eligible: '移除你的機器對機器應用程式', + /** UNTRANSLATED */ + add_on: 'Additional machine-to-machine apps', }, resources_limit: { name: 'API 資源',