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:
parent
aca6695fc3
commit
a6f12307b3
4 changed files with 52 additions and 11 deletions
|
@ -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,
|
||||
}
|
||||
),
|
||||
}),
|
||||
})}
|
||||
|
|
|
@ -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={{
|
||||
|
|
|
@ -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 && (
|
||||
|
|
|
@ -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>;
|
||||
|
|
Loading…
Reference in a new issue