Skip to content

Commit

Permalink
fix(console): add add-on display issues and refactor component PlanNa…
Browse files Browse the repository at this point in the history
…me (#6471)
  • Loading branch information
darcyYe authored Aug 20, 2024
1 parent 1c6b932 commit e0623df
Show file tree
Hide file tree
Showing 32 changed files with 145 additions and 252 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Trans, useTranslation } from 'react-i18next';

import AddOnNoticeFooter from '@/components/AddOnNoticeFooter';
import ContactUsPhraseLink from '@/components/ContactUsPhraseLink';
import PlanName from '@/components/PlanName';
import QuotaGuardFooter from '@/components/QuotaGuardFooter';
import SkuName from '@/components/SkuName';
import { addOnPricingExplanationLink } from '@/consts/external-links';
import { machineToMachineAddOnUnitPrice } from '@/consts/subscriptions';
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
Expand All @@ -25,9 +25,9 @@ type Props = {

function Footer({ selectedType, isLoading, onClickCreate, isThirdParty }: Props) {
const {
currentPlan,
currentSku,
currentSubscription: { isAddOnAvailable },
currentSubscription: { planId, isAddOnAvailable },
currentSubscriptionQuota,
} = useContext(SubscriptionDataContext);
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.upsell' });
const {
Expand All @@ -41,8 +41,6 @@ function Footer({ selectedType, isLoading, onClickCreate, isThirdParty }: Props)
} = useUserPreferences();

if (selectedType) {
const { id: planId, name: planName, quota } = currentPlan;

if (
selectedType === ApplicationType.MachineToMachine &&
isAddOnAvailable &&
Expand Down Expand Up @@ -113,10 +111,10 @@ function Footer({ selectedType, isLoading, onClickCreate, isThirdParty }: Props)
<Trans
components={{
a: <ContactUsPhraseLink />,
planName: <PlanName skuId={currentSku.id} name={planName} />,
planName: <SkuName skuId={currentSku.id} />,
}}
>
{t('paywall.applications', { count: quota.applicationsLimit ?? 0 })}
{t('paywall.applications', { count: currentSubscriptionQuota.applicationsLimit ?? 0 })}
</Trans>
</QuotaGuardFooter>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { useContext } from 'react';
import { Trans, useTranslation } from 'react-i18next';

import ContactUsPhraseLink from '@/components/ContactUsPhraseLink';
import PlanName from '@/components/PlanName';
import QuotaGuardFooter from '@/components/QuotaGuardFooter';
import SkuName from '@/components/SkuName';
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
import Button from '@/ds-components/Button';
import { type ConnectorGroup } from '@/types/connector';
Expand All @@ -24,7 +24,7 @@ function Footer({
onClickCreateButton,
}: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.upsell.paywall' });
const { currentPlan, currentSku, currentSubscriptionUsage, currentSubscriptionQuota } =
const { currentSku, currentSubscriptionUsage, currentSubscriptionQuota } =
useContext(SubscriptionDataContext);

const isSocialConnectorsReachLimit = hasReachedSubscriptionQuotaLimit({
Expand All @@ -33,25 +33,26 @@ function Footer({
quota: currentSubscriptionQuota,
});

if (isCreatingSocialConnector && selectedConnectorGroup) {
const { name: planName } = currentPlan;

if (isSocialConnectorsReachLimit && !selectedConnectorGroup.isStandard) {
return (
<QuotaGuardFooter>
<Trans
components={{
a: <ContactUsPhraseLink />,
planName: <PlanName skuId={currentSku.id} name={planName} />,
}}
>
{t('social_connectors', {
count: currentSubscriptionQuota.socialConnectorsLimit ?? 0,
})}
</Trans>
</QuotaGuardFooter>
);
}
if (
isCreatingSocialConnector &&
selectedConnectorGroup &&
isSocialConnectorsReachLimit &&
!selectedConnectorGroup.isStandard
) {
return (
<QuotaGuardFooter>
<Trans
components={{
a: <ContactUsPhraseLink />,
planName: <SkuName skuId={currentSku.id} />,
}}
>
{t('social_connectors', {
count: currentSubscriptionQuota.socialConnectorsLimit ?? 0,
})}
</Trans>
</QuotaGuardFooter>
);
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Trans, useTranslation } from 'react-i18next';
import ArrowRight from '@/assets/icons/arrow-right.svg?react';
import { type LogtoSkuResponse } from '@/cloud/types/router';
import PlanDescription from '@/components/PlanDescription';
import PlanName from '@/components/PlanName';
import SkuName from '@/components/SkuName';
import { pricingLink } from '@/consts';
import { TenantsContext } from '@/contexts/TenantsProvider';
import Button, { type Props as ButtonProps } from '@/ds-components/Button';
Expand Down Expand Up @@ -42,7 +42,7 @@ function SkuCardItem({ sku, onSelect, buttonProps }: Props) {
<div className={styles.container}>
<div className={styles.planInfo}>
<div className={styles.title}>
<PlanName skuId={skuId} name={skuId} />
<SkuName skuId={skuId} />
</div>
<div className={styles.priceInfo}>
<div className={styles.priceLabel}>{t('base_price')}</div>
Expand Down Expand Up @@ -77,9 +77,7 @@ function SkuCardItem({ sku, onSelect, buttonProps }: Props) {
<Button
title={
<DangerousRaw>
<Trans components={{ name: <PlanName skuId={skuId} name={skuId} /> }}>
{t('select_plan')}
</Trans>
<Trans components={{ name: <SkuName skuId={skuId} /> }}>{t('select_plan')}</Trans>
</DangerousRaw>
}
type={isFreeSku ? 'outline' : 'primary'}
Expand Down
4 changes: 2 additions & 2 deletions packages/console/src/components/Guide/GuideCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function GuideCard({ data, onClick, hasBorder, hasButton }: Props) {
} = data;

const buttonText = target === 'API' ? 'guide.get_started' : 'guide.start_building';
const { currentPlan } = useContext(SubscriptionDataContext);
const { currentSubscriptionQuota } = useContext(SubscriptionDataContext);
const theme = useTheme();

const showPaywallTag = isCloud && isThirdParty;
Expand Down Expand Up @@ -73,7 +73,7 @@ function GuideCard({ data, onClick, hasBorder, hasButton }: Props) {
<div className={styles.tagWrapper}>
{showPaywallTag && (
<FeatureTag
isVisible={currentPlan.quota.thirdPartyApplicationsLimit === 0}
isVisible={currentSubscriptionQuota.thirdPartyApplicationsLimit === 0}
plan={ReservedPlanId.Pro}
/>
)}
Expand Down
8 changes: 3 additions & 5 deletions packages/console/src/components/MauExceededModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import ModalLayout from '@/ds-components/ModalLayout';
import useTenantPathname from '@/hooks/use-tenant-pathname';
import modalStyles from '@/scss/modal.module.scss';

import PlanName from '../PlanName';
import SkuName from '../SkuName';

import styles from './index.module.scss';

function MauExceededModal() {
const { currentPlan, currentSubscription, currentSku } = useContext(SubscriptionDataContext);
const { currentSku } = useContext(SubscriptionDataContext);
const { currentTenant } = useContext(TenantsContext);

const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
Expand All @@ -35,8 +35,6 @@ function MauExceededModal() {
return null;
}

const { name: planName } = currentPlan;

const isMauExceeded =
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain, prettier/prettier
cond(currentTenant && currentTenant.quota.mauLimit !== null &&
Expand Down Expand Up @@ -77,7 +75,7 @@ function MauExceededModal() {
<InlineNotification severity="error">
<Trans
components={{
planName: <PlanName skuId={currentSku.id} name={planName} />,
planName: <SkuName skuId={currentSku.id} />,
}}
>
{t('upsell.mau_exceeded_modal.notification')}
Expand Down
49 changes: 0 additions & 49 deletions packages/console/src/components/PlanName/index.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
max-width: calc((100% - _.unit(2) * 2) / 3);
max-height: 112px;

&.freeUser {
&.periodicUsage {
flex: 0 0 calc((100% - _.unit(2)) / 2);
max-width: calc((100% - _.unit(2)) / 2);
}
Expand Down
12 changes: 6 additions & 6 deletions packages/console/src/components/PlanUsage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,15 @@ function PlanUsage({ periodicUsage: rawPeriodicUsage }: Props) {
return null;
}

const onlyShowPeriodicUsage =
planId === ReservedPlanId.Free || (!isAddOnAvailable && planId === ReservedPlanId.Pro);

const usages: PlanUsageCardProps[] = usageKeys
// Show all usages for Pro plan and only show MAU and token usage for Free plan
.filter(
(key) =>
isAddOnAvailable ??
(planId === ReservedPlanId.Free && (key === 'mauLimit' || key === 'tokenLimit'))
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
isAddOnAvailable || (onlyShowPeriodicUsage && (key === 'mauLimit' || key === 'tokenLimit'))
)
.map((key) => ({
usage:
Expand Down Expand Up @@ -89,10 +92,7 @@ function PlanUsage({ periodicUsage: rawPeriodicUsage }: Props) {
<PlanUsageCard
// eslint-disable-next-line react/no-array-index-key
key={index}
className={classNames(
styles.cardItem,
planId === ReservedPlanId.Free && styles.freeUser
)}
className={classNames(styles.cardItem, onlyShowPeriodicUsage && styles.periodicUsage)}
{...props}
/>
))}
Expand Down
32 changes: 32 additions & 0 deletions packages/console/src/components/SkuName/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { type TFuncKey } from 'i18next';
import { useTranslation } from 'react-i18next';

import { ReservedSkuId } from '@/types/subscriptions';

const registeredSkuIdNamePhraseMap: Record<
string,
TFuncKey<'translation', 'admin_console.subscription'> | undefined
> = {
quotaKey: undefined,
[ReservedSkuId.Free]: 'free_plan',
[ReservedSkuId.Pro]: 'pro_plan',
[ReservedSkuId.Enterprise]: 'enterprise',
};

type Props = {
readonly skuId: string;
};

function SkuName({ skuId }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.subscription' });
const skuNamePhrase = registeredSkuIdNamePhraseMap[skuId];

/**
* Note: fallback to the plan name if the phrase is not registered.
*/
const skuName = skuNamePhrase ? String(t(skuNamePhrase)) : skuId;

return <span>{skuName}</span>;
}

export default SkuName;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useContext, useMemo } from 'react';

import Tick from '@/assets/icons/tick.svg?react';
import { type TenantResponse } from '@/cloud/types/router';
import PlanName from '@/components/PlanName';
import SkuName from '@/components/SkuName';
import TenantEnvTag from '@/components/TenantEnvTag';
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
import { DropdownItem } from '@/ds-components/Dropdown';
Expand All @@ -26,7 +26,7 @@ function TenantDropdownItem({ tenantData, isSelected, onClick }: Props) {
subscription: { planId },
} = tenantData;

const { currentPlan, subscriptionPlans } = useContext(SubscriptionDataContext);
const { subscriptionPlans } = useContext(SubscriptionDataContext);
const tenantSubscriptionPlan = useMemo(
() => subscriptionPlans.find((plan) => plan.id === planId),
[subscriptionPlans, planId]
Expand All @@ -48,7 +48,7 @@ function TenantDropdownItem({ tenantData, isSelected, onClick }: Props) {
{tag === TenantTag.Development ? (
<DynamicT forKey="subscription.no_subscription" />
) : (
<PlanName skuId={planId} name={currentPlan.name} />
<SkuName skuId={planId} />
)}
</div>
</div>
Expand Down
8 changes: 0 additions & 8 deletions packages/console/src/consts/plan-quotas.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ReservedPlanId } from '@logto/schemas';

import { type LogtoSkuQuota } from '@/types/skus';
import { type SubscriptionPlanQuota } from '@/types/subscriptions';

/**
* Manually add this support quota item to the plan since it will be compared in the downgrade plan notification modal.
Expand Down Expand Up @@ -37,11 +36,4 @@ export const skuQuotaItemOrder: Array<keyof LogtoSkuQuota> = [
'ticketSupportResponseTime',
];

/**
* Unreleased quota keys will be added here, and it will effect the following:
* - Related quota items will have a "Coming soon" tag in the plan selection component.
* - Related quota items will be hidden from the downgrade plan notification modal.
*/
export const comingSoonQuotaKeys: Array<keyof SubscriptionPlanQuota> = [];

export const comingSoonSkuQuotaKeys: Array<keyof LogtoSkuQuota> = [];
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { Trans, useTranslation } from 'react-i18next';
import ReactModal from 'react-modal';

import ContactUsPhraseLink from '@/components/ContactUsPhraseLink';
import PlanName from '@/components/PlanName';
import QuotaGuardFooter from '@/components/QuotaGuardFooter';
import SkuName from '@/components/SkuName';
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
import Button from '@/ds-components/Button';
import FormField from '@/ds-components/FormField';
Expand All @@ -28,12 +28,8 @@ type Props = {
type CreatePermissionFormData = Pick<CreateScope, 'name' | 'description'>;

function CreatePermissionModal({ resourceId, totalResourceCount, onClose }: Props) {
const {
currentPlan,
currentSku,
currentSubscriptionQuota,
currentSubscriptionResourceScopeUsage,
} = useContext(SubscriptionDataContext);
const { currentSku, currentSubscriptionQuota, currentSubscriptionResourceScopeUsage } =
useContext(SubscriptionDataContext);
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });

const {
Expand Down Expand Up @@ -87,7 +83,7 @@ function CreatePermissionModal({ resourceId, totalResourceCount, onClose }: Prop
<Trans
components={{
a: <ContactUsPhraseLink />,
planName: <PlanName skuId={currentSku.id} name={currentPlan.name} />,
planName: <SkuName skuId={currentSku.id} />,
}}
>
{t('upsell.paywall.scopes_per_resource', {
Expand Down
Loading

0 comments on commit e0623df

Please sign in to comment.