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

refactor(console): add use tenants hook

This commit is contained in:
Darcy Ye 2023-06-08 10:15:49 +08:00
parent ec6e266705
commit 0c1e086a43
No known key found for this signature in database
GPG key ID: B46F4C07EDEFC610
2 changed files with 128 additions and 1 deletions

View file

@ -17,6 +17,7 @@ export type Tenants = {
setTenants: (tenants: TenantInfo[]) => void; setTenants: (tenants: TenantInfo[]) => void;
setIsSettle: (isSettle: boolean) => void; setIsSettle: (isSettle: boolean) => void;
currentTenantId: string; currentTenantId: string;
setCurrentTenantId: (tenantId: string) => void;
navigate: (tenantId: string, options?: NavigateOptions) => void; navigate: (tenantId: string, options?: NavigateOptions) => void;
}; };
@ -33,6 +34,7 @@ export const TenantsContext = createContext<Tenants>({
isSettle: false, isSettle: false,
setIsSettle: noop, setIsSettle: noop,
currentTenantId: '', currentTenantId: '',
setCurrentTenantId: noop,
navigate: noop, navigate: noop,
}); });
@ -52,7 +54,15 @@ function TenantsProvider({ children }: Props) {
}, []); }, []);
const memorizedContext = useMemo( const memorizedContext = useMemo(
() => ({ tenants, setTenants, isSettle, setIsSettle, currentTenantId, navigate }), () => ({
tenants,
setTenants,
isSettle,
setIsSettle,
currentTenantId,
setCurrentTenantId,
navigate,
}),
[currentTenantId, isSettle, navigate, tenants] [currentTenantId, isSettle, navigate, tenants]
); );

View file

@ -0,0 +1,117 @@
import { useLogto } from '@logto/react';
import { type PatchTenant, type CreateTenant, type TenantInfo } from '@logto/schemas';
import { trySafe } from '@silverhand/essentials';
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useCloudApi } from '@/cloud/hooks/use-cloud-api';
import { TenantsContext } from '@/contexts/TenantsProvider';
const useTenants = () => {
const { signIn, getAccessToken } = useLogto();
const cloudApi = useCloudApi();
const { tenants, setTenants, currentTenantId, setCurrentTenantId, setIsSettle, navigate } =
useContext(TenantsContext);
const [error, setError] = useState<Error>();
const tryCatch = async (exec: Parameters<typeof trySafe>[0]) =>
trySafe(exec, (error) => {
setError(error instanceof Error ? error : new Error(String(error)));
});
const validate = useCallback(
async (tenant: TenantInfo) => {
const { id, indicator } = tenant;
if (await trySafe(getAccessToken(indicator))) {
setIsSettle(true);
} else {
void signIn(new URL(`/${id}/callback`, window.location.origin).toString());
}
},
[getAccessToken, setIsSettle, signIn]
);
const loadTenants = useCallback(async () => {
await tryCatch(async () => {
const availableTenants = await cloudApi.get('/api/tenants').json<TenantInfo[]>();
setTenants(availableTenants);
});
}, [cloudApi, setTenants]);
const create = useCallback(
async (payload: Required<Pick<CreateTenant, 'name' | 'tag'>>) => {
await tryCatch(async () => {
const createdTenant = await cloudApi
.post('/api/tenants', { json: payload })
.json<TenantInfo>();
const newTenants = [createdTenant, ...(tenants ?? [])];
setTenants(newTenants);
});
},
[cloudApi, setTenants, tenants]
);
const update = useCallback(
async (payload: Required<PatchTenant>) => {
await tryCatch(async () => {
const updatedTenant = await cloudApi
.patch(`/api/tenants/${currentTenantId}`, { json: payload })
.json<TenantInfo>();
const index = tenants?.findIndex(({ id }) => id === currentTenantId);
if (index !== undefined && index !== -1) {
const updatedTenants = [
...(tenants ?? []).slice(0, index),
updatedTenant,
...(tenants ?? []).slice(index + 1),
];
setTenants(updatedTenants);
}
});
},
[cloudApi, currentTenantId, setTenants, tenants]
);
/** `delete` is built-in property. */
const remove = useCallback(async () => {
await tryCatch(async () => {
await cloudApi.delete(`/api/tenants/${currentTenantId}`);
const tenantsAfterDeletion = (tenants ?? []).filter(({ id }) => id !== currentTenantId);
setTenants(tenantsAfterDeletion);
setCurrentTenantId('');
setIsSettle(false);
});
}, [cloudApi, currentTenantId, setCurrentTenantId, setIsSettle, setTenants, tenants]);
useEffect(() => {
if (!tenants) {
void loadTenants();
}
}, [loadTenants, tenants]);
const currentTenant = useMemo(() => {
return tenants?.find(({ id }) => id === currentTenantId);
}, [currentTenantId, tenants]);
useEffect(() => {
if (currentTenant) {
void validate(currentTenant);
}
/** Fallback to the first available tenant. */
if (tenants?.[0]) {
setCurrentTenantId(tenants[0].id);
navigate(tenants[0].id);
}
}, [currentTenant, navigate, setCurrentTenantId, tenants, validate]);
return {
tenants,
currentTenantId,
currentTenant,
create,
update,
remove,
isLoaded: Boolean(tenants && !error),
error,
};
};
export default useTenants;