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

refactor(console): create user process (#2698)

This commit is contained in:
Xiao Yijun 2022-12-22 11:15:39 +08:00 committed by GitHub
parent 3daf30835a
commit 5743515804
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 80 deletions

View file

@ -4,4 +4,3 @@ export * from './logs';
export const themeStorageKey = 'logto:admin_console:theme'; export const themeStorageKey = 'logto:admin_console:theme';
export const requestTimeout = 20_000; export const requestTimeout = 20_000;
export const generatedPasswordStorageKey = 'logto:admin_console:generated_password';

View file

@ -19,7 +19,6 @@ import DetailsSkeleton from '@/components/DetailsSkeleton';
import TabNav, { TabNavItem } from '@/components/TabNav'; import TabNav, { TabNavItem } from '@/components/TabNav';
import TextLink from '@/components/TextLink'; import TextLink from '@/components/TextLink';
import UserAvatar from '@/components/UserAvatar'; import UserAvatar from '@/components/UserAvatar';
import { generatedPasswordStorageKey } from '@/consts';
import type { RequestError } from '@/hooks/use-api'; import type { RequestError } from '@/hooks/use-api';
import useApi from '@/hooks/use-api'; import useApi from '@/hooks/use-api';
import * as detailsStyles from '@/scss/details.module.scss'; import * as detailsStyles from '@/scss/details.module.scss';
@ -42,7 +41,6 @@ const UserDetails = () => {
const [isDeleted, setIsDeleted] = useState(false); const [isDeleted, setIsDeleted] = useState(false);
const [isResetPasswordFormOpen, setIsResetPasswordFormOpen] = useState(false); const [isResetPasswordFormOpen, setIsResetPasswordFormOpen] = useState(false);
const [resetResult, setResetResult] = useState<string>(); const [resetResult, setResetResult] = useState<string>();
const [password, setPassword] = useState(sessionStorage.getItem(generatedPasswordStorageKey));
const { data, error, mutate } = useSWR<User, RequestError>(userId && `/api/users/${userId}`); const { data, error, mutate } = useSWR<User, RequestError>(userId && `/api/users/${userId}`);
const isLoading = !data && !error; const isLoading = !data && !error;
@ -176,17 +174,6 @@ const UserDetails = () => {
)} )}
</> </>
)} )}
{data && password && (
<CreateSuccess
title="user_details.created_title"
username={data.username ?? '-'}
password={password}
onClose={() => {
setPassword(null);
sessionStorage.removeItem(generatedPasswordStorageKey);
}}
/>
)}
{data && resetResult && ( {data && resetResult && (
<CreateSuccess <CreateSuccess
title="user_details.reset_password.congratulations" title="user_details.reset_password.congratulations"

View file

@ -1,31 +1,44 @@
import { usernameRegEx } from '@logto/core-kit'; import { usernameRegEx } from '@logto/core-kit';
import type { User } from '@logto/schemas'; import type { User } from '@logto/schemas';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import { useState } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Modal from 'react-modal';
import { useNavigate } from 'react-router-dom';
import Button from '@/components/Button'; import Button from '@/components/Button';
import FormField from '@/components/FormField'; import FormField from '@/components/FormField';
import ModalLayout from '@/components/ModalLayout'; import ModalLayout from '@/components/ModalLayout';
import TextInput from '@/components/TextInput'; import TextInput from '@/components/TextInput';
import useApi from '@/hooks/use-api'; import useApi from '@/hooks/use-api';
import CreateSuccess from '@/pages/UserDetails/components/CreateSuccess';
import * as modalStyles from '@/scss/modal.module.scss';
type FormData = { type FormData = {
username: string; username: string;
name: string; name: string;
}; };
type CreatedUserInfo = {
user: User;
password: string;
};
type Props = { type Props = {
onClose?: (createdUser?: User, password?: string) => void; onClose: () => void;
}; };
const CreateForm = ({ onClose }: Props) => { const CreateForm = ({ onClose }: Props) => {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const navigate = useNavigate();
const [createdUserInfo, setCreatedUserInfo] = useState<CreatedUserInfo>();
const { const {
handleSubmit, handleSubmit,
register, register,
formState: { isSubmitting, errors }, formState: { isSubmitting, errors },
} = useForm<FormData>(); } = useForm<FormData>();
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const api = useApi(); const api = useApi();
@ -37,10 +50,30 @@ const CreateForm = ({ onClose }: Props) => {
const password = nanoid(8); const password = nanoid(8);
const createdUser = await api.post('/api/users', { json: { ...data, password } }).json<User>(); const createdUser = await api.post('/api/users', { json: { ...data, password } }).json<User>();
onClose?.(createdUser, password);
setCreatedUserInfo({
user: createdUser,
password,
});
}); });
return ( return createdUserInfo ? (
<CreateSuccess
title="user_details.created_title"
username={createdUserInfo.user.username ?? '-'}
password={createdUserInfo.password}
onClose={() => {
navigate(`/users/${createdUserInfo.user.id}`, { replace: true });
}}
/>
) : (
<Modal
shouldCloseOnEsc
isOpen
className={modalStyles.content}
overlayClassName={modalStyles.overlay}
onRequestClose={onClose}
>
<ModalLayout <ModalLayout
title="users.create" title="users.create"
footer={ footer={
@ -80,6 +113,7 @@ const CreateForm = ({ onClose }: Props) => {
</FormField> </FormField>
</form> </form>
</ModalLayout> </ModalLayout>
</Modal>
); );
}; };

View file

@ -2,7 +2,6 @@ import type { User } from '@logto/schemas';
import { conditional, conditionalString } from '@silverhand/essentials'; import { conditional, conditionalString } from '@silverhand/essentials';
import classNames from 'classnames'; import classNames from 'classnames';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Modal from 'react-modal';
import { useLocation, useNavigate, useSearchParams } from 'react-router-dom'; import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';
import useSWR from 'swr'; import useSWR from 'swr';
@ -18,9 +17,7 @@ import TableEmpty from '@/components/Table/TableEmpty';
import TableError from '@/components/Table/TableError'; import TableError from '@/components/Table/TableError';
import TableLoading from '@/components/Table/TableLoading'; import TableLoading from '@/components/Table/TableLoading';
import UserAvatar from '@/components/UserAvatar'; import UserAvatar from '@/components/UserAvatar';
import { generatedPasswordStorageKey } from '@/consts';
import type { RequestError } from '@/hooks/use-api'; import type { RequestError } from '@/hooks/use-api';
import * as modalStyles from '@/scss/modal.module.scss';
import * as resourcesStyles from '@/scss/resources.module.scss'; import * as resourcesStyles from '@/scss/resources.module.scss';
import * as tableStyles from '@/scss/table.module.scss'; import * as tableStyles from '@/scss/table.module.scss';
@ -68,36 +65,17 @@ const Users = () => {
}); });
}} }}
/> />
<Modal {isCreateNew && (
shouldCloseOnEsc
isOpen={isCreateNew}
className={modalStyles.content}
overlayClassName={modalStyles.overlay}
onRequestClose={() => {
navigate({
pathname: usersPathname,
search,
});
}}
>
<CreateForm <CreateForm
onClose={(createdUser, password) => { onClose={() => {
if (createdUser && password) {
sessionStorage.setItem(generatedPasswordStorageKey, password);
navigate(buildDetailsPathname(createdUser.id), { replace: true });
return;
}
navigate({ navigate({
pathname: usersPathname, pathname: usersPathname,
search, search,
}); });
}} }}
/> />
</Modal> )}
</div> </div>
<div className={classNames(resourcesStyles.table, styles.tableLayout)}> <div className={classNames(resourcesStyles.table, styles.tableLayout)}>
<div className={styles.filter}> <div className={styles.filter}>
<Search <Search