0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

feat(console,core): support hidding charge notification on read (#5151)

This commit is contained in:
Xiao Yijun 2023-12-25 16:42:13 +08:00 committed by GitHub
parent aca6695fc3
commit a6f12307b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 11 deletions

View file

@ -1,5 +1,5 @@
import { ReservedPlanId } from '@logto/schemas';
import { cond } from '@silverhand/essentials';
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';
@ -8,27 +8,44 @@ import { pricingLink } from '@/consts';
import { TenantsContext } from '@/contexts/TenantsProvider';
import InlineNotification from '@/ds-components/InlineNotification';
import TextLink from '@/ds-components/TextLink';
import useConfigs from '@/hooks/use-configs';
import useSubscriptionPlan from '@/hooks/use-subscription-plan';
type Props = {
hasSurpassedLimit: boolean;
quotaItem: TFuncKey<'translation', 'admin_console.upsell.add_on_quota_item'>;
quotaItemPhraseKey: TFuncKey<'translation', 'admin_console.upsell.add_on_quota_item'>;
quotaLimit?: number;
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}
*/
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.
* 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, quotaItem, quotaLimit, className }: Props) {
function ChargeNotification({
hasSurpassedLimit,
quotaItemPhraseKey,
quotaLimit,
className,
checkedFlagKey,
}: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.upsell' });
const { currentTenantId } = useContext(TenantsContext);
const { data: currentPlan } = useSubscriptionPlan(currentTenantId);
const { configs, updateConfigs } = useConfigs();
const checkedChargeNotification = configs?.checkedChargeNotification;
if (
Boolean(checkedChargeNotification?.[checkedFlagKey]) ||
!hasSurpassedLimit ||
// No charge notification for free plan
currentPlan?.id === ReservedPlanId.Free
@ -37,13 +54,26 @@ function ChargeNotification({ hasSurpassedLimit, quotaItem, quotaLimit, classNam
}
return (
<InlineNotification className={className}>
<InlineNotification
className={className}
action="general.got_it"
onClick={() => {
void updateConfigs({
checkedChargeNotification: {
...checkedChargeNotification,
[checkedFlagKey]: true,
},
});
}}
>
<Trans components={{ a: <TextLink href={pricingLink} targetBlank="noopener" /> }}>
{t('charge_notification_for_quota_limit', {
item: t(`add_on_quota_item.${quotaItem}`, {
item: t(`add_on_quota_item.${quotaItemPhraseKey}`, {
...cond(
// Note: tokens use 'M' as unit
quotaLimit && { limit: quotaItem === 'tokens' ? quotaLimit / 1_000_000 : quotaLimit }
quotaLimit && {
limit: quotaItemPhraseKey === 'tokens' ? quotaLimit / 1_000_000 : quotaLimit,
}
),
}),
})}

View file

@ -83,7 +83,11 @@ function ApiResources() {
isCloud &&
// Todo @xiaoyijun [Pricing] Remove feature flag
isDevFeaturesEnabled && (
<ChargeNotification hasSurpassedLimit={hasSurpassedLimit} quotaItem="api_resource" />
<ChargeNotification
hasSurpassedLimit={hasSurpassedLimit}
quotaItemPhraseKey="api_resource"
checkedFlagKey="apiResource"
/>
)
}
table={{

View file

@ -77,8 +77,9 @@ function Applications() {
{isCloud && isDevFeaturesEnabled && (
<ChargeNotification
hasSurpassedLimit={hasMachineToMachineAppsSurpassedLimit}
quotaItem="machine_to_machine"
quotaItemPhraseKey="machine_to_machine"
className={styles.chargeNotification}
checkedFlagKey="machineToMachineApp"
/>
)}
{!isLoading && !applications?.length && (

View file

@ -58,6 +58,12 @@ export const adminConsoleDataGuard = z.object({
readAt: z.number().optional(),
})
.optional(),
checkedChargeNotification: z
.object({
apiResource: z.boolean().optional(),
machineToMachineApp: z.boolean().optional(),
})
.optional(),
});
export type AdminConsoleData = z.infer<typeof adminConsoleDataGuard>;