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:
parent
3daf30835a
commit
5743515804
4 changed files with 78 additions and 80 deletions
|
@ -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';
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue