0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-24 22:41:28 -05:00

refactor(console): treat hobby plan as the new pro plan (#5126)

This commit is contained in:
Xiao Yijun 2023-12-20 13:57:58 +08:00 committed by GitHub
parent 0691669d6f
commit ed1692959f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 60 additions and 22 deletions

View file

@ -8,7 +8,7 @@ import { useContext, useMemo, useState } from 'react';
import Modal from 'react-modal';
import useSWR from 'swr';
import { isCloud } from '@/consts/env';
import { isCloud, isDevFeaturesEnabled } from '@/consts/env';
import { TenantsContext } from '@/contexts/TenantsProvider';
import DynamicT from '@/ds-components/DynamicT';
import ModalLayout from '@/ds-components/ModalLayout';
@ -170,7 +170,8 @@ function CreateConnectorForm({ onClose, isOpen: isFormOpen, type }: Props) {
<FeatureTag
isVisible={isStandardConnectorDisabled}
for="upsell"
plan={ReservedPlanId.Hobby}
// Todo @xiaoyijun [Pricing] Remove feature flag
plan={isDevFeaturesEnabled ? ReservedPlanId.Pro : ReservedPlanId.Hobby}
/>
)}
</div>

View file

@ -1,7 +1,9 @@
import { type AdminConsoleKey } from '@logto/phrases';
import { TenantTag } from '@logto/schemas';
import { condArray } from '@silverhand/essentials';
import TenantEnvTag from '@/components/TenantEnvTag';
import { isDevFeaturesEnabled } from '@/consts/env';
import Divider from '@/ds-components/Divider';
import DynamicT from '@/ds-components/DynamicT';
import Tag from '@/ds-components/Tag';
@ -22,7 +24,8 @@ const descriptionMap: Record<TenantTag, AdminConsoleKey> = {
const availableProductionPlanNames = [
ReservedPlanName.Free,
ReservedPlanName.Hobby,
// Todo @xiaoyijun [Pricing] Remove feature flag
...condArray(!isDevFeaturesEnabled && ReservedPlanName.Hobby),
ReservedPlanName.Pro,
];

View file

@ -8,6 +8,7 @@ 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';
@ -76,10 +77,13 @@ function PlanCardItem({ plan, onSelect }: Props) {
<div className={styles.price}>
${t('monthly_price', { value: Number(basePrice) / 100 })}
</div>
<div className={styles.priceLabel}>
{t('mau_unit_price')}
<span className={styles.unitPrices}>{tierPrices}</span>
</div>
{/* Todo @xiaoyijun [Pricing] Remove feature flag */}
{!isDevFeaturesEnabled && (
<div className={styles.priceLabel}>
{t('mau_unit_price')}
<span className={styles.unitPrices}>{tierPrices}</span>
</div>
)}
</div>
<div className={styles.description}>
<PlanDescription planId={planId} />
@ -125,9 +129,11 @@ function PlanCardItem({ plan, onSelect }: Props) {
onClick={onSelect}
/>
</div>
{planId === ReservedPlanId.Pro && (
<div className={styles.mostPopularTag}>{t('most_popular')}</div>
)}
{planId === ReservedPlanId.Pro ||
// Todo @xiaoyijun [Pricing] Remove feature flag
(isDevFeaturesEnabled && planId === ReservedPlanId.Hobby && (
<div className={styles.mostPopularTag}>{t('most_popular')}</div>
))}
</div>
);
}

View file

@ -6,6 +6,7 @@ import Modal from 'react-modal';
import { useCloudApi, toastResponseError } from '@/cloud/hooks/use-cloud-api';
import { type TenantResponse } from '@/cloud/types/router';
import { pricingLink } from '@/consts';
import { isDevFeaturesEnabled } from '@/consts/env';
import DangerousRaw from '@/ds-components/DangerousRaw';
import ModalLayout from '@/ds-components/ModalLayout';
import TextLink from '@/ds-components/TextLink';
@ -72,7 +73,7 @@ function SelectTenantPlanModal({ tenantData, onClose }: Props) {
</Trans>
</DangerousRaw>
}
size="xlarge"
size={isDevFeaturesEnabled ? 'large' : 'xlarge'}
onClose={onClose}
>
<div className={styles.container}>

View file

@ -4,7 +4,7 @@ import { Suspense, useCallback, useContext } from 'react';
import { type Guide, type GuideMetadata } from '@/assets/docs/guides/types';
import FeatureTag from '@/components/FeatureTag';
import { isCloud } from '@/consts/env';
import { isCloud, isDevFeaturesEnabled } from '@/consts/env';
import { subscriptionPage } from '@/consts/pages';
import { TenantsContext } from '@/contexts/TenantsProvider';
import Button from '@/ds-components/Button';
@ -77,7 +77,11 @@ function GuideCard({ data, onClick, hasBorder, hasButton }: Props) {
<div className={styles.flexRow}>
<div className={styles.name}>{name}</div>
{hasPaywall && (
<FeatureTag isVisible={isM2mDisabled} for="upsell" plan={ReservedPlanId.Hobby} />
<FeatureTag
isVisible={isM2mDisabled}
for="upsell"
plan={isDevFeaturesEnabled ? ReservedPlanId.Pro : ReservedPlanId.Hobby}
/>
)}
</div>
<div className={styles.description} title={description}>

View file

@ -1,6 +1,7 @@
import { ReservedPlanId } from '@logto/schemas';
import { type TFuncKey } from 'i18next';
import { isDevFeaturesEnabled } from '@/consts/env';
import DynamicT from '@/ds-components/DynamicT';
const registeredPlanDescriptionPhrasesMap: Record<
@ -8,7 +9,7 @@ const registeredPlanDescriptionPhrasesMap: Record<
TFuncKey<'translation', 'admin_console.subscription'> | undefined
> = {
[ReservedPlanId.Free]: 'free_plan_description',
[ReservedPlanId.Hobby]: 'hobby_plan_description',
[ReservedPlanId.Hobby]: isDevFeaturesEnabled ? 'pro_plan_description' : 'hobby_plan_description',
[ReservedPlanId.Pro]: 'pro_plan_description',
};

View file

@ -2,6 +2,7 @@ import { type TFuncKey } from 'i18next';
import { useTranslation } from 'react-i18next';
import titleize from 'titleize';
import { isDevFeaturesEnabled } from '@/consts/env';
import { ReservedPlanName } from '@/types/subscriptions';
const registeredPlanNamePhraseMap: Record<
@ -10,7 +11,8 @@ const registeredPlanNamePhraseMap: Record<
> = {
quotaKey: undefined,
[ReservedPlanName.Free]: 'free_plan',
[ReservedPlanName.Hobby]: 'hobby_plan',
// Todo @xiaoyijun [Pricing] Remove feature flag
[ReservedPlanName.Hobby]: isDevFeaturesEnabled ? 'pro_plan' : 'hobby_plan',
[ReservedPlanName.Pro]: 'pro_plan',
[ReservedPlanName.Enterprise]: 'enterprise',
};

View file

@ -1,4 +1,7 @@
import { ReservedPlanId } from '@logto/schemas';
import { condArray } from '@silverhand/essentials';
import { isDevFeaturesEnabled as isDevelopmentFeaturesEnabled } from './env';
/**
* In console, only featured plans are shown in the plan selection component.
@ -6,7 +9,8 @@ import { ReservedPlanId } from '@logto/schemas';
export const featuredPlanIds: string[] = [
ReservedPlanId.Free,
ReservedPlanId.Hobby,
ReservedPlanId.Pro,
// Todo @xiaoyijun [Pricing] Remove feature flag
...condArray(!isDevelopmentFeaturesEnabled && ReservedPlanId.Pro),
];
/**

View file

@ -9,7 +9,7 @@ import FeatureTag from '@/components/FeatureTag';
import { type SelectedGuide } from '@/components/Guide/GuideCard';
import GuideCardGroup from '@/components/Guide/GuideCardGroup';
import { useAppGuideMetadata } from '@/components/Guide/hooks';
import { isCloud } from '@/consts/env';
import { isCloud, isDevFeaturesEnabled } from '@/consts/env';
import { TenantsContext } from '@/contexts/TenantsProvider';
import { CheckboxGroup } from '@/ds-components/Checkbox';
import OverlayScrollbar from '@/ds-components/OverlayScrollbar';
@ -105,7 +105,8 @@ function GuideLibrary({ className, hasCardBorder, hasCardButton, hasFilters }: P
<FeatureTag
isVisible={isM2mDisabledForCurrentPlan}
for="upsell"
plan={ReservedPlanId.Hobby}
// Todo @xiaoyijun [Pricing] Remove feature flag
plan={isDevFeaturesEnabled ? ReservedPlanId.Pro : ReservedPlanId.Hobby}
className={styles.proTag}
/>
</div>

View file

@ -4,7 +4,7 @@ import { useContext } from 'react';
import ApplicationIcon from '@/components/ApplicationIcon';
import FeatureTag from '@/components/FeatureTag';
import { isCloud } from '@/consts/env';
import { isCloud, isDevFeaturesEnabled } from '@/consts/env';
import { TenantsContext } from '@/contexts/TenantsProvider';
import useSubscriptionPlan from '@/hooks/use-subscription-plan';
@ -34,7 +34,8 @@ function TypeDescription({ title, subtitle, description, type, size = 'large' }:
<FeatureTag
isVisible={!currentPlan?.quota.machineToMachineLimit}
for="upsell"
plan={ReservedPlanId.Hobby}
// Todo @xiaoyijun [Pricing] Remove feature flag
plan={isDevFeaturesEnabled ? ReservedPlanId.Pro : ReservedPlanId.Hobby}
/>
</div>
)}

View file

@ -13,6 +13,7 @@ import FeatureTag from '@/components/FeatureTag';
import PlanName from '@/components/PlanName';
import QuotaGuardFooter from '@/components/QuotaGuardFooter';
import RoleScopesTransfer from '@/components/RoleScopesTransfer';
import { isDevFeaturesEnabled } from '@/consts/env';
import { TenantsContext } from '@/contexts/TenantsProvider';
import Button from '@/ds-components/Button';
import DynamicT from '@/ds-components/DynamicT';
@ -229,7 +230,8 @@ function CreateRoleForm({ totalRoleCount, onClose }: Props) {
<FeatureTag
isVisible={!currentPlan?.quota.machineToMachineLimit}
for="upsell"
plan={ReservedPlanId.Hobby}
// Todo @xiaoyijun [Pricing] Remove feature flag
plan={isDevFeaturesEnabled ? ReservedPlanId.Pro : ReservedPlanId.Hobby}
className={styles.proTag}
/>
)

View file

@ -2,6 +2,7 @@ import { ReservedPlanId } from '@logto/schemas';
import { useContext, useMemo, useState } from 'react';
import { toastResponseError } from '@/cloud/hooks/use-cloud-api';
import { isDevFeaturesEnabled } from '@/consts/env';
import { subscriptionPage } from '@/consts/pages';
import { TenantsContext } from '@/contexts/TenantsProvider';
import DynamicT from '@/ds-components/DynamicT';
@ -26,7 +27,18 @@ function MauLimitExceededNotification({ activeUsers, currentPlan, className }: P
const { data: subscriptionPlans } = useSubscriptionPlans();
const [isLoading, setIsLoading] = useState(false);
const proPlan = useMemo(
() => subscriptionPlans?.find(({ id }) => id === ReservedPlanId.Pro),
() =>
subscriptionPlans?.find(({ id }) => {
/**
* Todo @xiaoyijun [Pricing] Remove feature flag
* Note: In new pricing version, we treat Hobby plan as the new pro plan.
*/
if (isDevFeaturesEnabled) {
return id === ReservedPlanId.Hobby;
}
return id === ReservedPlanId.Pro;
}),
[subscriptionPlans]
);