From ac2f492dbee5641014e59d9e9bf244f28376aad7 Mon Sep 17 00:00:00 2001 From: Xiao Yijun Date: Thu, 20 Jul 2023 11:29:01 +0800 Subject: [PATCH] feat(console): apply quota limit for connector creation (#4190) --- .../CreateConnectorForm/Footer/index.tsx | 117 ++++++++++++++++++ .../components/CreateConnectorForm/index.tsx | 30 +++-- 2 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 packages/console/src/components/CreateConnectorForm/Footer/index.tsx diff --git a/packages/console/src/components/CreateConnectorForm/Footer/index.tsx b/packages/console/src/components/CreateConnectorForm/Footer/index.tsx new file mode 100644 index 000000000..ab8f8146d --- /dev/null +++ b/packages/console/src/components/CreateConnectorForm/Footer/index.tsx @@ -0,0 +1,117 @@ +import { + ConnectorType, + type ConnectorResponse, + type ConnectorFactoryResponse, +} from '@logto/schemas'; +import { useMemo } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; + +import ContactUsPhraseLink from '@/components/ContactUsPhraseLink'; +import PlanName from '@/components/PlanName'; +import QuotaGuardFooter from '@/components/QuotaGuardFooter'; +import { ReservedPlanId } from '@/consts/subscriptions'; +import Button from '@/ds-components/Button'; +import useCurrentSubscriptionPlan from '@/hooks/use-current-subscription-plan'; +import { type ConnectorGroup } from '@/types/connector'; +import { isOverQuota } from '@/utils/quota'; + +type Props = { + isCreatingSocialConnector: boolean; + existingConnectors: ConnectorResponse[]; + selectedConnectorGroup?: ConnectorGroup; + isCreateButtonDisabled: boolean; + onClickCreateButton: () => void; +}; + +function Footer({ + isCreatingSocialConnector, + existingConnectors, + selectedConnectorGroup, + isCreateButtonDisabled, + onClickCreateButton, +}: Props) { + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.upsell.paywall' }); + const { data: currentPlan } = useCurrentSubscriptionPlan(); + + const standardConnectorCount = useMemo( + () => + existingConnectors.filter( + ({ isStandard, isDemo, type }) => isStandard && !isDemo && type === ConnectorType.Social + ).length, + [existingConnectors] + ); + + const socialConnectorCount = useMemo( + () => + existingConnectors.filter( + ({ isStandard, isDemo, type }) => !isStandard && !isDemo && type === ConnectorType.Social + ).length, + [existingConnectors] + ); + + const isStandardConnectorsOverQuota = isOverQuota({ + quotaKey: 'standardConnectorsLimit', + plan: currentPlan, + usage: standardConnectorCount, + }); + + const isSocialConnectorsOverQuota = isOverQuota({ + quotaKey: 'socialConnectorsLimit', + plan: currentPlan, + usage: socialConnectorCount, + }); + + if (isCreatingSocialConnector && currentPlan && selectedConnectorGroup) { + const { id: planId, name: planName, quota } = currentPlan; + + if (isStandardConnectorsOverQuota && selectedConnectorGroup.isStandard) { + return ( + + , + planName: , + }} + > + {quota.standardConnectorsLimit === 0 + ? t('standard_connectors_feature') + : t( + planId === ReservedPlanId.pro ? 'standard_connectors_pro' : 'standard_connectors', + { + count: quota.standardConnectorsLimit, + } + )} + + + ); + } + + if (isSocialConnectorsOverQuota && !selectedConnectorGroup.isStandard) { + return ( + + , + planName: , + }} + > + {t('social_connectors', { + count: quota.socialConnectorsLimit ?? 0, + })} + + + ); + } + } + + return ( +