mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
refactor(console): reorg organization details routes (#5702)
This commit is contained in:
parent
336aa6f49a
commit
077cd85a06
5 changed files with 52 additions and 43 deletions
|
@ -1,8 +1,11 @@
|
|||
import { condArray } from '@silverhand/essentials';
|
||||
import { type RouteObject } from 'react-router-dom';
|
||||
import { Navigate, type RouteObject } from 'react-router-dom';
|
||||
|
||||
import { isDevFeaturesEnabled } from '@/consts/env';
|
||||
import OrganizationDetails from '@/pages/OrganizationDetails';
|
||||
import Members from '@/pages/OrganizationDetails/Members';
|
||||
import Settings from '@/pages/OrganizationDetails/Settings';
|
||||
import { OrganizationDetailsTabs } from '@/pages/OrganizationDetails/types';
|
||||
import Organizations from '@/pages/Organizations';
|
||||
|
||||
export const organizations: RouteObject = {
|
||||
|
@ -14,6 +17,14 @@ export const organizations: RouteObject = {
|
|||
path: 'template',
|
||||
element: <Organizations tab="template" />,
|
||||
},
|
||||
{ path: ':id/*', element: <OrganizationDetails /> }
|
||||
{
|
||||
path: ':id/*',
|
||||
element: <OrganizationDetails />,
|
||||
children: [
|
||||
{ index: true, element: <Navigate replace to={OrganizationDetailsTabs.Settings} /> },
|
||||
{ path: OrganizationDetailsTabs.Settings, element: <Settings /> },
|
||||
{ path: OrganizationDetailsTabs.Members, element: <Members /> },
|
||||
],
|
||||
}
|
||||
),
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { type UserWithOrganizationRoles, type Organization } from '@logto/schemas';
|
||||
import { type UserWithOrganizationRoles } from '@logto/schemas';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import Plus from '@/assets/icons/plus.svg';
|
||||
|
@ -19,17 +20,16 @@ import useActionTranslation from '@/hooks/use-action-translation';
|
|||
import useApi, { type RequestError } from '@/hooks/use-api';
|
||||
import { buildUrl } from '@/utils/url';
|
||||
|
||||
import { type OrganizationDetailsOutletContext } from '../types';
|
||||
|
||||
import AddMembersToOrganization from './AddMembersToOrganization';
|
||||
import EditOrganizationRolesModal from './EditOrganizationRolesModal';
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
const pageSize = defaultPageSize;
|
||||
|
||||
type Props = {
|
||||
organization: Organization;
|
||||
};
|
||||
|
||||
function Members({ organization }: Props) {
|
||||
function Members() {
|
||||
const { data: organization } = useOutletContext<OrganizationDetailsOutletContext>();
|
||||
const api = useApi();
|
||||
const [keyword, setKeyword] = useState('');
|
||||
const [page, setPage] = useState(1);
|
||||
|
|
|
@ -2,6 +2,7 @@ import { type Organization } from '@logto/schemas';
|
|||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
|
||||
import DetailsForm from '@/components/DetailsForm';
|
||||
import FormCard from '@/components/FormCard';
|
||||
|
@ -11,17 +12,10 @@ import TextInput from '@/ds-components/TextInput';
|
|||
import useApi from '@/hooks/use-api';
|
||||
import { trySubmitSafe } from '@/utils/form';
|
||||
|
||||
type Props = {
|
||||
/**
|
||||
* Whether the organization is being deleted, this is used to disable the unsaved
|
||||
* changes alert modal.
|
||||
*/
|
||||
isDeleting: boolean;
|
||||
data: Organization;
|
||||
onUpdated: (data: Organization) => void;
|
||||
};
|
||||
import { type OrganizationDetailsOutletContext } from '../types';
|
||||
|
||||
function Settings({ isDeleting, data, onUpdated }: Props) {
|
||||
function Settings() {
|
||||
const { isDeleting, data, onUpdated } = useOutletContext<OrganizationDetailsOutletContext>();
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const {
|
||||
register,
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { type Organization } from '@logto/schemas';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
// FIXME: @gao
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Navigate, Route, Routes, useParams } from 'react-router-dom';
|
||||
import { Outlet, useParams } from 'react-router-dom';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import Delete from '@/assets/icons/delete.svg';
|
||||
|
@ -23,15 +21,10 @@ import useTenantPathname from '@/hooks/use-tenant-pathname';
|
|||
|
||||
import Introduction from '../Organizations/Guide/Introduction';
|
||||
|
||||
import Members from './Members';
|
||||
import Settings from './Settings';
|
||||
import * as styles from './index.module.scss';
|
||||
import { OrganizationDetailsTabs, type OrganizationDetailsOutletContext } from './types';
|
||||
|
||||
const pathname = '/organizations';
|
||||
const tabs = Object.freeze({
|
||||
settings: 'settings',
|
||||
members: 'members',
|
||||
});
|
||||
|
||||
function OrganizationDetails() {
|
||||
const { id } = useParams();
|
||||
|
@ -111,27 +104,22 @@ function OrganizationDetails() {
|
|||
{t('organization_details.delete_confirmation')}
|
||||
</DeleteConfirmModal>
|
||||
<TabNav>
|
||||
<TabNavItem href={`${pathname}/${data.id}/${tabs.settings}`}>
|
||||
<TabNavItem href={`${pathname}/${data.id}/${OrganizationDetailsTabs.Settings}`}>
|
||||
{t('general.settings_nav')}
|
||||
</TabNavItem>
|
||||
<TabNavItem href={`${pathname}/${data.id}/${tabs.members}`}>
|
||||
<TabNavItem href={`${pathname}/${data.id}/${OrganizationDetailsTabs.Members}`}>
|
||||
{t('organizations.members')}
|
||||
</TabNavItem>
|
||||
</TabNav>
|
||||
<Routes>
|
||||
<Route index element={<Navigate replace to={tabs.settings} />} />
|
||||
<Route
|
||||
path={tabs.settings}
|
||||
element={
|
||||
<Settings
|
||||
isDeleting={isDeleting}
|
||||
data={data}
|
||||
onUpdated={async (data) => mutate(data)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route path={tabs.members} element={<Members organization={data} />} />
|
||||
</Routes>
|
||||
<Outlet
|
||||
context={
|
||||
{
|
||||
data,
|
||||
isDeleting,
|
||||
onUpdated: async (data) => mutate(data),
|
||||
} satisfies OrganizationDetailsOutletContext
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</DetailsPage>
|
||||
|
|
16
packages/console/src/pages/OrganizationDetails/types.ts
Normal file
16
packages/console/src/pages/OrganizationDetails/types.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { type Organization } from '@logto/schemas';
|
||||
|
||||
export type OrganizationDetailsOutletContext = {
|
||||
data: Organization;
|
||||
/**
|
||||
* Whether the organization is being deleted, this is used to disable the unsaved
|
||||
* changes alert modal.
|
||||
*/
|
||||
isDeleting: boolean;
|
||||
onUpdated: (data: Organization) => void;
|
||||
};
|
||||
|
||||
export enum OrganizationDetailsTabs {
|
||||
Settings = 'settings',
|
||||
Members = 'members',
|
||||
}
|
Loading…
Reference in a new issue