Implement edit, delete user

This commit is contained in:
2023-10-29 21:33:49 +07:00
parent 2d936a9fdf
commit b45130c151
13 changed files with 254 additions and 81 deletions
+8 -2
View File
@@ -11,7 +11,7 @@ const UserDialog = forwardRef((props, ref) => {
const dialogRef = ref as React.MutableRefObject<
HTMLDialogElement | undefined
>;
const { onClose, setReload, reload } = props;
const { onClose, setReload, reload, user, isAdd } = props;
useEffect(() => {
if (dialogRef.current) {
@@ -31,7 +31,13 @@ const UserDialog = forwardRef((props, ref) => {
return (
<Dialog title={'Add user'} onClose={onClose} ref={dialogRef}>
<UserForm onClose={onClose!} reload={reload!} setReload={setReload!} />
<UserForm
onClose={onClose!}
reload={reload!}
setReload={setReload!}
user={user}
isAdd={isAdd!}
/>
</Dialog>
);
}) as React.FC<IDialogProps>;
+78 -29
View File
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import styled from 'styled-components';
import toast from 'react-hot-toast';
@@ -14,8 +14,8 @@ import Button from '../../commons/styles/Button.ts';
// Types
import {
TKeyValue,
TResponse,
TStateSchema,
TUser,
TValidator,
} from '../../globals/types';
@@ -29,12 +29,17 @@ import {
isValidPhoneNumber,
isValidString,
} from '../../helpers/validators';
import { addValidator } from '../../helpers/utils.ts';
import { addValidator, getValueUser } from '../../helpers/utils.ts';
import { sendRequest } from '../../helpers/sendRequest.ts';
// Constants
import { STATUS_CODE } from '../../constants/statusCode.ts';
import { ADD_SUCCESS, ERROR_MSG } from '../../constants/messages.ts';
import {
ADD_SUCCESS,
EDIT_SUCCESS,
ERROR_MSG,
} from '../../constants/messages.ts';
import { USER_PATH } from '../../constants/path.ts';
const FormBtn = styled(Button)`
width: 100%;
@@ -49,18 +54,34 @@ interface IUserFormProp {
onClose: () => void;
reload: boolean;
setReload: React.Dispatch<React.SetStateAction<boolean>>;
user?: TUser | null;
isAdd: boolean;
}
const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
const UserForm = ({
onClose,
reload,
setReload,
user,
isAdd,
}: IUserFormProp) => {
const [reset, setReset] = useState(true);
let initialValue: string = '';
if (isAdd) {
initialValue = '';
} else if (user) {
initialValue = user.id;
}
// Define your state schema
const stateSchema: TStateSchema = {
name: { value: '', error: '' },
identifiedCode: { value: '', error: '' },
phone: { value: '', error: '' },
roomId: { value: '', error: '' },
address: { value: '', error: '' },
id: { value: getValueUser(user, 'id') },
name: { value: getValueUser(user, 'name'), error: '' },
identifiedCode: { value: getValueUser(user, 'identifiedCode'), error: '' },
phone: { value: getValueUser(user, 'phone'), error: '' },
roomId: { value: getValueUser(user, 'roomId'), error: '' },
address: { value: getValueUser(user, 'address'), error: '' },
};
// prettier-ignore
@@ -90,31 +111,51 @@ const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
// Submit form
const onSubmitForm = async (state: TKeyValue) => {
try {
const response = await sendRequest(
'users',
JSON.stringify(state),
'POST',
);
if (isAdd) {
// Add request
const response = await sendRequest(
USER_PATH,
JSON.stringify(state),
'POST',
);
if (response.statusCode === STATUS_CODE.CREATE) {
toast.success(ADD_SUCCESS);
// Reload table data
setReload(!reload);
if (response.statusCode === STATUS_CODE.CREATE) {
toast.success(ADD_SUCCESS);
} else {
throw new Error(ERROR_MSG(response.statusCode, response.msg));
}
} else {
toast.error(ERROR_MSG(response.statusCode, response.msg));
}
// Edit request
const response = await sendRequest(
USER_PATH + `/${user!.id}`,
JSON.stringify(state),
'PUT',
);
if (response.statusCode == STATUS_CODE.OK) {
toast.success(EDIT_SUCCESS);
} else {
throw new Error(ERROR_MSG(response.statusCode, response.msg));
}
}
// Reload table data
setReload(!reload);
onResetForm();
} catch (error) {
toast.error(
ERROR_MSG((error as TResponse).statusCode, (error as TResponse).msg),
);
} catch (error: unknown) {
if (error instanceof Error) {
toast.error(error.message);
}
}
onClose();
};
// Close form
const closeAndReset = () => {
onClose();
onResetForm();
};
// prettier-ignore
const {
values,
@@ -127,10 +168,12 @@ const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
stateSchema,
stateValidatorSchema,
onSubmitForm,
initialValue
);
// prettier-ignore
const {
const {
id,
name,
identifiedCode,
phone,
@@ -138,6 +181,12 @@ const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
address
} = values;
useEffect(() => {
if (isAdd) {
Object.keys(values).forEach((key) => (values[key] = ''));
}
}, [isAdd]); // eslint-disable-line
// Reset form
const onResetForm = () => {
setReset(!reset);
@@ -146,7 +195,7 @@ const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
return (
<Form onSubmit={handleOnSubmit}>
<Input type="hidden" id="id" />
<Input type="hidden" name="id" value={id as string} />
<FormRow
label="Full Name"
error={
@@ -235,7 +284,7 @@ const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
<FormBtn type="submit" name="submit" disabled={disable}>
Add
</FormBtn>
<FormBtn type="button" styled="secondary" onClick={onClose}>
<FormBtn type="button" styled="secondary" onClick={closeAndReset}>
Close
</FormBtn>
</Form.Action>
+60 -8
View File
@@ -17,12 +17,47 @@ import { useFetch } from '../../hooks/useFetch';
// Styled
import Spinner from '../../commons/styles/Spinner';
import { sendRequest } from '../../helpers/sendRequest';
import { USER_PATH } from '../../constants/path';
import toast from 'react-hot-toast';
import { STATUS_CODE } from '../../constants/statusCode';
import { CONFIRM_DELETE, DELETE_SUCCESS } from '../../constants/messages';
type TUserModal = { user: TUser };
interface IUserRow {
user: TUser;
openFormDialog: () => void;
setUser: React.Dispatch<React.SetStateAction<TUser | null>>;
reload: boolean;
setReload: React.Dispatch<React.SetStateAction<boolean>>;
}
const UserRow = ({ user }: TUserModal) => {
const handleOnClick = (id: string) => {
alert(`Id: ${id}`);
const UserRow = ({
user,
openFormDialog,
setUser,
reload,
setReload,
}: IUserRow) => {
const handleOnEdit = (user: TUser) => {
setUser(user);
openFormDialog();
};
const handleOnDelete = async (user: TUser) => {
if (confirm(CONFIRM_DELETE)) {
const response = await sendRequest(
USER_PATH + `/${user.id}`,
null,
'DELETE',
);
if (response.statusCode === STATUS_CODE.OK) {
toast.success(DELETE_SUCCESS);
// Reload table
setReload(!reload);
}
}
};
const { id, name, identifiedCode, phone, roomId } = user;
@@ -41,11 +76,11 @@ const UserRow = ({ user }: TUserModal) => {
<Menus.List id={id}>
<Menus.Button
icon={<HiSquare2Stack />}
onClick={() => handleOnClick(id)}
onClick={() => handleOnEdit(user)}
>
Edit
</Menus.Button>
<Menus.Button icon={<HiTrash />} onClick={() => handleOnClick(id)}>
<Menus.Button icon={<HiTrash />} onClick={() => handleOnDelete(user)}>
Delete
</Menus.Button>
</Menus.List>
@@ -56,9 +91,17 @@ const UserRow = ({ user }: TUserModal) => {
interface IUserTable {
reload: boolean;
setReload: React.Dispatch<React.SetStateAction<boolean>>;
openFormDialog: () => void;
setUser?: React.Dispatch<React.SetStateAction<TUser | null>>;
}
const UserTable = ({ reload }: IUserTable) => {
const UserTable = ({
reload,
setReload,
openFormDialog,
setUser,
}: IUserTable) => {
const { data, isPending, errorMsg } = useFetch('users', reload);
const [users, setUsers] = useState<TUser[]>([]);
@@ -94,7 +137,16 @@ const UserTable = ({ reload }: IUserTable) => {
</Table.Header>
<Table.Body<TUser>
data={users}
render={(user: TUser) => <UserRow user={user} key={user.id} />}
render={(user: TUser) => (
<UserRow
user={user}
key={user.id}
reload={reload}
setReload={setReload}
openFormDialog={openFormDialog}
setUser={setUser!}
/>
)}
/>
</Table>
</Menus>
+14 -3
View File
@@ -8,12 +8,16 @@ import UserTable from './Table';
// Styled
import { StyledUser, Title } from './styled';
import UserDialog from './Dialog';
import { TUser } from '../../globals/types';
const User = () => {
const dialogRef = useRef<HTMLDialogElement>();
const [reload, setReload] = useState(true);
const [user, setUser] = useState<TUser | null>(null);
const [isAdd, setIsAdd] = useState(false);
const openDialog = () => {
const openDialog = (isAdd: boolean) => {
setIsAdd(isAdd);
dialogRef.current?.showModal();
};
@@ -26,10 +30,15 @@ const User = () => {
<StyledUser>
<Direction type="horizontal">
<Title>List User</Title>
<Button onClick={openDialog}>Add user</Button>
<Button onClick={() => openDialog(true)}>Add user</Button>
</Direction>
<UserTable reload={reload} />
<UserTable
reload={reload}
setReload={setReload}
openFormDialog={() => openDialog(false)}
setUser={setUser}
/>
</StyledUser>
<UserDialog
@@ -37,6 +46,8 @@ const User = () => {
ref={dialogRef}
setReload={setReload}
reload={reload}
user={user}
isAdd={isAdd}
/>
</>
);