diff --git a/hotel-management/src/commons/styles/Button.ts b/hotel-management/src/commons/styles/Button.ts index 11d30f4..7eb5fed 100644 --- a/hotel-management/src/commons/styles/Button.ts +++ b/hotel-management/src/commons/styles/Button.ts @@ -11,7 +11,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 110fea7..9653f45 100644 --- a/hotel-management/src/commons/styles/ButtonIcon.ts +++ b/hotel-management/src/commons/styles/ButtonIcon.ts @@ -2,9 +2,11 @@ import styled from 'styled-components'; const ButtonIcon = styled.button` background: none; - border: none; + padding: 8px; transition: all 0.2s; + + border: none; border-radius: var(--radius-md); &:hover { diff --git a/hotel-management/src/commons/styles/CommonInput.ts b/hotel-management/src/commons/styles/CommonInput.ts index d854062..15adb1f 100644 --- a/hotel-management/src/commons/styles/CommonInput.ts +++ b/hotel-management/src/commons/styles/CommonInput.ts @@ -3,9 +3,11 @@ import { css } from 'styled-components'; const CommonInput = css` border: 1px solid var(--border-color); border-radius: var(--radius-sm); - padding: 10px 20px; - font-size: var(--fs-sm-x); + padding: 10px 20px; + + font-size: var(--fs-sm-x); + width: 200px; `; diff --git a/hotel-management/src/components/AppLayout/styled.ts b/hotel-management/src/components/AppLayout/styled.ts index 87fbadd..90bbd79 100644 --- a/hotel-management/src/components/AppLayout/styled.ts +++ b/hotel-management/src/components/AppLayout/styled.ts @@ -4,6 +4,7 @@ const StyledAppLayout = styled.div` display: grid; grid-template-columns: 300px 1fr; grid-template-rows: auto 1fr; + height: 100vh; `; diff --git a/hotel-management/src/components/Dialog/index.tsx b/hotel-management/src/components/Dialog/index.tsx index d7b545b..53b09eb 100644 --- a/hotel-management/src/components/Dialog/index.tsx +++ b/hotel-management/src/components/Dialog/index.tsx @@ -1,26 +1,29 @@ -import { forwardRef } from 'react'; +import { MutableRefObject, ReactNode, forwardRef } from 'react'; // Styled import { StyledBody, StyledDialog, StyledTitle } from './styled'; +// Type +import { Nullable } from '../../globals/types'; + export interface IDialogProps { title?: string; - children?: JSX.Element[] | JSX.Element; + children?: ReactNode; onClose?: () => void; - ref?: React.MutableRefObject; + ref?: MutableRefObject>; } -const Dialog = forwardRef((props: IDialogProps, ref) => { - const { title, children, onClose } = props; - return ( - | undefined} - onClose={onClose} - > - {title} - {children} - - ); -}); +const Dialog = forwardRef( + (props: IDialogProps, ref) => { + const { title, children, onClose } = props; + + return ( + + {title} + {children} + + ); + } +); export default Dialog; diff --git a/hotel-management/src/components/Form/index.tsx b/hotel-management/src/components/Form/index.tsx index 5fe4a93..99e2782 100644 --- a/hotel-management/src/components/Form/index.tsx +++ b/hotel-management/src/components/Form/index.tsx @@ -1,9 +1,11 @@ +import { FormEvent, ReactNode } from 'react'; + // Styled import { StyledActionBtn, StyledForm } from './styled'; interface IFormProps { - children: JSX.Element | JSX.Element[]; - onSubmit: (event: React.FormEvent) => void; + children: ReactNode; + onSubmit: (event: FormEvent) => void; id?: string; } diff --git a/hotel-management/src/components/Header/styled.ts b/hotel-management/src/components/Header/styled.ts index 304040e..9ba8124 100644 --- a/hotel-management/src/components/Header/styled.ts +++ b/hotel-management/src/components/Header/styled.ts @@ -2,6 +2,7 @@ import styled from 'styled-components'; const StyledHeader = styled.header` border-bottom: 1px solid var(--border-color); + padding: 20px 40px; display: flex; diff --git a/hotel-management/src/components/LabelControl/index.tsx b/hotel-management/src/components/LabelControl/index.tsx index 11b62ae..cb57530 100644 --- a/hotel-management/src/components/LabelControl/index.tsx +++ b/hotel-management/src/components/LabelControl/index.tsx @@ -1,10 +1,12 @@ +import { ReactNode } from 'react'; + // Styled import { Error, Label, StyledFormRow } from './styled'; interface IFormRow { label: string; error?: string; - children: JSX.Element | JSX.Element[]; + children: ReactNode; } const FormRow = ({ label, error, children }: IFormRow) => { diff --git a/hotel-management/src/components/LabelControl/styled.ts b/hotel-management/src/components/LabelControl/styled.ts index d37bbf4..587fabc 100644 --- a/hotel-management/src/components/LabelControl/styled.ts +++ b/hotel-management/src/components/LabelControl/styled.ts @@ -15,8 +15,10 @@ const Label = styled.label` const Error = styled.p` color: var(--error-text); font-size: var(--fs-sm-2x); + margin-top: 5px; padding-inline: 5px; + width: 220px; `; diff --git a/hotel-management/src/components/Menus/index.tsx b/hotel-management/src/components/Menus/index.tsx index c490e3e..afff48b 100644 --- a/hotel-management/src/components/Menus/index.tsx +++ b/hotel-management/src/components/Menus/index.tsx @@ -1,22 +1,28 @@ -import { useContext, useState } from 'react'; +import { MouseEvent, ReactNode, useContext, useState } from 'react'; // Components import { HiEllipsisVertical } from 'react-icons/hi2'; + +// Hooks import { useOutsideClick } from '../../hooks/useOutsideClick'; + +// Styled import { StyledMenu, StyledButton, StyledList, StyledToggle } from './styled'; // Contexts import MenusContext from '../../contexts/MenuContext'; +// Types +import { Nullable } from '../../globals/types'; + interface IButton { children?: string; - icon?: JSX.Element; + icon?: ReactNode; onClick?: () => void; } -const Menus = ({ children }: { children: JSX.Element }) => { +const Menus = ({ children }: { children: ReactNode }) => { const [openId, setOpenId] = useState(''); - const close = () => setOpenId(''); const open = setOpenId; @@ -27,13 +33,14 @@ const Menus = ({ children }: { children: JSX.Element }) => { ); }; -const Toggle = ({ id }: { id: string }): React.JSX.Element => { +const Toggle = ({ id }: { id: string }): ReactNode => { const { openId, close, open } = useContext(MenusContext); - - const handleClick = (e: React.MouseEvent) => { + const handleClick = (e: MouseEvent) => { e.stopPropagation(); - openId === '' || openId !== id ? open!(id) : close!(); + openId === '' || openId !== id + ? open!(id) + : close!(); }; return ( @@ -48,8 +55,8 @@ const List = ({ children, }: { id: string; - children: JSX.Element[]; -}): React.JSX.Element | null => { + children: ReactNode; +}): Nullable => { const { openId, close } = useContext(MenusContext); const ref = useOutsideClick(close!, false); @@ -58,9 +65,8 @@ const List = ({ return {children}; }; -const Button = ({ children, icon, onClick }: IButton): React.JSX.Element => { +const Button = ({ children, icon, onClick }: IButton): ReactNode => { const { close } = useContext(MenusContext); - const handleClick = () => { onClick?.(); close!(); diff --git a/hotel-management/src/components/Message/styled.ts b/hotel-management/src/components/Message/styled.ts index 10cc192..2f1d2bd 100644 --- a/hotel-management/src/components/Message/styled.ts +++ b/hotel-management/src/components/Message/styled.ts @@ -3,6 +3,7 @@ import styled from 'styled-components'; const StyledMessage = styled.p` font-size: var(--fs-sm); text-align: center; + padding: 20px; `; diff --git a/hotel-management/src/components/OrderBy/index.tsx b/hotel-management/src/components/OrderBy/index.tsx index e8f0716..c24df2e 100644 --- a/hotel-management/src/components/OrderBy/index.tsx +++ b/hotel-management/src/components/OrderBy/index.tsx @@ -13,10 +13,8 @@ interface IOrderProps { const OrderBy = memo(({ options }: IOrderProps) => { const field = 'orderBy'; - const [searchParams, setSearchParams] = useSearchParams(); const currentOrder = searchParams.get(field) || options[0].value; - const handleClick = (value: string) => { searchParams.set(field, value); diff --git a/hotel-management/src/components/OrderBy/styled.ts b/hotel-management/src/components/OrderBy/styled.ts index ea3325b..bfbfa56 100644 --- a/hotel-management/src/components/OrderBy/styled.ts +++ b/hotel-management/src/components/OrderBy/styled.ts @@ -14,8 +14,16 @@ interface IOrderBtn { const OrderButton = styled.button` border: none; - cursor: pointer; + border-radius: var(--radius-sm); + cursor: pointer; + transition: all 0.3s; + + font-weight: 500; + font-size: var(--fs-sm-x); + + padding: 5px 10px; + ${(props) => props.active && css` @@ -24,12 +32,6 @@ const OrderButton = styled.button` cursor: no-drop; `} - border-radius: var(--radius-sm); - font-weight: 500; - font-size: var(--fs-sm-x); - padding: 5px 10px; - transition: all 0.3s; - &:hover:not(:disabled) { background-color: var(--hover-dark-background-color); } diff --git a/hotel-management/src/components/Search/index.tsx b/hotel-management/src/components/Search/index.tsx index 544a832..fa747a2 100644 --- a/hotel-management/src/components/Search/index.tsx +++ b/hotel-management/src/components/Search/index.tsx @@ -1,6 +1,11 @@ import { memo, useEffect, useState } from 'react'; + +// Styled import { StyledSearch } from './styled'; +// Hooks +import { useDebounce } from '../../hooks/useDebounce'; + interface ISearch { setPlaceHolder: string; setValueSearch: (phone: string) => void; @@ -8,14 +13,11 @@ interface ISearch { const Search = memo(({ setValueSearch, setPlaceHolder }: ISearch) => { const [query, setQuery] = useState(''); + const debounceValue = useDebounce(query, 700); useEffect(() => { - const timeOut = setTimeout(() => { - setValueSearch(query); - }, 500); - - return () => clearTimeout(timeOut); - }, [setValueSearch, query]); + setValueSearch(debounceValue); + }, [debounceValue, setValueSearch]); return ( | undefined; value?: string; - onChange?: React.ChangeEventHandler | undefined; + onChange?: ChangeEventHandler | undefined; id?: string; ariaLabel: string; } diff --git a/hotel-management/src/components/Sidebar/styled.ts b/hotel-management/src/components/Sidebar/styled.ts index 23053b5..75e26c6 100644 --- a/hotel-management/src/components/Sidebar/styled.ts +++ b/hotel-management/src/components/Sidebar/styled.ts @@ -4,6 +4,7 @@ const StyledSidebar = styled.aside` padding: 50px 20px; grid-row: 1 / 3; + border: 1px solid var(--border-color); `; @@ -11,6 +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 def89c0..023be55 100644 --- a/hotel-management/src/components/SortBy/index.tsx +++ b/hotel-management/src/components/SortBy/index.tsx @@ -1,5 +1,5 @@ import { useSearchParams } from 'react-router-dom'; -import { memo } from 'react'; +import { ChangeEvent, memo } from 'react'; // Components import Select from '../Select'; @@ -14,8 +14,7 @@ interface ISortByProps { const SortBy = memo(({ options }: ISortByProps) => { const [searchParams, setSearchParams] = useSearchParams(); const sortBy = searchParams.get('sortBy') || ''; - - const handleChange = (event: React.ChangeEvent) => { + const handleChange = (event: ChangeEvent) => { searchParams.set('sortBy', event.target.value); setSearchParams(searchParams); }; diff --git a/hotel-management/src/components/Table/index.tsx b/hotel-management/src/components/Table/index.tsx index d305dc7..bb6107c 100644 --- a/hotel-management/src/components/Table/index.tsx +++ b/hotel-management/src/components/Table/index.tsx @@ -8,12 +8,12 @@ import TableContext from '../../contexts/TableContext'; export interface ITable { columns?: string; - children: React.ReactNode; + children: ReactNode; } interface ITableBody { data?: T[]; - render?: (value: T) => JSX.Element; + render?: CallbackMapFunc; } type CallbackMapFunc = (value: T, index: number, array: T[]) => ReactNode; @@ -28,6 +28,7 @@ const Table = ({ columns, children }: ITable) => { const Header = ({ children }: ITable) => { const { columns } = useContext(TableContext); + return {children}; }; @@ -41,6 +42,7 @@ const Body = ({ data, render }: ITableBody) => { const Row = ({ children }: ITable) => { const { columns } = useContext(TableContext); + return {children}; }; diff --git a/hotel-management/src/components/Table/styled.ts b/hotel-management/src/components/Table/styled.ts index 9219f55..9b1f31e 100644 --- a/hotel-management/src/components/Table/styled.ts +++ b/hotel-management/src/components/Table/styled.ts @@ -1,11 +1,13 @@ import styled from 'styled-components'; + +// Interfaces import { ITable } from '.'; const StyledTable = styled.div` border: 1px solid var(--border-color); + border-radius: var(--radius-md); font-size: 20px; - border-radius: var(--radius-md); `; const CommonRow = styled.div` diff --git a/hotel-management/src/constants/variables.ts b/hotel-management/src/constants/variables.ts index a2180fb..98558b2 100644 --- a/hotel-management/src/constants/variables.ts +++ b/hotel-management/src/constants/variables.ts @@ -1,11 +1,10 @@ -// prettier-ignore const USER_PAGE = { SORTBY_OPTIONS: [ - { + { value: 'id', label: 'Sort by id', }, - { + { value: 'name', label: 'Sort by name', }, @@ -13,11 +12,11 @@ const USER_PAGE = { value: 'identifiedCode', label: 'Sort by identified code', }, - { + { value: 'phone', label: 'Sort by phone', }, - { + { value: 'roomId', label: 'Sort by room', }, @@ -35,24 +34,22 @@ const ORDERBY_OPTIONS = [ }, ]; -// prettier-ignore const ROOM_PAGE = { SORTBY_OPTIONS: [ - { + { value: 'id', label: 'Sort by id', }, - { + { value: 'name', label: 'Sort by name', }, - { - value: 'price', + { + value: 'finalPrice', label: 'Sort by price', }, ], -} - +}; const VALUE = 'value'; const ERROR = 'error'; @@ -70,5 +67,5 @@ export { VALUE, ERROR, ORDERBY_OPTIONS, - INIT_VALUE_USER_FORM + INIT_VALUE_USER_FORM, }; diff --git a/hotel-management/src/contexts/MenuContext.ts b/hotel-management/src/contexts/MenuContext.ts index 0a166dc..08ce3c5 100644 --- a/hotel-management/src/contexts/MenuContext.ts +++ b/hotel-management/src/contexts/MenuContext.ts @@ -1,9 +1,9 @@ -import { createContext } from 'react'; +import { Dispatch, SetStateAction, createContext } from 'react'; interface IMenusContext { openId?: string; close?: () => void; - open?: React.Dispatch>; + open?: Dispatch>; } const MenusContext = createContext({}); diff --git a/hotel-management/src/globals/types.ts b/hotel-management/src/globals/types.ts index 67f2ea6..4d15334 100644 --- a/hotel-management/src/globals/types.ts +++ b/hotel-management/src/globals/types.ts @@ -11,49 +11,21 @@ type TRoom = { name: string; price: number; discount: number; + finalPrice: number; status: boolean; }; -type TStateSchema = { - [key: string]: { - value?: string; - error?: string; - }; -}; - -type TKeyValue = { - [key: string]: boolean | undefined | string; -}; - -type TKeyString = { - [key: string]: string; -}; - -type TPropValues = 'value' | 'error' | boolean; - -type TValidator = { - [key: string]: { - required?: boolean; - validator?: { - func?: (value: string) => boolean; - error?: string; - }; - }; -}; - type TResponse = { statusCode: number; msg: string; data?: T; }; +type Nullable = T | null; + export type { TUser, TRoom, - TStateSchema, - TKeyValue, - TKeyString, - TPropValues, - TValidator, TResponse, + Nullable, }; diff --git a/hotel-management/src/helpers/sendRequest.ts b/hotel-management/src/helpers/sendRequest.ts index 7f3cd06..e851cd1 100644 --- a/hotel-management/src/helpers/sendRequest.ts +++ b/hotel-management/src/helpers/sendRequest.ts @@ -13,26 +13,25 @@ type TMethodRequest = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; * @param method HTTP method * @returns The status code and message from server */ -export const sendRequest = async ( +export const sendRequest = async ( path: string, method: TMethodRequest = 'GET', - body?: BodyInit, + body?: BodyInit ): Promise> => { const response = await fetch(BASE_URL + path, { method, body, headers: { - // prettier-ignore 'Accept': 'application/json', 'Content-Type': 'application/json', }, }); - const data = await response.json() as T; + const data = (await response.json()) as T; return { statusCode: response.status, msg: response.statusText, - data + data, }; }; diff --git a/hotel-management/src/helpers/utils.ts b/hotel-management/src/helpers/utils.ts index 2f2dce8..3b890d0 100644 --- a/hotel-management/src/helpers/utils.ts +++ b/hotel-management/src/helpers/utils.ts @@ -1,23 +1,6 @@ // Constants import { REQUIRED_FIELD_ERROR } from '../constants/formValidateMessage'; -// Types -import { - TKeyString, - TKeyValue, - TPropValues, - TStateSchema, -} from '../globals/types'; - -/** - * The function check value has type boolean or not - * @param value The value need to checked - * @returns A boolean indicating whether or not the argument has type boolean - */ -const isBool = (value: unknown) => { - return typeof value === 'boolean'; -}; - /** * Set required error for value * @param value The value set required or not @@ -29,50 +12,6 @@ const isRequired = (value: string | number, isRequired: unknown) => { return ''; }; -/** - * Get values from props - * @param stateSchema StateSchema value - * @param prop Prop value (Has 3 type: boolean | "value" | "error") - * @returns Return value object depend on props - */ -const getPropValues = (stateSchema: TStateSchema, prop?: TPropValues) => { - return Object.keys(stateSchema).reduce((field, key) => { - field[key] = isBool(prop) - ? prop - : stateSchema[key][prop as Exclude]; - - return field; - }, {} as TKeyValue); -}; - -/** - * Return the object contains values of object pass - * @param obj Object need to get value - * @returns The object contains value of object - */ -const getValueFromObj = (obj: T | null = null): TKeyString => { - let result = {}; - - if (obj) { - for (const key of Object.keys(obj)) { - const tempValue = obj[key as keyof typeof obj]; - let value: string | boolean = ''; - - if (typeof tempValue === 'string' || typeof tempValue === 'boolean') { - value = tempValue; - } - - if (typeof tempValue === 'number') { - value = tempValue.toString(); - } - - result = { ...result, [`${key}Value`]: value }; - } - } - - return result; -}; - /** * Create query url for search * @param columnSearch Column want to search @@ -87,11 +26,15 @@ const searchQuery = ( sort: string, order: string ) => { - const phoneParams = keySearch ? `${columnSearch}_like=` + keySearch : ''; - - const sortParams = sort ? '_sort=' + sort : ''; - - const orderParams = order ? '_order=' + order : ''; + const phoneParams = keySearch + ? `${columnSearch}_like=` + keySearch + : ''; + const sortParams = sort + ? '_sort=' + sort + : ''; + const orderParams = order + ? '_order=' + order + : ''; const finalParam = [phoneParams, sortParams, orderParams]; let query = ''; let isFirstParam = true; @@ -117,11 +60,4 @@ const formatCurrency = (value: number): string => { }).format(value); }; -export { - isRequired, - getPropValues, - getValueFromObj, - searchQuery, - formatCurrency, - REQUIRED_FIELD_ERROR, -}; +export { isRequired, searchQuery, formatCurrency, REQUIRED_FIELD_ERROR }; diff --git a/hotel-management/src/helpers/validators.ts b/hotel-management/src/helpers/validators.ts index 523cb48..ae3c974 100644 --- a/hotel-management/src/helpers/validators.ts +++ b/hotel-management/src/helpers/validators.ts @@ -1,10 +1,19 @@ +/** + * Check value is valid name or not + * @param value Values need to be checked + * @returns A boolean indicating whether or not the argument has valid + */ +const isValidName = (value: string): boolean => { + return /^[a-zA-Z]{2,}(?: [a-zA-Z]+){0,2}$/gm.test(value); +}; + /** * Check value is valid number or not * @param value Value need to be checked * @returns A boolean indicating whether or not the argument has valid */ -const isValidNumber = (value: unknown): boolean => { - return /^[0-9]*$/.test(value as string); +const isValidNumber = (value: string): boolean => { + return /^[0-9]*$/.test(value); }; /** @@ -40,15 +49,21 @@ const isValidString = (value: string): boolean => { */ const skipCheck = () => true; +/** + * Check object is empty or not + * @param obj Object need to be check + * @returns A boolean indicating whether or not the argument has valid + */ const isEmptyObj = (obj: object) => { return Object.keys(obj).length === 0; -} +}; export { + isValidName, isValidNumber, isValidPhoneNumber, isValidString, skipCheck, isValidDiscount, - isEmptyObj + isEmptyObj, }; diff --git a/hotel-management/src/hooks/useDebounce.ts b/hotel-management/src/hooks/useDebounce.ts new file mode 100644 index 0000000..3af1ecd --- /dev/null +++ b/hotel-management/src/hooks/useDebounce.ts @@ -0,0 +1,17 @@ +import { useEffect, useState } from 'react'; + +const useDebounce = (value: T, delay: number): T => { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const timer = setTimeout(() => setDebouncedValue(value), delay); + + return () => { + clearTimeout(timer); + }; + }, [value, delay]); + + return debouncedValue; +}; + +export { useDebounce }; diff --git a/hotel-management/src/hooks/useFetch.ts b/hotel-management/src/hooks/useFetch.ts index 080c502..cce60ce 100644 --- a/hotel-management/src/hooks/useFetch.ts +++ b/hotel-management/src/hooks/useFetch.ts @@ -4,9 +4,12 @@ import { useEffect, useState } from 'react'; import { BASE_URL } from '../constants/path'; import { DEFAULT_ORDER_BY, DEFAULT_SORT_BY } from '../constants/config'; -// Utils +// Helpers import { searchQuery } from '../helpers/utils'; +// Types +import { Nullable } from '../globals/types'; + /** * The function use to fetch data on server API. * @param path The path of url @@ -23,11 +26,11 @@ const useFetch = ( keyWord: string = '', tempSortBy?: string, tempOrderBy?: string, - reload?: boolean, + reload?: boolean ) => { const [data, setData] = useState(null); const [isPending, setIsPending] = useState(false); - const [errorFetchMsg, setErrorFetchMsg] = useState(null); + const [errorFetchMsg, setErrorFetchMsg] = useState>(null); useEffect(() => { // Clear data @@ -37,12 +40,9 @@ const useFetch = ( setIsPending(true); // Set default value - // prettier-ignore const sortBy = tempSortBy ? tempSortBy : DEFAULT_SORT_BY; - - // prettier-ignore const orderBy = tempOrderBy ? tempOrderBy : DEFAULT_ORDER_BY; @@ -56,7 +56,7 @@ const useFetch = ( if (!response.ok) { throw new Error( - `Error code: ${response.status} \n Messages: ${response.text}`, + `Error code: ${response.status} \n Messages: ${response.text}` ); } diff --git a/hotel-management/src/hooks/useForwardRef.ts b/hotel-management/src/hooks/useForwardRef.ts index ab9ee93..8081ec8 100644 --- a/hotel-management/src/hooks/useForwardRef.ts +++ b/hotel-management/src/hooks/useForwardRef.ts @@ -1,8 +1,11 @@ import { ForwardedRef, useEffect, useRef } from 'react'; +// Types +import { Nullable } from '../globals/types'; + const useForwardRef = ( ref: ForwardedRef, - initialValue: T | null = null + initialValue: Nullable = null ) => { const targetRef = useRef(initialValue); diff --git a/hotel-management/src/hooks/useOutsideClick.ts b/hotel-management/src/hooks/useOutsideClick.ts index bc6e040..ded42be 100644 --- a/hotel-management/src/hooks/useOutsideClick.ts +++ b/hotel-management/src/hooks/useOutsideClick.ts @@ -1,4 +1,7 @@ -import { useEffect, useRef } from 'react'; +import { MutableRefObject, useEffect, useRef } from 'react'; + +// Types +import { Nullable } from '../globals/types'; /** * Custom hook to call handler when click outside element @@ -9,7 +12,7 @@ import { useEffect, useRef } from 'react'; export const useOutsideClick = ( handler: () => void, listeningCapturing = true, -): React.MutableRefObject => { +): MutableRefObject> => { const ref = useRef(null); useEffect(() => { diff --git a/hotel-management/src/pages/Room/Dialog.tsx b/hotel-management/src/pages/Room/Dialog.tsx index 0aa69ba..ea1a8ec 100644 --- a/hotel-management/src/pages/Room/Dialog.tsx +++ b/hotel-management/src/pages/Room/Dialog.tsx @@ -1,60 +1,69 @@ -import { forwardRef, useEffect } from 'react'; +import { + Dispatch, + MutableRefObject, + SetStateAction, + forwardRef, + useEffect, +} from 'react'; // Components import Dialog from '../../components/Dialog'; import RoomForm from './Form'; -import { TRoom } from '../../globals/types'; +// Types +import { Nullable, TRoom } from '../../globals/types'; + +// Hooks +import { useForwardRef } from '../../hooks/useForwardRef'; interface IRoomDialog { onClose?: () => void; reload?: boolean; - setReload?: React.Dispatch>; - ref?: React.MutableRefObject; - room?: TRoom | null; + setReload?: Dispatch>; + ref?: MutableRefObject>; + room?: Nullable; isAdd?: boolean; } -const RoomDialog = forwardRef((props: IRoomDialog, ref) => { - const dialogRef = ref as React.MutableRefObject< - HTMLDialogElement | undefined - >; - // prettier-ignore - const { - onClose, - setReload, - reload, - room, - isAdd - } = props; +const RoomDialog = forwardRef( + (props: IRoomDialog, ref) => { + const dialogRef = useForwardRef(ref); + const { + onClose, + setReload, + reload, + room, + isAdd + } = props; - useEffect(() => { - if (dialogRef.current) { - dialogRef.current.addEventListener('click', (e: MouseEvent) => { - const dialogDimensions = dialogRef.current!.getBoundingClientRect(); - if ( - e.clientX < dialogDimensions.left || - e.clientX > dialogDimensions.right || - e.clientY < dialogDimensions.top || - e.clientY > dialogDimensions.bottom - ) { - dialogRef.current!.close(); - } - }); - } - }, [dialogRef]); + useEffect(() => { + if (dialogRef.current) { + dialogRef.current.addEventListener('click', (e: MouseEvent) => { + const dialogDimensions = dialogRef.current!.getBoundingClientRect(); + if ( + e.clientX < dialogDimensions.left || + e.clientX > dialogDimensions.right || + e.clientY < dialogDimensions.top || + e.clientY > dialogDimensions.bottom + ) { + dialogRef.current!.close(); + } + }); + } + }, [dialogRef]); - return ( - - - - ); -}); + return ( + + + + ); + } +); export default RoomDialog; diff --git a/hotel-management/src/pages/Room/Form.tsx b/hotel-management/src/pages/Room/Form.tsx index 7744a7b..8bb6ff0 100644 --- a/hotel-management/src/pages/Room/Form.tsx +++ b/hotel-management/src/pages/Room/Form.tsx @@ -1,20 +1,42 @@ +import { Dispatch, SetStateAction, useEffect } from 'react'; +import toast from 'react-hot-toast'; import styled from 'styled-components'; + +// Hooks +import { useForm } from 'react-hook-form'; + +// Styled import Button from '../../commons/styles/Button.ts'; +import Input from '../../commons/styles/Input.ts'; // Types -import { TRoom } from '../../globals/types.ts'; -import { useForm } from 'react-hook-form'; +import { Nullable, TRoom } from '../../globals/types.ts'; + +// Constants import { ROOM_PATH } from '../../constants/path.ts'; import { STATUS_CODE } from '../../constants/responseStatus.ts'; -import toast from 'react-hot-toast'; -import { ADD_SUCCESS, EDIT_SUCCESS, errorMsg } from '../../constants/messages.ts'; +import { + ADD_SUCCESS, + EDIT_SUCCESS, + errorMsg, +} from '../../constants/messages.ts'; +import { + INVALID_DISCOUNT, + INVALID_FIELD, + REQUIRED_FIELD_ERROR, +} from '../../constants/formValidateMessage.ts'; + +// Helpers import { sendRequest } from '../../helpers/sendRequest.ts'; -import Input from '../../commons/styles/Input.ts'; +import { + isValidDiscount, + isValidNumber, + isValidString, +} from '../../helpers/validators.ts'; + +// Components import FormRow from '../../components/LabelControl/index.tsx'; -import { INVALID_DISCOUNT, INVALID_FIELD, REQUIRED_FIELD_ERROR } from '../../constants/formValidateMessage.ts'; -import { isValidDiscount, isValidNumber, isValidString } from '../../helpers/validators.ts'; import Form from '../../components/Form/index.tsx'; -import { useEffect } from 'react'; const FormBtn = styled(Button)` width: 100%; @@ -29,8 +51,8 @@ const FormBtn = styled(Button)` interface IRoomFormProp { onClose: () => void; reload: boolean; - setReload: React.Dispatch>; - room?: TRoom | null; + setReload: Dispatch>; + room?: Nullable; isAdd: boolean; } @@ -51,20 +73,24 @@ const RoomForm = ({ } = formMethods; useEffect(() => { - if(room) { + if (room) { reset(room); } }, [room, reset]); // Submit form const onSubmit = async (room: TRoom) => { + // Calculate final price + room.finalPrice = room.price - (room.price * room.discount) / 100; + try { if (isAdd) { // Add request + const response = await sendRequest( ROOM_PATH, 'POST', - JSON.stringify(room), + JSON.stringify(room) ); if (response.statusCode === STATUS_CODE.CREATE) { @@ -77,7 +103,7 @@ const RoomForm = ({ const response = await sendRequest( ROOM_PATH + `/${room!.id}`, 'PUT', - JSON.stringify(room), + JSON.stringify(room) ); if (response.statusCode == STATUS_CODE.OK) { @@ -99,68 +125,66 @@ const RoomForm = ({ }; return ( -
- - - - isValidString(value) || INVALID_FIELD, - }, - onChange: () => trigger('name'), - })} - /> - + + + + isValidString(value) || INVALID_FIELD, + }, + onChange: () => trigger('name'), + })} + /> + - - isValidNumber(v) || INVALID_FIELD, - }, - onChange: () => trigger('price'), - })} - /> - + + + isValidNumber(v.toString()) || INVALID_FIELD, + }, + onChange: () => trigger('price'), + })} + /> + - - isValidDiscount(v) || INVALID_DISCOUNT, - }, - onChange: () => trigger('discount'), - })} - /> - + + isValidDiscount(v) || INVALID_DISCOUNT, + }, + onChange: () => trigger('discount'), + })} + /> + - - - { - // prettier-ignore - isAdd - ? 'Add' + + + { + isAdd + ? 'Add' : 'Save' - } - - - Close - - - + } + + + Close + +
+ ); }; diff --git a/hotel-management/src/pages/Room/Table.tsx b/hotel-management/src/pages/Room/Table.tsx index f0b0a05..74d6e79 100644 --- a/hotel-management/src/pages/Room/Table.tsx +++ b/hotel-management/src/pages/Room/Table.tsx @@ -1,5 +1,5 @@ import { useSearchParams } from 'react-router-dom'; -import { useEffect, useState } from 'react'; +import { Dispatch, SetStateAction, useEffect, useState } from 'react'; import toast from 'react-hot-toast'; // Components @@ -15,7 +15,7 @@ import SortBy from '../../components/SortBy'; import OrderBy from '../../components/OrderBy'; // Types -import { TRoom } from '../../globals/types'; +import { Nullable, TRoom } from '../../globals/types'; // Constants import { useFetch } from '../../hooks/useFetch'; @@ -27,16 +27,16 @@ import { ORDERBY_OPTIONS, ROOM_PAGE } from '../../constants/variables'; // Styled import Spinner from '../../commons/styles/Spinner'; -// Utils +// Helpers import { sendRequest } from '../../helpers/sendRequest'; import { formatCurrency } from '../../helpers/utils'; interface IRoomRow { room: TRoom; openFormDialog: () => void; - setRoom: React.Dispatch>; + setRoom: Dispatch>>; reload: boolean; - setReload: React.Dispatch>; + setReload: Dispatch>; } const RoomRow = ({ @@ -46,12 +46,12 @@ const RoomRow = ({ reload, setReload, }: IRoomRow) => { - const handleOnEdit = (room: TRoom) => { + const handleEdit = (room: TRoom) => { setRoom(room); openFormDialog(); }; - const handleOnDelete = async (room: TRoom) => { + const handleDelete = async (room: TRoom) => { if (confirm(CONFIRM_DELETE)) { const response = await sendRequest(ROOM_PATH + `/${room.id}`, 'DELETE'); @@ -64,12 +64,8 @@ const RoomRow = ({ } }; - const { id, name, price, discount, status } = room; + const { id, name, finalPrice, status } = room; - // Calculate final price - const finalPrice = price - (price * discount / 100); - - // prettier-ignore const statusText = status ? 'Unavailable' : 'Available'; @@ -87,11 +83,11 @@ const RoomRow = ({ } - onClick={() => handleOnEdit(room)} + onClick={() => handleEdit(room)} > Edit - } onClick={() => handleOnDelete(room)}> + } onClick={() => handleDelete(room)}> Delete @@ -102,9 +98,9 @@ const RoomRow = ({ interface IRoomTable { reload: boolean; - setReload: React.Dispatch>; + setReload: Dispatch>; openFormDialog: () => void; - setRoom?: React.Dispatch>; + setRoom?: Dispatch>>; } const RoomTable = ({ diff --git a/hotel-management/src/pages/Room/index.tsx b/hotel-management/src/pages/Room/index.tsx index 24b1498..b6cb461 100644 --- a/hotel-management/src/pages/Room/index.tsx +++ b/hotel-management/src/pages/Room/index.tsx @@ -1,21 +1,21 @@ import { useRef, useState } from 'react'; // Components -import Direction from '../../commons/styles/Direction'; -import Button from '../../commons/styles/Button'; import RoomTable from './Table'; // Styled import { StyledRoom, Title } from './styled'; +import Direction from '../../commons/styles/Direction'; +import Button from '../../commons/styles/Button'; import RoomDialog from './Dialog'; // Types -import { TRoom } from '../../globals/types'; +import { Nullable, TRoom } from '../../globals/types'; const Room = () => { - const dialogRef = useRef(); + const dialogRef = useRef(null); const [reload, setReload] = useState(true); - const [room, setRoom] = useState(null); + const [room, setRoom] = useState>(null); const [isAdd, setIsAdd] = useState(false); const openFormDialog = (isAddForm: boolean = false) => { diff --git a/hotel-management/src/pages/User/Dialog.tsx b/hotel-management/src/pages/User/Dialog.tsx index 7dd9a8a..4b9a76e 100644 --- a/hotel-management/src/pages/User/Dialog.tsx +++ b/hotel-management/src/pages/User/Dialog.tsx @@ -1,26 +1,33 @@ -import { forwardRef, useEffect } from 'react'; +import { + Dispatch, + MutableRefObject, + SetStateAction, + forwardRef, + useEffect, +} from 'react'; // Components import Dialog from '../../components/Dialog'; import UserForm from './Form'; // Types -import { TUser } from '../../globals/types'; +import { Nullable, TUser } from '../../globals/types'; + +// Hooks import { useForwardRef } from '../../hooks/useForwardRef'; interface IUserDialog { onClose: () => void; reload: boolean; - setReload: React.Dispatch>; - ref: React.MutableRefObject; - user: TUser | null; + setReload: Dispatch>; + ref: MutableRefObject>; + user: Nullable; isAdd: boolean; } -const UserDialog = forwardRef((props, ref) => { +const UserDialog = forwardRef((props, ref) => { const dialogRef = useForwardRef(ref); - // prettier-ignore const { onClose, setReload, @@ -56,6 +63,6 @@ const UserDialog = forwardRef((props, ref) => { /> ); -}) 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 4582dfa..37a6d4e 100644 --- a/hotel-management/src/pages/User/Form.tsx +++ b/hotel-management/src/pages/User/Form.tsx @@ -1,5 +1,13 @@ -import { useCallback, useEffect, useState } from 'react'; +import { + Dispatch, + SetStateAction, + useCallback, + useEffect, + useState, +} from 'react'; import toast from 'react-hot-toast'; + +// Hooks import { FormProvider, useForm } from 'react-hook-form'; // Styled @@ -8,14 +16,15 @@ import Input from '../../commons/styles/Input'; // Components import Form from '../../components/Form'; import FormRow from '../../components/LabelControl/index.tsx'; +import Select, { ISelectOptions } from '../../components/Select'; -// Utils +// Helpers import { sendRequest } from '../../helpers/sendRequest.ts'; import { isEmptyObj, + isValidName, isValidNumber, isValidPhoneNumber, - isValidString, } from '../../helpers/validators.ts'; // Constants @@ -26,26 +35,27 @@ import { errorMsg, } from '../../constants/messages.ts'; import { USER_PATH } from '../../constants/path.ts'; -import Select, { ISelectOptions } from '../../components/Select'; - -// Hooks - -// Styled -import { FormBtn } from './styled.ts'; import { INVALID_FIELD, INVALID_PHONE, REQUIRED_FIELD_ERROR, } from '../../constants/formValidateMessage.ts'; -import { getAllRoom, updateRoomStatus } from '../../services/roomServices.ts'; -import { TRoom, TUser } from '../../globals/types.ts'; import { INIT_VALUE_USER_FORM } from '../../constants/variables.ts'; +// Styled +import { FormBtn } from './styled.ts'; + +// Services +import { getAllRoom, updateRoomStatus } from '../../services/roomServices.ts'; + +// Types +import { Nullable, TRoom, TUser } from '../../globals/types.ts'; + interface IUserFormProp { onClose: () => void; reload: boolean; - setReload: React.Dispatch>; - user: TUser | null; + setReload: Dispatch>; + user: Nullable; isAdd: boolean; } @@ -78,11 +88,13 @@ const UserForm = ({ rooms.forEach((item) => { if (!item.status || tempUser?.roomId === item.id) options.push({ - label: item.name! as string, + label: item.name!, value: item.id!.toString(), }); }); + } + if (options.length > 0) { setOptions(options); reset({ roomId: +options[0].value }); } @@ -178,8 +190,7 @@ const UserForm = ({ {...register('name', { required: REQUIRED_FIELD_ERROR, validate: { - checkValidName: (value) => - isValidString(value) || INVALID_FIELD, + checkValidName: (value) => isValidName(value) || INVALID_FIELD, }, onChange: () => trigger('name'), })} @@ -196,7 +207,8 @@ const UserForm = ({ {...register('identifiedCode', { required: REQUIRED_FIELD_ERROR, validate: { - checkIdentifiedCode: (v) => isValidNumber(v) || INVALID_FIELD, + checkIdentifiedCode: (v) => + isValidNumber(v.toString()) || INVALID_FIELD, }, onChange: () => trigger('identifiedCode'), })} @@ -218,25 +230,24 @@ const UserForm = ({ - trigger('roomId'), + }} + /> + ) : ( +

