diff --git a/hotel-management/src/commons/styles/Button.ts b/hotel-management/src/commons/styles/Button.ts index 7eb5fed..30d6165 100644 --- a/hotel-management/src/commons/styles/Button.ts +++ b/hotel-management/src/commons/styles/Button.ts @@ -1,7 +1,9 @@ import styled, { css } from 'styled-components'; +type TButtonStyle = 'primary' | 'secondary'; + interface IButtonStyle { - styled?: 'primary' | 'secondary'; + styled?: TButtonStyle; } const Button = styled.button` @@ -11,7 +13,7 @@ const Button = styled.button` font-weight: 600; cursor: pointer; - + border-radius: var(--radius-md); ${(props) => diff --git a/hotel-management/src/commons/styles/ButtonIcon.ts b/hotel-management/src/commons/styles/ButtonIcon.ts index 9653f45..7dc043e 100644 --- a/hotel-management/src/commons/styles/ButtonIcon.ts +++ b/hotel-management/src/commons/styles/ButtonIcon.ts @@ -5,7 +5,7 @@ const ButtonIcon = styled.button` padding: 8px; transition: all 0.2s; - + border: none; border-radius: var(--radius-md); diff --git a/hotel-management/src/commons/styles/CommonInput.ts b/hotel-management/src/commons/styles/CommonInput.ts index 15adb1f..436924d 100644 --- a/hotel-management/src/commons/styles/CommonInput.ts +++ b/hotel-management/src/commons/styles/CommonInput.ts @@ -5,9 +5,9 @@ const CommonInput = css` border-radius: var(--radius-sm); padding: 10px 20px; - + font-size: var(--fs-sm-x); - + width: 200px; `; diff --git a/hotel-management/src/commons/styles/Direction.ts b/hotel-management/src/commons/styles/Direction.ts index 787a6e5..6fe5a18 100644 --- a/hotel-management/src/commons/styles/Direction.ts +++ b/hotel-management/src/commons/styles/Direction.ts @@ -1,7 +1,9 @@ import styled, { css } from 'styled-components'; +type TDirection = 'vertical' | 'horizontal'; + interface IDirection { - type?: 'vertical' | 'horizontal'; + type?: TDirection; } const Direction = styled.div` diff --git a/hotel-management/src/commons/styles/Input.ts b/hotel-management/src/commons/styles/Input.ts index 0826c7e..32e5eb2 100644 --- a/hotel-management/src/commons/styles/Input.ts +++ b/hotel-management/src/commons/styles/Input.ts @@ -3,8 +3,10 @@ import styled, { css } from 'styled-components'; // Styled import CommonInput from './CommonInput'; +type TInput = 'text' | 'checkbox' | 'hidden'; + interface IInputTyped { - type?: 'text' | 'checkbox' | 'hidden'; + type?: TInput; } const Input = styled.input` diff --git a/hotel-management/src/components/Dialog/index.tsx b/hotel-management/src/components/Dialog/index.tsx index 3b42dd7..a58f982 100644 --- a/hotel-management/src/components/Dialog/index.tsx +++ b/hotel-management/src/components/Dialog/index.tsx @@ -16,7 +16,7 @@ export interface IDialogProps { const Dialog = forwardRef( (props: IDialogProps, ref) => { const { title, children, onClose } = props; - + return ( {title} diff --git a/hotel-management/src/components/Search/index.tsx b/hotel-management/src/components/Search/index.tsx index fa747a2..06d3bbb 100644 --- a/hotel-management/src/components/Search/index.tsx +++ b/hotel-management/src/components/Search/index.tsx @@ -1,4 +1,4 @@ -import { memo, useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; // Styled import { StyledSearch } from './styled'; @@ -11,7 +11,7 @@ interface ISearch { setValueSearch: (phone: string) => void; } -const Search = memo(({ setValueSearch, setPlaceHolder }: ISearch) => { +const Search = ({ setValueSearch, setPlaceHolder }: ISearch) => { const [query, setQuery] = useState(''); const debounceValue = useDebounce(query, 700); @@ -25,6 +25,6 @@ const Search = memo(({ setValueSearch, setPlaceHolder }: ISearch) => { placeholder={setPlaceHolder} /> ); -}); +}; export default Search; diff --git a/hotel-management/src/components/Select/index.tsx b/hotel-management/src/components/Select/index.tsx index 5856814..8a59409 100644 --- a/hotel-management/src/components/Select/index.tsx +++ b/hotel-management/src/components/Select/index.tsx @@ -68,7 +68,7 @@ const Select = ({ optionsConfigForm, value, onChange, - ariaLabel + ariaLabel, }: ISelect) => { const { register } = useFormContext() ?? {}; diff --git a/hotel-management/src/components/Sidebar/styled.ts b/hotel-management/src/components/Sidebar/styled.ts index 75e26c6..2973bef 100644 --- a/hotel-management/src/components/Sidebar/styled.ts +++ b/hotel-management/src/components/Sidebar/styled.ts @@ -12,7 +12,7 @@ const Heading = styled.h1` font-size: var(--fs-md); text-transform: uppercase; text-align: center; - + color: var(--primary-color); `; diff --git a/hotel-management/src/components/SortBy/index.tsx b/hotel-management/src/components/SortBy/index.tsx index 023be55..ca85296 100644 --- a/hotel-management/src/components/SortBy/index.tsx +++ b/hotel-management/src/components/SortBy/index.tsx @@ -20,11 +20,11 @@ const SortBy = memo(({ options }: ISortByProps) => { }; return ( - trigger('roomId'), + validate: (v) => v !== 0, }} /> ) : ( @@ -249,7 +234,11 @@ const UserForm = ({ - {isAdd ? 'Add' : 'Save'} + { + isAdd + ? 'Add' + : 'Save' + } Close diff --git a/hotel-management/src/pages/User/Table.tsx b/hotel-management/src/pages/User/Table.tsx index fb95fc5..825faf2 100644 --- a/hotel-management/src/pages/User/Table.tsx +++ b/hotel-management/src/pages/User/Table.tsx @@ -15,7 +15,7 @@ import OrderBy from '../../components/OrderBy'; // Types import { Nullable } from '../../types/common'; -import { TUser } from '../../types/user'; +import { IUser } from '../../types/users'; // Hooks import { useFetch } from '../../hooks/useFetch'; @@ -23,7 +23,7 @@ import { useFetch } from '../../hooks/useFetch'; // Constants import { STATUS_CODE } from '../../constants/responseStatus'; import { ORDERBY_OPTIONS, USER_PAGE } from '../../constants/variables'; -import { CONFIRM_MESSAGE } from '../../constants/messages'; +import { CONFIRM_MESSAGE, DENIED_ACTION } from '../../constants/messages'; // Styled import { StyledOperationTable } from './styled'; @@ -34,9 +34,9 @@ import { updateRoomStatus } from '../../services/roomServices'; import { checkOutUser } from '../../services/userServices'; interface IUserRow { - user: TUser; + user: IUser; openFormDialog: () => void; - setUser: Dispatch>>; + setUser: Dispatch>>; reload: boolean; setReload: Dispatch>; } @@ -48,26 +48,31 @@ const UserRow = ({ reload, setReload, }: IUserRow) => { - const handleEdit = (user: TUser) => { + const handleEdit = (user: IUser) => { setUser(user); openFormDialog(); }; - const handleCheckOut = async (user: TUser) => { - if (confirm(CONFIRM_MESSAGE)) { - const resUpdateStatus = await updateRoomStatus(user.roomId, false); - const resCheckoutUser = await checkOutUser(user); - - if ( - resCheckoutUser?.statusCode === STATUS_CODE.OK && - resUpdateStatus?.statusCode === STATUS_CODE.OK - ) { - toast.success('Check out complete!'); - - // Reload table - setReload(!reload); + const handleCheckOut = async (user: IUser) => { + if(user.roomId !== 0) { + if (confirm(CONFIRM_MESSAGE)) { + const resUpdateStatus = await updateRoomStatus(user.roomId, false); + const resCheckoutUser = await checkOutUser(user); + + if ( + resCheckoutUser?.statusCode === STATUS_CODE.OK && + resUpdateStatus?.statusCode === STATUS_CODE.OK + ) { + toast.success('Check out complete!'); + + // Reload table + setReload(!reload); + } } + } else { + toast.error(DENIED_ACTION); } + }; const { id, name, identifiedCode, phone, roomId } = user; @@ -107,7 +112,7 @@ interface IUserTable { reload: boolean; setReload: Dispatch>; openFormDialog: () => void; - setUser?: Dispatch>>; + setUser?: Dispatch>>; } const UserTable = ({ @@ -116,7 +121,7 @@ const UserTable = ({ openFormDialog, setUser, }: IUserTable) => { - const [users, setUsers] = useState([]); + const [users, setUsers] = useState([]); const [phoneSearch, setPhoneSearch] = useState(''); const [searchParams] = useSearchParams(); const sortByValue = searchParams.get('sortBy') @@ -172,9 +177,9 @@ const UserTable = ({
Phone
Room Id
- + data={users} - render={(user: TUser) => ( + render={(user: IUser) => ( { const dialogRef = useRef(null); const [reload, setReload] = useState(true); - const [user, setUser] = useState>(null); + const [user, setUser] = useState>(null); const [isAdd, setIsAdd] = useState(false); const openFormDialog = (isAddForm: boolean = false) => { diff --git a/hotel-management/src/services/roomServices.ts b/hotel-management/src/services/roomServices.ts index 74dc58a..d258e37 100644 --- a/hotel-management/src/services/roomServices.ts +++ b/hotel-management/src/services/roomServices.ts @@ -2,24 +2,24 @@ import toast from 'react-hot-toast'; // Types import { Nullable } from '../types/common'; -import { TRoom } from '../types/rooms'; -import { TResponse } from '../types/response'; +import { IResponse } from '../types/responses'; +import { IRoom } from '../types/rooms'; // Helpers import { sendRequest } from '../helpers/sendRequest'; +import { errorMsg } from '../helpers/helper'; // Constants import { STATUS_CODE, RESPONSE_MESSAGE } from '../constants/responseStatus'; -import { errorMsg } from '../constants/messages'; import { ROOM_PATH } from '../constants/path'; /** * Get all rooms from server * @returns Return all rooms in server */ -const getAllRoom = async (): Promise> => { +const getAllRoom = async (): Promise> => { try { - const response = await sendRequest(ROOM_PATH); + const response = await sendRequest(ROOM_PATH); if (response.statusCode === STATUS_CODE.OK) { const rooms = response.data!; @@ -42,17 +42,17 @@ const getAllRoom = async (): Promise> => { * @param roomId The id room need to be get * @returns Return the room object depend on room id */ -const getRoom = async (roomId: number): Promise> => { +const getRoom = async (roomId: number): Promise> => { try { - const response = await sendRequest(ROOM_PATH + '/' + roomId); + const response = await sendRequest(ROOM_PATH + '/' + roomId); - if (response.statusCode === STATUS_CODE.OK) { - const rooms = response.data!; - - return rooms; - } else { + if (response.statusCode !== STATUS_CODE.OK) { throw new Error(errorMsg(response.statusCode, response.msg)); } + + const rooms = response.data!; + + return rooms; } catch (error) { if (error instanceof Error) { toast.error(error.message); @@ -67,18 +67,14 @@ const getRoom = async (roomId: number): Promise> => { * @param room Room object need to be updated * @returns The response object */ -const updateRoom = async (room: TRoom): Promise>> => { +const updateRoom = async (room: IRoom): Promise>> => { try { - const response = await sendRequest( + const response = await sendRequest( ROOM_PATH + '/' + room.id, 'PUT', JSON.stringify(room) ); - if (response.statusCode !== STATUS_CODE.OK) { - throw new Error(errorMsg(response.statusCode, response.msg)); - } - return response; } catch (error: unknown) { if (error instanceof Error) { @@ -100,45 +96,78 @@ const updateRoomStatus = async ( roomId: number, status: boolean, roomIdNew?: number -): Promise>> => { - if (!roomIdNew) { - const response = await sendRequest( - ROOM_PATH + '/' + roomId, +): Promise>> => { + try { + if (!roomIdNew) { + const response = await sendRequest( + ROOM_PATH + '/' + roomId, + 'PATCH', + JSON.stringify({ status: status }) + ); + + return response; + } + + // Update new room status + const resNewRoom = await sendRequest( + ROOM_PATH + '/' + roomIdNew, 'PATCH', JSON.stringify({ status: status }) ); - return response; - } - - // Update new room status - const resNewRoom = await sendRequest( - ROOM_PATH + '/' + roomIdNew, - 'PATCH', - JSON.stringify({ status: status }) - ); + // Update old room status; + const resOldRoom = await sendRequest( + ROOM_PATH + '/' + roomId, + 'PATCH', + JSON.stringify({ status: !status }) + ); - // Update old room status; - const resOldRoom = await sendRequest( - ROOM_PATH + '/' + roomId, - 'PATCH', - JSON.stringify({ status: !status }) - ); - - if ( - resNewRoom.statusCode === STATUS_CODE.OK && - resOldRoom.statusCode === STATUS_CODE.OK - ) { - return { - statusCode: STATUS_CODE.OK, - msg: RESPONSE_MESSAGE.UPDATE_SUCCESS, - }; + if ( + resNewRoom.statusCode === STATUS_CODE.OK && + resOldRoom.statusCode === STATUS_CODE.OK + ) { + return { + statusCode: STATUS_CODE.OK, + msg: RESPONSE_MESSAGE.UPDATE_SUCCESS, + }; + } + } catch (error) { + if (error instanceof Error) { + toast.error(error.message); + } } - return { - statusCode: STATUS_CODE.INTERNAL_SERVER_ERROR, - msg: 'Something went wrong!', - }; + return null; }; -export { getRoom, updateRoom, updateRoomStatus, getAllRoom }; +/** + * Add room to server + * @param room The room object need to be add + * @returns The response object if complete or null + */ +const addRoom = async (room: IRoom): Promise>> => { + try { + // Set default status room + room.status = false; + + const response = await sendRequest( + ROOM_PATH, + 'POST', + JSON.stringify(room) + ); + + if (response.statusCode !== STATUS_CODE.CREATE) { + throw new Error(errorMsg(response.statusCode, response.msg)); + } + + return response; + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + + return null; +}; + +export { getRoom, updateRoom, updateRoomStatus, getAllRoom, addRoom }; diff --git a/hotel-management/src/services/userServices.ts b/hotel-management/src/services/userServices.ts index fedacd0..ae43f86 100644 --- a/hotel-management/src/services/userServices.ts +++ b/hotel-management/src/services/userServices.ts @@ -1,21 +1,53 @@ import toast from 'react-hot-toast'; // Constants -import { errorMsg } from '../constants/messages'; import { USER_PATH } from '../constants/path'; import { STATUS_CODE } from '../constants/responseStatus'; // Types import { Nullable } from '../types/common'; -import { TUser } from '../types/user'; -import { TResponse } from '../types/response'; +import { IResponse } from '../types/responses'; +import { IUser } from '../types/users'; // Helpers import { sendRequest } from '../helpers/sendRequest'; +import { errorMsg } from '../helpers/helper'; -const updateUser = async (user: TUser): Promise>> => { +/** + * Create user to the server + * @param user The user object need to be created + * @returns The IResponse object if success or null + */ +const createUser = async (user: IUser): Promise>> => { try { - const response = await sendRequest( + const response = await sendRequest( + USER_PATH, + 'POST', + JSON.stringify(user) + ); + + if (response.statusCode !== STATUS_CODE.CREATE) { + throw new Error(errorMsg(response.statusCode, response.msg)); + } + + return response; + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + + return null; +} + +/** + * Update the user to the server + * @param user The user object need to be updated + * @returns The IResponse object if update success or null + */ +const updateUser = async (user: IUser): Promise>> => { + try { + const response = await sendRequest( USER_PATH + '/' + user.id, 'PUT', JSON.stringify(user) @@ -35,7 +67,12 @@ const updateUser = async (user: TUser): Promise>> => { return null; }; -const checkOutUser = async (user: TUser): Promise>> => { +/** + * Checkout user + * @param user The user need to be checkout + * @returns The IResponse object if checkout success or not + */ +const checkOutUser = async (user: IUser): Promise>> => { const tempUser = user; if (tempUser) { @@ -48,4 +85,4 @@ const checkOutUser = async (user: TUser): Promise>> => return null; }; -export { updateUser, checkOutUser }; +export { updateUser, checkOutUser, createUser }; diff --git a/hotel-management/src/types/response.ts b/hotel-management/src/types/response.ts deleted file mode 100644 index 21085b8..0000000 --- a/hotel-management/src/types/response.ts +++ /dev/null @@ -1,7 +0,0 @@ -type TResponse = { - statusCode: number; - msg: string; - data?: T; -}; - -export type { TResponse }; diff --git a/hotel-management/src/types/responses.ts b/hotel-management/src/types/responses.ts new file mode 100644 index 0000000..2ea9981 --- /dev/null +++ b/hotel-management/src/types/responses.ts @@ -0,0 +1,7 @@ +interface IResponse { + statusCode: number; + msg: string; + data?: T; +} + +export type { IResponse }; diff --git a/hotel-management/src/types/rooms.ts b/hotel-management/src/types/rooms.ts index 0672efb..4b6cd19 100644 --- a/hotel-management/src/types/rooms.ts +++ b/hotel-management/src/types/rooms.ts @@ -1,10 +1,10 @@ -type TRoom = { +interface IRoom { id: number; name: string; price: number; discount: number; finalPrice: number; status: boolean; -}; +} -export type { TRoom }; +export type { IRoom }; diff --git a/hotel-management/src/types/user.ts b/hotel-management/src/types/users.ts similarity index 68% rename from hotel-management/src/types/user.ts rename to hotel-management/src/types/users.ts index fff1e20..6d4a5b2 100644 --- a/hotel-management/src/types/user.ts +++ b/hotel-management/src/types/users.ts @@ -1,9 +1,9 @@ -type TUser = { +interface IUser { id: number; name: string; identifiedCode: string; phone: string; roomId: number; -}; +} -export type { TUser }; +export type { IUser };