0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-04-07 23:01:25 -05:00

feat(console): add charge notification for add-on features ()

This commit is contained in:
Xiao Yijun 2023-12-20 14:06:09 +08:00 committed by GitHub
parent ed1692959f
commit b5bc374f2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 112 additions and 10 deletions
packages
console/src
components
ChargeNotification
ListPage
pages
ApiResources
Applications
Connectors/SignInExperienceSetupNotice
scss
phrases/src/locales
de/translation/admin-console/upsell
en/translation/admin-console/upsell
es/translation/admin-console/upsell
fr/translation/admin-console/upsell
it/translation/admin-console/upsell
ja/translation/admin-console/upsell
ko/translation/admin-console/upsell
pl-pl/translation/admin-console/upsell
pt-br/translation/admin-console/upsell
pt-pt/translation/admin-console/upsell
ru/translation/admin-console/upsell
tr-tr/translation/admin-console/upsell
zh-cn/translation/admin-console/upsell
zh-hk/translation/admin-console/upsell
zh-tw/translation/admin-console/upsell

View file

@ -0,0 +1,47 @@
import { ReservedPlanId } from '@logto/schemas';
import { type TFuncKey } from 'i18next';
import { useContext } from 'react';
import { isDevFeaturesEnabled } from '@/consts/env';
import { TenantsContext } from '@/contexts/TenantsProvider';
import DynamicT from '@/ds-components/DynamicT';
import InlineNotification from '@/ds-components/InlineNotification';
import useSubscriptionPlan from '@/hooks/use-subscription-plan';
type Props = {
hasReachedLimit: boolean;
notification?: TFuncKey<'translation', 'admin_console.upsell'>;
className?: string;
};
/**
* 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.
*/
function ChargeNotification({
hasReachedLimit,
notification = 'charge_notification_for_quota_limit',
className,
}: Props) {
const { currentTenantId } = useContext(TenantsContext);
const { data: currentPlan } = useSubscriptionPlan(currentTenantId);
if (
// Todo @xiaoyijun [Pricing] Remove feature flag
isDevFeaturesEnabled &&
// No charge notification for free plan
(!hasReachedLimit || currentPlan?.id === ReservedPlanId.Free)
) {
return null;
}
return (
<InlineNotification severity="error" className={className}>
<DynamicT forKey={`upsell.${notification}`} />
</InlineNotification>
);
}
export default ChargeNotification;

View file

@ -49,7 +49,7 @@ function ListPage<
<CardTitle {...title} />
{createButton && <Button icon={<Plus />} type="primary" size="large" {...createButton} />}
</div>
{subHeader}
{subHeader && <div className={pageLayout.subHeader}>{subHeader}</div>}
<Table className={pageLayout.table} {...table} />
{widgets}
</div>

View file

@ -9,6 +9,7 @@ import ApiResourceDark from '@/assets/icons/api-resource-dark.svg';
import ApiResource from '@/assets/icons/api-resource.svg';
import ManagementApiResourceDark from '@/assets/icons/management-api-resource-dark.svg';
import ManagementApiResource from '@/assets/icons/management-api-resource.svg';
import ChargeNotification from '@/components/ChargeNotification';
import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder';
import ItemPreview from '@/components/ItemPreview';
import ListPage from '@/components/ListPage';
@ -17,6 +18,7 @@ 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';
@ -39,7 +41,7 @@ const icons = {
function ApiResources() {
const { search } = useLocation();
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { hasReachedLimit } = useApiResourcesUsage();
const [{ page }, updateSearchParameters] = useSearchParametersWatcher({
page: 1,
});
@ -76,6 +78,7 @@ function ApiResources() {
});
},
}}
subHeader={<ChargeNotification hasReachedLimit={hasReachedLimit} />}
table={{
rowGroups: [{ key: 'apiResources', data: apiResources }],
rowIndexKey: 'id',

View file

@ -1,5 +1,9 @@
@use '@/scss/underscore' as _;
.chargeNotification {
margin: _.unit(4) 0 0;
}
.icon {
flex-shrink: 0;
}

View file

@ -6,6 +6,7 @@ import useSWR from 'swr';
import Plus from '@/assets/icons/plus.svg';
import ApplicationIcon from '@/components/ApplicationIcon';
import ChargeNotification from '@/components/ChargeNotification';
import ItemPreview from '@/components/ItemPreview';
import PageMeta from '@/components/PageMeta';
import { defaultPageSize } from '@/consts';
@ -15,6 +16,7 @@ import CopyToClipboard from '@/ds-components/CopyToClipboard';
import OverlayScrollbar from '@/ds-components/OverlayScrollbar';
import Table from '@/ds-components/Table';
import type { RequestError } from '@/hooks/use-api';
import useApplicationsUsage from '@/hooks/use-applications-usage';
import useSearchParametersWatcher from '@/hooks/use-search-parameters-watcher';
import useTenantPathname from '@/hooks/use-tenant-pathname';
import * as pageLayout from '@/scss/page-layout.module.scss';
@ -35,6 +37,7 @@ function Applications() {
const { match, navigate } = useTenantPathname();
const isCreating = match(createApplicationPathname);
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { hasMachineToMachineAppsReachedLimit } = useApplicationsUsage();
const [{ page }, updateSearchParameters] = useSearchParametersWatcher({
page: 1,
});
@ -69,6 +72,11 @@ function Applications() {
/>
)}
</div>
<ChargeNotification
hasReachedLimit={hasMachineToMachineAppsReachedLimit}
notification="charge_notification_for_m2m_app_limit"
className={styles.chargeNotification}
/>
{!isLoading && !applications?.length && (
<OverlayScrollbar className={styles.guideLibraryContainer}>
<CardTitle

View file

@ -1,5 +0,0 @@
@use '@/scss/underscore' as _;
.notice {
margin: _.unit(4) 0 0;
}

View file

@ -6,8 +6,6 @@ import InlineNotification from '@/ds-components/InlineNotification';
import TextLink from '@/ds-components/TextLink';
import useUserPreferences from '@/hooks/use-user-preferences';
import * as styles from './index.module.scss';
function SignInExperienceSetupNotice() {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { data: connectors } = useSWR<ConnectorResponse[]>('api/connectors');
@ -23,7 +21,6 @@ function SignInExperienceSetupNotice() {
return (
<InlineNotification
action="general.got_it"
className={styles.notice}
onClick={() => {
void update({ connectorSieNoticeConfirmed: true });
}}

View file

@ -14,6 +14,10 @@
align-items: center;
}
.subHeader {
margin: _.unit(4) 0 0;
}
.table {
flex: 1;
margin-top: _.unit(4);

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -35,6 +35,8 @@ const upsell = {
'You have reached your quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};

View file

@ -37,6 +37,9 @@ const upsell = {
/** UNTRANSLATED */
charge_notification_for_token_limit:
'You have reached your {{value}}M token quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
/** UNTRANSLATED */
charge_notification_for_m2m_app_limit:
'You have reached your machine-to-machine quota limit. We may add charges for features that go beyond your quota limit as add-ons, once we finalize the prices.',
paywall,
};