0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-27 21:39:16 -05:00

feat(console): add tenant suspended page (#4473)

This commit is contained in:
Xiao Yijun 2023-09-12 11:28:41 +08:00 committed by GitHub
parent c775d6c66f
commit 2337c1a3d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 91 additions and 12 deletions

View file

@ -1,4 +1,4 @@
import Topbar from '@/containers/AppContent/components/Topbar';
import Topbar from '@/components/Topbar';
import TenantLandingPageContent from './TenantLandingPageContent';
import * as styles from './index.module.scss';

View file

@ -10,15 +10,23 @@ type Props = {
};
function TenantStatusTag({ tenantData, tenantPlan, className }: Props) {
const { usage, openInvoices } = tenantData;
const { usage, openInvoices, isSuspended } = tenantData;
/**
* Tenant status priority:
* 1. suspend (WIP) @xiaoyijun
* 1. suspend
* 2. overdue
* 3. mau exceeded
*/
if (isSuspended) {
return (
<Tag className={className}>
<DynamicT forKey="user_details.suspended" />
</Tag>
);
}
if (openInvoices.length > 0) {
return (
<Tag className={className}>

View file

@ -4,11 +4,10 @@ import { useMemo } from 'react';
import Tick from '@/assets/icons/tick.svg';
import { type TenantResponse } from '@/cloud/types/router';
import PlanName from '@/components/PlanName';
import TenantEnvTag from '@/components/TenantEnvTag';
import { DropdownItem } from '@/ds-components/Dropdown';
import useSubscriptionPlans from '@/hooks/use-subscription-plans';
import TenantEnvTag from '../TenantEnvTag';
import TenantStatusTag from './TenantStatusTag';
import * as styles from './index.module.scss';

View file

@ -5,6 +5,7 @@ import KeyboardArrowDown from '@/assets/icons/keyboard-arrow-down.svg';
import PlusSign from '@/assets/icons/plus.svg';
import { type TenantResponse } from '@/cloud/types/router';
import CreateTenantModal from '@/components/CreateTenantModal';
import TenantEnvTag from '@/components/TenantEnvTag';
import { TenantsContext } from '@/contexts/TenantsProvider';
import Divider from '@/ds-components/Divider';
import Dropdown from '@/ds-components/Dropdown';
@ -13,7 +14,6 @@ import useUserDefaultTenantId from '@/hooks/use-user-default-tenant-id';
import { onKeyDownHandler } from '@/utils/a11y';
import TenantDropdownItem from './TenantDropdownItem';
import TenantEnvTag from './TenantEnvTag';
import * as styles from './index.module.scss';
export default function TenantSelector() {

View file

@ -0,0 +1,29 @@
@use '@/scss/underscore' as _;
.suspendedPage {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
.image {
flex-shrink: 0;
}
.title {
font: var(--font-title-1);
}
.description {
font: var(--font-body-2);
text-align: center;
margin: _.unit(2);
width: 470px;
}
.linkButton {
margin-top: _.unit(4);
text-decoration: none;
}
}

View file

@ -0,0 +1,35 @@
import { Theme } from '@logto/schemas';
import ErrorDark from '@/assets/images/error-dark.svg';
import Error from '@/assets/images/error.svg';
import { contactEmailLink } from '@/consts';
import Button from '@/ds-components/Button';
import DynamicT from '@/ds-components/DynamicT';
import useTheme from '@/hooks/use-theme';
import * as styles from './index.module.scss';
function TenantSuspendedPage() {
const theme = useTheme();
const ErrorImage = theme === Theme.Light ? Error : ErrorDark;
return (
<div className={styles.suspendedPage}>
<ErrorImage className={styles.image} />
<div className={styles.title}>
<DynamicT forKey="tenants.tenant_suspended_page.title" />
</div>
<div className={styles.description}>
<DynamicT forKey="tenants.tenant_suspended_page.description_1" />
</div>
<div className={styles.description}>
<DynamicT forKey="tenants.tenant_suspended_page.description_2" />
</div>
<a href={contactEmailLink} className={styles.linkButton} rel="noopener">
<Button title="general.contact_us_action" type="outline" />
</a>
</div>
);
}
export default TenantSuspendedPage;

View file

@ -1,28 +1,33 @@
import { conditional, joinPath } from '@silverhand/essentials';
import { useRef } from 'react';
import { useContext, useRef } from 'react';
import { Navigate, Outlet, useParams } from 'react-router-dom';
import AppLoading from '@/components/AppLoading';
import MauExceededModal from '@/components/MauExceededModal';
import PaymentOverdueModal from '@/components/PaymentOverdueModal';
import Topbar from '@/components/Topbar';
import { isCloud } from '@/consts/env';
import { TenantsContext } from '@/contexts/TenantsProvider';
import useScroll from '@/hooks/use-scroll';
import useUserPreferences from '@/hooks/use-user-preferences';
import { getPath } from '../ConsoleContent/Sidebar';
import { useSidebarMenuItems } from '../ConsoleContent/Sidebar/hook';
import Topbar from './components/Topbar';
import TenantSuspendedPage from './TenantSuspendedPage';
import * as styles from './index.module.scss';
import { type AppContentOutletContext } from './types';
export default function AppContent() {
const { isLoading } = useUserPreferences();
const { currentTenant } = useContext(TenantsContext);
const isTenantSuspended = isCloud && currentTenant?.isSuspended;
const shouldCheckSubscriptionState = isCloud && !currentTenant?.isSuspended;
const scrollableContent = useRef<HTMLDivElement>(null);
const { scrollTop } = useScroll(scrollableContent.current);
if (isLoading) {
if (isLoading || !currentTenant) {
return <AppLoading />;
}
@ -30,9 +35,12 @@ export default function AppContent() {
<>
<div className={styles.app}>
<Topbar className={conditional(scrollTop && styles.topbarShadow)} />
{isTenantSuspended && <TenantSuspendedPage />}
{!isTenantSuspended && (
<Outlet context={{ scrollableContent } satisfies AppContentOutletContext} />
)}
</div>
{isCloud && (
{shouldCheckSubscriptionState && (
<>
<MauExceededModal />
<PaymentOverdueModal />

View file

@ -2,8 +2,8 @@ import classNames from 'classnames';
import { useTranslation, Trans } from 'react-i18next';
import { type TenantResponse } from '@/cloud/types/router';
import { tenantTagMap } from '@/components/TenantEnvTag';
import { contactEmailLink } from '@/consts';
import { tenantTagMap } from '@/containers/AppContent/components/Topbar/TenantSelector/TenantEnvTag';
import DeleteConfirmModal from '@/ds-components/DeleteConfirmModal';
import TextLink from '@/ds-components/TextLink';