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

refactor(console): use useSWRImmutable to avoid redundant subscrtipion data fetching (#4272)

This commit is contained in:
Xiao Yijun 2023-08-03 14:04:25 +08:00 committed by GitHub
parent 8cba35d116
commit 56b0a2cd18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 55 deletions

View file

@ -1,7 +1,9 @@
import { useContext, useEffect, useState } from 'react'; import { useContext, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next'; import { Trans, useTranslation } from 'react-i18next';
import ReactModal from 'react-modal'; import ReactModal from 'react-modal';
import useSWRImmutable from 'swr/immutable';
import { useCloudApi } from '@/cloud/hooks/use-cloud-api';
import PlanUsage from '@/components/PlanUsage'; import PlanUsage from '@/components/PlanUsage';
import { contactEmailLink } from '@/consts'; import { contactEmailLink } from '@/consts';
import { subscriptionPage } from '@/consts/pages'; import { subscriptionPage } from '@/consts/pages';
@ -10,9 +12,7 @@ import Button from '@/ds-components/Button';
import FormField from '@/ds-components/FormField'; import FormField from '@/ds-components/FormField';
import InlineNotification from '@/ds-components/InlineNotification'; import InlineNotification from '@/ds-components/InlineNotification';
import ModalLayout from '@/ds-components/ModalLayout'; import ModalLayout from '@/ds-components/ModalLayout';
import useSubscription from '@/hooks/use-subscription'; import useSubscriptionPlans from '@/hooks/use-subscription-plans';
import useSubscriptionPlan from '@/hooks/use-subscription-plan';
import useSubscriptionUsage from '@/hooks/use-subscription-usage';
import useTenantPathname from '@/hooks/use-tenant-pathname'; import useTenantPathname from '@/hooks/use-tenant-pathname';
import * as modalStyles from '@/scss/modal.module.scss'; import * as modalStyles from '@/scss/modal.module.scss';
@ -22,55 +22,52 @@ import * as styles from './index.module.scss';
function MauExceededModal() { function MauExceededModal() {
const { currentTenantId } = useContext(TenantsContext); const { currentTenantId } = useContext(TenantsContext);
const cloudApi = useCloudApi();
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { navigate } = useTenantPathname(); const { navigate } = useTenantPathname();
const [hasClosed, setHasClosed] = useState(false); const [hasClosed, setHasClosed] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const handleCloseModal = () => { const handleCloseModal = () => {
setHasClosed(true); setHasClosed(true);
setIsOpen(false);
}; };
const { data: currentUsage, error: fetchUsageError } = useSubscriptionUsage(currentTenantId); const { data: subscriptionPlans } = useSubscriptionPlans();
const { data: currentSubscription, error: fetchSubscriptionError } =
useSubscription(currentTenantId);
const { data: currentPlan, error: fetchCurrentPlanError } = useSubscriptionPlan(currentTenantId);
const isLoadingUsage = !currentUsage && !fetchUsageError; const { data: currentSubscription } = useSWRImmutable(
const isLoadingSubscription = !currentSubscription && !fetchSubscriptionError; `/api/tenants/${currentTenantId}/subscription`,
const isLoadingCurrentPlan = !currentPlan && !fetchCurrentPlanError; async () =>
cloudApi.get('/api/tenants/:tenantId/subscription', { params: { tenantId: currentTenantId } })
);
useEffect(() => { const { data: currentUsage } = useSWRImmutable(
if (!currentUsage || !currentPlan || hasClosed) { `/api/tenants/${currentTenantId}/usage`,
return; async () =>
} cloudApi.get('/api/tenants/:tenantId/usage', { params: { tenantId: currentTenantId } })
);
const { const currentPlan =
quota: { mauLimit }, currentSubscription &&
} = currentPlan; subscriptionPlans?.find((plan) => plan.id === currentSubscription.planId);
if (mauLimit === null) { if (!currentPlan || !currentUsage || hasClosed) {
return;
}
if (currentUsage.activeUsers >= mauLimit) {
setIsOpen(true);
}
}, [currentPlan, currentUsage, hasClosed]);
if (isLoadingUsage || isLoadingSubscription || isLoadingCurrentPlan) {
return null; return null;
} }
if (!currentUsage || !currentSubscription || !currentPlan) { const {
quota: { mauLimit },
name: planName,
} = currentPlan;
const isMauExceeded = mauLimit !== null && currentUsage.activeUsers >= mauLimit;
if (!isMauExceeded) {
return null; return null;
} }
return ( return (
<ReactModal <ReactModal
isOpen
shouldCloseOnEsc shouldCloseOnEsc
isOpen={isOpen}
className={modalStyles.content} className={modalStyles.content}
overlayClassName={modalStyles.overlay} overlayClassName={modalStyles.overlay}
onRequestClose={handleCloseModal} onRequestClose={handleCloseModal}
@ -97,7 +94,7 @@ function MauExceededModal() {
<InlineNotification severity="error"> <InlineNotification severity="error">
<Trans <Trans
components={{ components={{
planName: <PlanName name={currentPlan.name} />, planName: <PlanName name={planName} />,
}} }}
> >
{t('upsell.mau_exceeded_modal.notification')} {t('upsell.mau_exceeded_modal.notification')}

View file

@ -1,15 +1,16 @@
import { conditional } from '@silverhand/essentials'; import { conditional } from '@silverhand/essentials';
import { useContext, useEffect, useMemo, useState } from 'react'; import { useContext, useMemo, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next'; import { Trans, useTranslation } from 'react-i18next';
import ReactModal from 'react-modal'; import ReactModal from 'react-modal';
import useSWRImmutable from 'swr/immutable';
import { useCloudApi } from '@/cloud/hooks/use-cloud-api';
import { contactEmailLink } from '@/consts'; import { contactEmailLink } from '@/consts';
import { TenantsContext } from '@/contexts/TenantsProvider'; import { TenantsContext } from '@/contexts/TenantsProvider';
import Button from '@/ds-components/Button'; import Button from '@/ds-components/Button';
import FormField from '@/ds-components/FormField'; import FormField from '@/ds-components/FormField';
import InlineNotification from '@/ds-components/InlineNotification'; import InlineNotification from '@/ds-components/InlineNotification';
import ModalLayout from '@/ds-components/ModalLayout'; import ModalLayout from '@/ds-components/ModalLayout';
import useInvoices from '@/hooks/use-invoices';
import useSubscribe from '@/hooks/use-subscribe'; import useSubscribe from '@/hooks/use-subscribe';
import * as modalStyles from '@/scss/modal.module.scss'; import * as modalStyles from '@/scss/modal.module.scss';
import { getLatestUnpaidInvoice } from '@/utils/subscription'; import { getLatestUnpaidInvoice } from '@/utils/subscription';
@ -21,41 +22,33 @@ import * as styles from './index.module.scss';
function PaymentOverdueModal() { function PaymentOverdueModal() {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { currentTenant, currentTenantId } = useContext(TenantsContext); const { currentTenant, currentTenantId } = useContext(TenantsContext);
const { data: invoices, error } = useInvoices(currentTenantId); const cloudApi = useCloudApi();
const { data: invoicesResponse } = useSWRImmutable(
`/api/tenants/${currentTenantId}/invoices`,
async () =>
cloudApi.get('/api/tenants/:tenantId/invoices', { params: { tenantId: currentTenantId } })
);
const { visitManagePaymentPage } = useSubscribe(); const { visitManagePaymentPage } = useSubscribe();
const [isActionLoading, setIsActionLoading] = useState(false); const [isActionLoading, setIsActionLoading] = useState(false);
const isLoadingInvoices = !invoices && !error;
const latestUnpaidInvoice = useMemo(() => { const latestUnpaidInvoice = useMemo(
return conditional(invoices && getLatestUnpaidInvoice(invoices)); () => conditional(invoicesResponse && getLatestUnpaidInvoice(invoicesResponse.invoices)),
}, [invoices]); [invoicesResponse]
);
const [hasClosed, setHasClosed] = useState(false); const [hasClosed, setHasClosed] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const handleCloseModal = () => { const handleCloseModal = () => {
setHasClosed(true); setHasClosed(true);
setIsOpen(false);
}; };
useEffect(() => { if (!invoicesResponse || !latestUnpaidInvoice || hasClosed) {
if (isLoadingInvoices || hasClosed) {
return;
}
if (latestUnpaidInvoice) {
setIsOpen(true);
}
}, [hasClosed, isLoadingInvoices, latestUnpaidInvoice]);
if (isLoadingInvoices || !latestUnpaidInvoice || hasClosed) {
return null; return null;
} }
return ( return (
<ReactModal <ReactModal
isOpen
shouldCloseOnEsc shouldCloseOnEsc
isOpen={isOpen}
className={modalStyles.content} className={modalStyles.content}
overlayClassName={modalStyles.overlay} overlayClassName={modalStyles.overlay}
onRequestClose={handleCloseModal} onRequestClose={handleCloseModal}