No room available!

+ )}
- { - // prettier-ignore - 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 a12d302..387c8d7 100644 --- a/hotel-management/src/pages/User/Table.tsx +++ b/hotel-management/src/pages/User/Table.tsx @@ -1,11 +1,10 @@ import { useSearchParams } from 'react-router-dom'; -import { useEffect, useState } from 'react'; +import { Dispatch, SetStateAction, useEffect, useState } from 'react'; import toast from 'react-hot-toast'; // Components import { RiEditBoxFill } from 'react-icons/ri'; import { IoExit } from 'react-icons/io5'; -import { StyledOperationTable } from './styled'; import Menus from '../../components/Menus'; import Table from '../../components/Table'; import Direction from '../../commons/styles/Direction'; @@ -15,27 +14,30 @@ import SortBy from '../../components/SortBy'; import OrderBy from '../../components/OrderBy'; // Types -import { TUser } from '../../globals/types'; +import { Nullable, TUser } from '../../globals/types'; + +// Hooks +import { useFetch } from '../../hooks/useFetch'; // Constants -import { useFetch } from '../../hooks/useFetch'; import { STATUS_CODE } from '../../constants/responseStatus'; import { ORDERBY_OPTIONS, USER_PAGE } from '../../constants/variables'; +import { CONFIRM_MESSAGE } from '../../constants/messages'; // Styled +import { StyledOperationTable } from './styled'; import Spinner from '../../commons/styles/Spinner'; -// Utils +// Services import { updateRoomStatus } from '../../services/roomServices'; import { checkOutUser } from '../../services/userServices'; -import { CONFIRM_MESSAGE } from '../../constants/messages'; interface IUserRow { user: TUser; openFormDialog: () => void; - setUser: React.Dispatch>; + setUser: Dispatch>>; reload: boolean; - setReload: React.Dispatch>; + setReload: Dispatch>; } const UserRow = ({ @@ -45,12 +47,12 @@ const UserRow = ({ reload, setReload, }: IUserRow) => { - const handleOnEdit = (user: TUser) => { + const handleEdit = (user: TUser) => { setUser(user); openFormDialog(); }; - const handleOnCheckOut = async (user: TUser) => { + const handleCheckOut = async (user: TUser) => { if (confirm(CONFIRM_MESSAGE)) { const resUpdateStatus = await updateRoomStatus(user.roomId, false); const resCheckoutUser = await checkOutUser(user); @@ -75,7 +77,11 @@ const UserRow = ({
{name}
{identifiedCode}
{phone}
-
{roomId ? roomId : 'None'}
+
{ + roomId + ? roomId + : 'None' + }
@@ -83,14 +89,11 @@ const UserRow = ({ } - onClick={() => handleOnEdit(user)} + onClick={() => handleEdit(user)} > Edit - } - onClick={() => handleOnCheckOut(user)} - > + } onClick={() => handleCheckOut(user)}> Check out @@ -101,9 +104,9 @@ const UserRow = ({ interface IUserTable { reload: boolean; - setReload: React.Dispatch>; + setReload: Dispatch>; openFormDialog: () => void; - setUser?: React.Dispatch>; + setUser?: Dispatch>>; } const UserTable = ({ diff --git a/hotel-management/src/pages/User/index.tsx b/hotel-management/src/pages/User/index.tsx index 7703a29..f415671 100644 --- a/hotel-management/src/pages/User/index.tsx +++ b/hotel-management/src/pages/User/index.tsx @@ -1,21 +1,21 @@ import { useRef, useState } from 'react'; // Components -import Direction from '../../commons/styles/Direction'; -import Button from '../../commons/styles/Button'; import UserTable from './Table'; // Styled +import Button from '../../commons/styles/Button'; +import Direction from '../../commons/styles/Direction'; import { StyledUser, Title } from './styled'; import UserDialog from './Dialog'; // Types -import { TUser } from '../../globals/types'; +import { Nullable, TUser } from '../../globals/types'; const User = () => { 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 7aa6b26..5500165 100644 --- a/hotel-management/src/services/roomServices.ts +++ b/hotel-management/src/services/roomServices.ts @@ -1,11 +1,21 @@ import toast from 'react-hot-toast'; -import { TResponse, TRoom } from '../globals/types'; + +// Types +import { Nullable, TResponse, TRoom } from '../globals/types'; + +// Helpers import { sendRequest } from '../helpers/sendRequest'; + +// Constants import { STATUS_CODE, RESPONSE_MESSAGE } from '../constants/responseStatus'; import { errorMsg } from '../constants/messages'; import { ROOM_PATH } from '../constants/path'; -const getAllRoom = async (): Promise => { +/** + * Get all rooms from server + * @returns Return all rooms in server + */ +const getAllRoom = async (): Promise> => { try { const response = await sendRequest(ROOM_PATH); @@ -25,7 +35,12 @@ const getAllRoom = async (): Promise => { return null; }; -const getRoom = async (roomId: number): Promise => { +/** + * Get room by id + * @param roomId The id room need to be get + * @returns Return the room object depend on room id + */ +const getRoom = async (roomId: number): Promise> => { try { const response = await sendRequest(ROOM_PATH + '/' + roomId); @@ -45,7 +60,12 @@ const getRoom = async (roomId: number): Promise => { return null; }; -const updateRoom = async (room: TRoom): Promise | null> => { +/** + * Update room into server + * @param room Room object need to be updated + * @returns The response object + */ +const updateRoom = async (room: TRoom): Promise>> => { try { const response = await sendRequest( ROOM_PATH + '/' + room.id, @@ -67,11 +87,18 @@ const updateRoom = async (room: TRoom): Promise | null> => { return null; }; +/** + * Update room status + * @param roomId The id room need to be updated + * @param status Status of room + * @param roomIdNew The new id room need to be updated + * @returns Return the response object + */ const updateRoomStatus = async ( roomId: number, status: boolean, roomIdNew?: number -): Promise | null> => { +): Promise>> => { if (!roomIdNew) { const response = await sendRequest( ROOM_PATH + '/' + roomId, @@ -80,52 +107,36 @@ const updateRoomStatus = async ( ); return response; - } else { - // Update new room status - const resNewRoom = await sendRequest( - ROOM_PATH + '/' + roomIdNew, - 'PATCH', - JSON.stringify({ status: status }) - ); + } + + // 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 }) - ); - - if ( - resNewRoom.statusCode === STATUS_CODE.OK && - resOldRoom.statusCode === STATUS_CODE.OK - ) { - return { - statusCode: STATUS_CODE.OK, - msg: RESPONSE_MESSAGE.UPDATE_SUCCESS, - }; - } + // 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.INTERNAL_SERVER_ERROR, - msg: 'Something went wrong!', + statusCode: STATUS_CODE.OK, + msg: RESPONSE_MESSAGE.UPDATE_SUCCESS, }; } - // if (rooms?.length) { - // const oldRoom = rooms.find((room) => room.id === roomId); - // const newRoom = rooms.find((room) => room.id === roomIdNew); - - // if(newRoom) { - - // } - - // oldRoom!.status = status; - // const response = await updateRoom(oldRoom!); - - // return response; - // } - - return null; + return { + statusCode: STATUS_CODE.INTERNAL_SERVER_ERROR, + msg: 'Something went wrong!', + }; }; export { getRoom, updateRoom, updateRoomStatus, getAllRoom }; diff --git a/hotel-management/src/services/userServices.ts b/hotel-management/src/services/userServices.ts index c127909..7bd9027 100644 --- a/hotel-management/src/services/userServices.ts +++ b/hotel-management/src/services/userServices.ts @@ -1,11 +1,17 @@ import toast from 'react-hot-toast'; + +// Constants import { errorMsg } from '../constants/messages'; import { USER_PATH } from '../constants/path'; import { STATUS_CODE } from '../constants/responseStatus'; -import { TResponse, TUser } from '../globals/types'; + +// Types +import { Nullable, TResponse, TUser } from '../globals/types'; + +// Helpers import { sendRequest } from '../helpers/sendRequest'; -const updateUser = async (user: TUser): Promise | null> => { +const updateUser = async (user: TUser): Promise>> => { try { const response = await sendRequest( USER_PATH + '/' + user.id, @@ -27,7 +33,7 @@ const updateUser = async (user: TUser): Promise | null> => { return null; }; -const checkOutUser = async (user: TUser): Promise | null> => { +const checkOutUser = async (user: TUser): Promise>> => { const tempUser = user; if (tempUser) {