mirror of
https://github.com/logto-io/logto.git
synced 2025-03-17 22:31:28 -05:00
fix(console): remove legacy charge notification components (#6505)
This commit is contained in:
parent
ed774bf62d
commit
f1ecec5487
9 changed files with 1 additions and 163 deletions
|
@ -1,91 +0,0 @@
|
|||
import { type AdminConsoleData, ReservedPlanId } from '@logto/schemas';
|
||||
import { cond, type Truthy } from '@silverhand/essentials';
|
||||
import { type TFuncKey } from 'i18next';
|
||||
import { useContext } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
|
||||
import { addOnPricingExplanationLink } from '@/consts';
|
||||
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
|
||||
import InlineNotification from '@/ds-components/InlineNotification';
|
||||
import TextLink from '@/ds-components/TextLink';
|
||||
import useConfigs from '@/hooks/use-configs';
|
||||
|
||||
type Props = {
|
||||
readonly hasSurpassedLimit: boolean;
|
||||
readonly quotaItemPhraseKey: TFuncKey<'translation', 'admin_console.upsell.add_on_quota_item'>;
|
||||
readonly quotaLimit?: number;
|
||||
readonly className?: string;
|
||||
/**
|
||||
* The key of the flag in `checkedChargeNotification` config from the AdminConsoleData.
|
||||
* Used to determine whether the notification has been checked.
|
||||
* @see{@link AdminConsoleData}
|
||||
*/
|
||||
readonly checkedFlagKey: keyof Truthy<AdminConsoleData['checkedChargeNotification']>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Charge notification for add-on quota limit features
|
||||
*
|
||||
* CAUTION:
|
||||
* - This notification will be rendered only when the tenant's subscription plan is a paid plan. We won't render it for free plan since we will not charge for free plan.
|
||||
* - If the notification has been marked as checked, it will not be rendered.
|
||||
*/
|
||||
function ChargeNotification({
|
||||
hasSurpassedLimit,
|
||||
quotaItemPhraseKey,
|
||||
quotaLimit,
|
||||
className,
|
||||
checkedFlagKey,
|
||||
}: Props) {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.upsell' });
|
||||
const { currentSku } = useContext(SubscriptionDataContext);
|
||||
const { configs, updateConfigs } = useConfigs();
|
||||
|
||||
// Display null when loading
|
||||
if (!configs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { checkedChargeNotification } = configs;
|
||||
|
||||
if (
|
||||
Boolean(checkedChargeNotification?.[checkedFlagKey]) ||
|
||||
!hasSurpassedLimit ||
|
||||
// No charge notification for free plan
|
||||
currentSku.id === ReservedPlanId.Free
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<InlineNotification
|
||||
className={className}
|
||||
action="general.got_it"
|
||||
onClick={() => {
|
||||
void updateConfigs({
|
||||
checkedChargeNotification: {
|
||||
...checkedChargeNotification,
|
||||
[checkedFlagKey]: true,
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Trans
|
||||
components={{ a: <TextLink href={addOnPricingExplanationLink} targetBlank="noopener" /> }}
|
||||
>
|
||||
{t('charge_notification_for_quota_limit', {
|
||||
item: t(`add_on_quota_item.${quotaItemPhraseKey}`, {
|
||||
...cond(
|
||||
// Note: tokens use 'M' as unit
|
||||
quotaLimit && {
|
||||
limit: quotaItemPhraseKey === 'tokens' ? quotaLimit / 1_000_000 : quotaLimit,
|
||||
}
|
||||
),
|
||||
}),
|
||||
})}
|
||||
</Trans>
|
||||
</InlineNotification>
|
||||
);
|
||||
}
|
||||
|
||||
export default ChargeNotification;
|
|
@ -3,7 +3,3 @@
|
|||
.icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.chargeNotification {
|
||||
margin-top: _.unit(4);
|
||||
}
|
||||
|
|
|
@ -8,17 +8,14 @@ import ApiResourceDark from '@/assets/icons/api-resource-dark.svg?react';
|
|||
import ApiResource from '@/assets/icons/api-resource.svg?react';
|
||||
import ManagementApiResourceDark from '@/assets/icons/management-api-resource-dark.svg?react';
|
||||
import ManagementApiResource from '@/assets/icons/management-api-resource.svg?react';
|
||||
import ChargeNotification from '@/components/ChargeNotification';
|
||||
import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder';
|
||||
import ItemPreview from '@/components/ItemPreview';
|
||||
import ListPage from '@/components/ListPage';
|
||||
import { defaultPageSize } from '@/consts';
|
||||
import { isCloud } from '@/consts/env';
|
||||
import { ApiResourceDetailsTabs } from '@/consts/page-tabs';
|
||||
import CopyToClipboard from '@/ds-components/CopyToClipboard';
|
||||
import Tag from '@/ds-components/Tag';
|
||||
import type { RequestError } from '@/hooks/use-api';
|
||||
import useApiResourcesUsage from '@/hooks/use-api-resources-usage';
|
||||
import useSearchParametersWatcher from '@/hooks/use-search-parameters-watcher';
|
||||
import useTenantPathname from '@/hooks/use-tenant-pathname';
|
||||
import useTheme from '@/hooks/use-theme';
|
||||
|
@ -41,7 +38,6 @@ const icons = {
|
|||
function ApiResources() {
|
||||
const { search } = useLocation();
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const { hasSurpassedLimit } = useApiResourcesUsage();
|
||||
const [{ page }, updateSearchParameters] = useSearchParametersWatcher({
|
||||
page: 1,
|
||||
});
|
||||
|
@ -78,16 +74,6 @@ function ApiResources() {
|
|||
});
|
||||
},
|
||||
}}
|
||||
subHeader={
|
||||
isCloud && (
|
||||
<ChargeNotification
|
||||
hasSurpassedLimit={hasSurpassedLimit}
|
||||
quotaItemPhraseKey="api_resource"
|
||||
checkedFlagKey="apiResource"
|
||||
className={styles.chargeNotification}
|
||||
/>
|
||||
)
|
||||
}
|
||||
table={{
|
||||
rowGroups: [{ key: 'apiResources', data: apiResources }],
|
||||
rowIndexKey: 'id',
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.chargeNotification {
|
||||
margin: _.unit(4) 0 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
|
|
@ -6,17 +6,14 @@ import { useLocation } from 'react-router-dom';
|
|||
|
||||
import Plus from '@/assets/icons/plus.svg?react';
|
||||
import ApplicationCreation from '@/components/ApplicationCreation';
|
||||
import ChargeNotification from '@/components/ChargeNotification';
|
||||
import { type SelectedGuide } from '@/components/Guide/GuideCard';
|
||||
import ApplicationPreview from '@/components/ItemPreview/ApplicationPreview';
|
||||
import PageMeta from '@/components/PageMeta';
|
||||
import { isCloud } from '@/consts/env';
|
||||
import Button from '@/ds-components/Button';
|
||||
import CardTitle from '@/ds-components/CardTitle';
|
||||
import CopyToClipboard from '@/ds-components/CopyToClipboard';
|
||||
import TabNav, { TabNavItem } from '@/ds-components/TabNav';
|
||||
import Table from '@/ds-components/Table';
|
||||
import useApplicationsUsage from '@/hooks/use-applications-usage';
|
||||
import useTenantPathname from '@/hooks/use-tenant-pathname';
|
||||
import pageLayout from '@/scss/page-layout.module.scss';
|
||||
import { buildUrl } from '@/utils/url';
|
||||
|
@ -54,7 +51,6 @@ function Applications({ tab }: Props) {
|
|||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
|
||||
const isCreating = match(createApplicationPathname);
|
||||
const { hasMachineToMachineAppsSurpassedLimit } = useApplicationsUsage();
|
||||
/**
|
||||
* Selected guide from the guide library
|
||||
* - `undefined`: No guide is selected
|
||||
|
@ -121,15 +117,6 @@ function Applications({ tab }: Props) {
|
|||
/>
|
||||
)}
|
||||
</div>
|
||||
{isCloud && (
|
||||
<ChargeNotification
|
||||
hasSurpassedLimit={hasMachineToMachineAppsSurpassedLimit}
|
||||
quotaItemPhraseKey="machine_to_machine"
|
||||
className={styles.chargeNotification}
|
||||
checkedFlagKey="machineToMachineApp"
|
||||
/>
|
||||
)}
|
||||
|
||||
{showThirdPartyApplicationTab && (
|
||||
<TabNav className={styles.tabs}>
|
||||
<TabNavItem
|
||||
|
|
|
@ -13,7 +13,3 @@
|
|||
color: var(--color-text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.notification {
|
||||
margin-top: _.unit(6);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import { useContext, useMemo } from 'react';
|
|||
|
||||
import { type NewSubscriptionPeriodicUsage } from '@/cloud/types/router';
|
||||
import BillInfo from '@/components/BillInfo';
|
||||
import ChargeNotification from '@/components/ChargeNotification';
|
||||
import FormCard from '@/components/FormCard';
|
||||
import PlanDescription from '@/components/PlanDescription';
|
||||
import PlanUsage from '@/components/PlanUsage';
|
||||
|
@ -11,7 +10,6 @@ import SkuName from '@/components/SkuName';
|
|||
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
|
||||
import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||
import FormField from '@/ds-components/FormField';
|
||||
import { hasSurpassedSubscriptionQuotaLimit } from '@/utils/quota';
|
||||
|
||||
import AddOnUsageChangesNotification from './AddOnUsageChangesNotification';
|
||||
import MauLimitExceedNotification from './MauLimitExceededNotification';
|
||||
|
@ -23,8 +21,7 @@ type Props = {
|
|||
};
|
||||
|
||||
function CurrentPlan({ periodicUsage: rawPeriodicUsage }: Props) {
|
||||
const { currentSku, currentSubscription, currentSubscriptionQuota } =
|
||||
useContext(SubscriptionDataContext);
|
||||
const { currentSku, currentSubscription } = useContext(SubscriptionDataContext);
|
||||
const { currentTenant } = useContext(TenantsContext);
|
||||
|
||||
const periodicUsage = useMemo(
|
||||
|
@ -52,12 +49,6 @@ function CurrentPlan({ periodicUsage: rawPeriodicUsage }: Props) {
|
|||
return null;
|
||||
}
|
||||
|
||||
const hasTokenSurpassedLimit = hasSurpassedSubscriptionQuotaLimit({
|
||||
quotaKey: 'tokenLimit',
|
||||
usage: periodicUsage.tokenLimit,
|
||||
quota: currentSubscriptionQuota,
|
||||
});
|
||||
|
||||
return (
|
||||
<FormCard title="subscription.current_plan" description="subscription.current_plan_description">
|
||||
<div className={styles.planInfo}>
|
||||
|
@ -81,16 +72,6 @@ function CurrentPlan({ periodicUsage: rawPeriodicUsage }: Props) {
|
|||
periodicUsage={rawPeriodicUsage}
|
||||
className={styles.notification}
|
||||
/>
|
||||
<ChargeNotification
|
||||
hasSurpassedLimit={hasTokenSurpassedLimit}
|
||||
quotaItemPhraseKey="tokens"
|
||||
checkedFlagKey="token"
|
||||
className={styles.notification}
|
||||
quotaLimit={cond(
|
||||
typeof currentSubscriptionQuota.tokenLimit === 'number' &&
|
||||
currentSubscriptionQuota.tokenLimit
|
||||
)}
|
||||
/>
|
||||
<PaymentOverdueNotification className={styles.notification} />
|
||||
</FormCard>
|
||||
);
|
||||
|
|
|
@ -5,10 +5,6 @@
|
|||
flex-direction: column;
|
||||
gap: _.unit(4);
|
||||
|
||||
.chargeNotification {
|
||||
margin: _.unit(4) 0 0;
|
||||
}
|
||||
|
||||
.tabButtons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
@ -7,7 +7,6 @@ import InvitationIcon from '@/assets/icons/invitation.svg?react';
|
|||
import MembersIcon from '@/assets/icons/members.svg?react';
|
||||
import PlusIcon from '@/assets/icons/plus.svg?react';
|
||||
import { useAuthedCloudApi } from '@/cloud/hooks/use-cloud-api';
|
||||
import ChargeNotification from '@/components/ChargeNotification';
|
||||
import { TenantSettingsTabs } from '@/consts';
|
||||
import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||
import Button from '@/ds-components/Button';
|
||||
|
@ -16,11 +15,9 @@ import useCurrentTenantScopes from '@/hooks/use-current-tenant-scopes';
|
|||
import useTenantPathname from '@/hooks/use-tenant-pathname';
|
||||
|
||||
import InviteMemberModal from './InviteMemberModal';
|
||||
import useTenantMembersUsage from './hooks';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
function TenantMembers() {
|
||||
const { hasTenantMembersSurpassedLimit } = useTenantMembersUsage();
|
||||
const { navigate, match } = useTenantPathname();
|
||||
const [showInviteModal, setShowInviteModal] = useState(false);
|
||||
const {
|
||||
|
@ -39,12 +36,6 @@ function TenantMembers() {
|
|||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<ChargeNotification
|
||||
hasSurpassedLimit={hasTenantMembersSurpassedLimit}
|
||||
quotaItemPhraseKey="tenant_member"
|
||||
className={styles.chargeNotification}
|
||||
checkedFlagKey="tenantMember"
|
||||
/>
|
||||
{canInviteMember && (
|
||||
<div className={styles.tabButtons}>
|
||||
<Button
|
||||
|
|
Loading…
Add table
Reference in a new issue