From b0dd3abf0e472c5361c113d525b658ccecb313f1 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Sun, 5 Nov 2023 12:25:01 +0700 Subject: [PATCH] Fix asynchronous error --- .../src/components/Dialog/index.tsx | 14 +-- hotel-management/src/hooks/useForwardRef.ts | 22 ++++ hotel-management/src/pages/Room/Dialog.tsx | 22 ++-- hotel-management/src/pages/Room/index.tsx | 2 +- hotel-management/src/pages/User/Dialog.tsx | 24 ++-- hotel-management/src/pages/User/Form.tsx | 112 ++++++++++-------- hotel-management/src/pages/User/Table.tsx | 11 +- hotel-management/src/pages/User/index.tsx | 4 +- 8 files changed, 127 insertions(+), 84 deletions(-) create mode 100644 hotel-management/src/hooks/useForwardRef.ts diff --git a/hotel-management/src/components/Dialog/index.tsx b/hotel-management/src/components/Dialog/index.tsx index d3b010d..d7b545b 100644 --- a/hotel-management/src/components/Dialog/index.tsx +++ b/hotel-management/src/components/Dialog/index.tsx @@ -3,19 +3,15 @@ import { forwardRef } from 'react'; // Styled import { StyledBody, StyledDialog, StyledTitle } from './styled'; -export interface IDialogProps { +export interface IDialogProps { title?: string; children?: JSX.Element[] | JSX.Element; onClose?: () => void; - reload?: boolean; - setReload?: React.Dispatch>; - ref?: React.MutableRefObject; - data?: T | null; - isAdd?: boolean; + ref?: React.MutableRefObject; } -const Dialog = forwardRef((props, ref) => { - const { title, children, onClose } = props as IDialogProps; +const Dialog = forwardRef((props: IDialogProps, ref) => { + const { title, children, onClose } = props; return ( | undefined} @@ -25,6 +21,6 @@ const Dialog = forwardRef((props, ref) => { {children} ); -}) as React.FC>; +}); export default Dialog; diff --git a/hotel-management/src/hooks/useForwardRef.ts b/hotel-management/src/hooks/useForwardRef.ts new file mode 100644 index 0000000..ab9ee93 --- /dev/null +++ b/hotel-management/src/hooks/useForwardRef.ts @@ -0,0 +1,22 @@ +import { ForwardedRef, useEffect, useRef } from 'react'; + +const useForwardRef = ( + ref: ForwardedRef, + initialValue: T | null = null +) => { + const targetRef = useRef(initialValue); + + useEffect(() => { + if (!ref) return; + + if (typeof ref === 'function') { + ref(targetRef.current); + } else { + ref.current = targetRef.current; + } + }, [ref]); + + return targetRef; +}; + +export { useForwardRef }; diff --git a/hotel-management/src/pages/Room/Dialog.tsx b/hotel-management/src/pages/Room/Dialog.tsx index 2b08d17..0aa69ba 100644 --- a/hotel-management/src/pages/Room/Dialog.tsx +++ b/hotel-management/src/pages/Room/Dialog.tsx @@ -1,13 +1,21 @@ import { forwardRef, useEffect } from 'react'; // Components -import Dialog, { IDialogProps } from '../../components/Dialog'; +import Dialog from '../../components/Dialog'; import RoomForm from './Form'; - -// Types import { TRoom } from '../../globals/types'; -const RoomDialog = forwardRef((props, ref) => { + +interface IRoomDialog { + onClose?: () => void; + reload?: boolean; + setReload?: React.Dispatch>; + ref?: React.MutableRefObject; + room?: TRoom | null; + isAdd?: boolean; +} + +const RoomDialog = forwardRef((props: IRoomDialog, ref) => { const dialogRef = ref as React.MutableRefObject< HTMLDialogElement | undefined >; @@ -16,7 +24,7 @@ const RoomDialog = forwardRef((props, ref) => { onClose, setReload, reload, - data, + room, isAdd } = props; @@ -42,11 +50,11 @@ const RoomDialog = forwardRef((props, ref) => { onClose={onClose!} reload={reload!} setReload={setReload!} - room={data} + room={room} isAdd={isAdd!} /> ); -}) as React.FC>; +}); export default RoomDialog; diff --git a/hotel-management/src/pages/Room/index.tsx b/hotel-management/src/pages/Room/index.tsx index 84da1a0..24b1498 100644 --- a/hotel-management/src/pages/Room/index.tsx +++ b/hotel-management/src/pages/Room/index.tsx @@ -48,7 +48,7 @@ const Room = () => { ref={dialogRef} setReload={setReload} reload={reload} - data={room} + room={room} isAdd={isAdd} /> diff --git a/hotel-management/src/pages/User/Dialog.tsx b/hotel-management/src/pages/User/Dialog.tsx index c995b12..7dd9a8a 100644 --- a/hotel-management/src/pages/User/Dialog.tsx +++ b/hotel-management/src/pages/User/Dialog.tsx @@ -1,24 +1,32 @@ import { forwardRef, useEffect } from 'react'; // Components -import Dialog, { IDialogProps } from '../../components/Dialog'; +import Dialog from '../../components/Dialog'; import UserForm from './Form'; // Types import { TUser } from '../../globals/types'; +import { useForwardRef } from '../../hooks/useForwardRef'; + +interface IUserDialog { + onClose: () => void; + reload: boolean; + setReload: React.Dispatch>; + ref: React.MutableRefObject; + user: TUser | null; + isAdd: boolean; +} const UserDialog = forwardRef((props, ref) => { - const dialogRef = ref as React.MutableRefObject< - HTMLDialogElement | undefined - >; + const dialogRef = useForwardRef(ref); // prettier-ignore const { onClose, setReload, reload, - data, - isAdd + user, + isAdd, } = props; useEffect(() => { @@ -43,11 +51,11 @@ const UserDialog = forwardRef((props, ref) => { onClose={onClose!} reload={reload!} setReload={setReload!} - user={data} + user={user} isAdd={isAdd!} /> ); -}) as React.FC>; +}) as React.FC; export default UserDialog; diff --git a/hotel-management/src/pages/User/Form.tsx b/hotel-management/src/pages/User/Form.tsx index a89a672..4582dfa 100644 --- a/hotel-management/src/pages/User/Form.tsx +++ b/hotel-management/src/pages/User/Form.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import toast from 'react-hot-toast'; import { FormProvider, useForm } from 'react-hook-form'; @@ -38,14 +38,14 @@ import { REQUIRED_FIELD_ERROR, } from '../../constants/formValidateMessage.ts'; import { getAllRoom, updateRoomStatus } from '../../services/roomServices.ts'; -import { TUser } from '../../globals/types.ts'; +import { TRoom, TUser } from '../../globals/types.ts'; import { INIT_VALUE_USER_FORM } from '../../constants/variables.ts'; interface IUserFormProp { onClose: () => void; reload: boolean; setReload: React.Dispatch>; - user?: TUser | null; + user: TUser | null; isAdd: boolean; } @@ -64,19 +64,17 @@ const UserForm = ({ formState: { errors, isDirty, isValid }, trigger, } = formMethods; + const [rooms, setRooms] = useState([]); const [options, setOptions] = useState(); // Init value when edit form and load options useEffect(() => { const load = async () => { - const rooms = await getAllRoom(); const options: ISelectOptions[] = []; - const tempUser = isAdd - ? {} - : {...user}; + const tempUser = isAdd ? {} : { ...user }; // Load and set default options room - if (rooms) { + if (rooms.length > 0) { rooms.forEach((item) => { if (!item.status || tempUser?.roomId === item.id) options.push({ @@ -103,55 +101,71 @@ const UserForm = ({ }; load(); - }, [reset, user, isAdd]); + }, [reset, user, isAdd, rooms]); // Submit form - const onSubmit = async (newUser: TUser) => { - try { - if (isAdd) { - // Add request - const response = await sendRequest( - USER_PATH, - 'POST', - JSON.stringify(newUser) - ); + const onSubmit = useCallback( + async (newUser: TUser) => { + try { + if (isAdd) { + // Add request + const response = await sendRequest( + USER_PATH, + 'POST', + JSON.stringify(newUser) + ); - if (response.statusCode === STATUS_CODE.CREATE) { - toast.success(ADD_SUCCESS); + if (response.statusCode === STATUS_CODE.CREATE) { + toast.success(ADD_SUCCESS); + } else { + throw new Error(errorMsg(response.statusCode, response.msg)); + } + + // Update room status + updateRoomStatus(newUser.roomId, true); } else { - throw new Error(errorMsg(response.statusCode, response.msg)); + // Edit request + const response = await sendRequest( + USER_PATH + `/${newUser.id}`, + 'PUT', + JSON.stringify(newUser) + ); + + if (response.statusCode == STATUS_CODE.OK) { + toast.success(EDIT_SUCCESS); + } else { + throw new Error(errorMsg(response.statusCode, response.msg)); + } + + // Update room status + updateRoomStatus(user!.roomId, true, newUser.roomId); } - - // Update room status - updateRoomStatus(newUser.roomId, true); - } else { - // Edit request - const response = await sendRequest( - USER_PATH + `/${newUser.id}`, - 'PUT', - JSON.stringify(newUser) - ); - - if (response.statusCode == STATUS_CODE.OK) { - toast.success(EDIT_SUCCESS); - } else { - throw new Error(errorMsg(response.statusCode, response.msg)); + // Reload table data + setReload(!reload); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); } - - // Update room status - updateRoomStatus(user!.roomId, true, newUser.roomId); } - // Reload table data - setReload(!reload); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - } - } - reset(); - onClose(); - }; + reset(); + onClose(); + }, + [isAdd, onClose, reload, reset, setReload, user] + ); + + // Load all rooms + useEffect(() => { + const loadRoom = async () => { + const rooms = await getAllRoom(); + + if (rooms) { + setRooms(rooms); + } + }; + + loadRoom(); + }, [onSubmit]); return ( diff --git a/hotel-management/src/pages/User/Table.tsx b/hotel-management/src/pages/User/Table.tsx index 3d63624..a12d302 100644 --- a/hotel-management/src/pages/User/Table.tsx +++ b/hotel-management/src/pages/User/Table.tsx @@ -75,11 +75,7 @@ const UserRow = ({
{name}
{identifiedCode}
{phone}
-
{ - roomId - ? roomId - : 'None' - }
+
{roomId ? roomId : 'None'}
@@ -116,9 +112,9 @@ const UserTable = ({ openFormDialog, setUser, }: IUserTable) => { + const [users, setUsers] = useState([]); const [phoneSearch, setPhoneSearch] = useState(''); const [searchParams] = useSearchParams(); - const [users, setUsers] = useState([]); const sortByValue = searchParams.get('sortBy') ? searchParams.get('sortBy')! : ''; @@ -145,8 +141,7 @@ const UserTable = ({ if (errorFetchMsg) { console.error(errorFetchMsg); } - }, [data, errorFetchMsg]); - + }, [data, errorFetchMsg, setUsers]); return ( <> diff --git a/hotel-management/src/pages/User/index.tsx b/hotel-management/src/pages/User/index.tsx index b18d3be..7703a29 100644 --- a/hotel-management/src/pages/User/index.tsx +++ b/hotel-management/src/pages/User/index.tsx @@ -13,7 +13,7 @@ import UserDialog from './Dialog'; import { TUser } from '../../globals/types'; const User = () => { - const dialogRef = useRef(); + const dialogRef = useRef(null); const [reload, setReload] = useState(true); const [user, setUser] = useState(null); const [isAdd, setIsAdd] = useState(false); @@ -48,7 +48,7 @@ const User = () => { ref={dialogRef} setReload={setReload} reload={reload} - data={user} + user={user} isAdd={isAdd} />