diff --git a/hotel-management/src/commons/styles/Input.ts b/hotel-management/src/commons/styles/Input.ts index f1350ab..0826c7e 100644 --- a/hotel-management/src/commons/styles/Input.ts +++ b/hotel-management/src/commons/styles/Input.ts @@ -1,10 +1,25 @@ -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; // Styled import CommonInput from './CommonInput'; -const Input = styled.input` +interface IInputTyped { + type?: 'text' | 'checkbox' | 'hidden'; +} + +const Input = styled.input` ${CommonInput} + + ${(props) => + props.type === 'checkbox' && + css` + width: 20px; + height: 20px; + `} `; +Input.defaultProps = { + type: 'text', +}; + export default Input; diff --git a/hotel-management/src/components/Dialog/index.tsx b/hotel-management/src/components/Dialog/index.tsx index 8e73da6..1bedac9 100644 --- a/hotel-management/src/components/Dialog/index.tsx +++ b/hotel-management/src/components/Dialog/index.tsx @@ -7,7 +7,7 @@ import { IDialogProps } from '../../globals/interfaces'; import { StyledBody, StyledDialog, StyledTitle } from './styled'; const Dialog = forwardRef((props, ref) => { - const { title, children, onClose } = props as IDialogProps; + const { title, children, onClose } = props as IDialogProps; return ( | undefined} @@ -17,6 +17,6 @@ const Dialog = forwardRef((props, ref) => { {children} ); -}) as React.FC; +}) as React.FC>; export default Dialog; diff --git a/hotel-management/src/components/Search.tsx b/hotel-management/src/components/Search.tsx index 71538f5..ddc1585 100644 --- a/hotel-management/src/components/Search.tsx +++ b/hotel-management/src/components/Search.tsx @@ -9,24 +9,25 @@ const StyledSearch = styled.input` `; interface ISearch { - setPhoneSearch: React.Dispatch>; + setPlaceHolder: string; + setValueSearch: React.Dispatch>; } -const Search = ({ setPhoneSearch }: ISearch) => { +const Search = ({ setValueSearch, setPlaceHolder }: ISearch) => { const [query, setQuery] = useState(''); useEffect(() => { const timeOut = setTimeout(() => { - setPhoneSearch(query); + setValueSearch(query); }, 500); return () => clearTimeout(timeOut); - }, [setPhoneSearch, query]); + }, [setValueSearch, query]); return ( setQuery(e.target.value)} - placeholder="Search by phone..." + placeholder={setPlaceHolder} /> ); }; diff --git a/hotel-management/src/components/SortBy.tsx b/hotel-management/src/components/SortBy.tsx index 524366b..128b630 100644 --- a/hotel-management/src/components/SortBy.tsx +++ b/hotel-management/src/components/SortBy.tsx @@ -1,4 +1,6 @@ import { useSearchParams } from 'react-router-dom'; + +// Components import Select from './Select'; interface ISortByProps { diff --git a/hotel-management/src/components/Table/styled.ts b/hotel-management/src/components/Table/styled.ts index 739542f..5e89ff2 100644 --- a/hotel-management/src/components/Table/styled.ts +++ b/hotel-management/src/components/Table/styled.ts @@ -15,6 +15,7 @@ const CommonRow = styled.div` grid-template-columns: ${(props) => props.columns}; column-gap: 10px; align-items: center; + justify-items: center; `; const StyledBody = styled.div` diff --git a/hotel-management/src/constants/messages.ts b/hotel-management/src/constants/messages.ts index 7ddb73a..0b9531e 100644 --- a/hotel-management/src/constants/messages.ts +++ b/hotel-management/src/constants/messages.ts @@ -10,6 +10,7 @@ const ADD_SUCCESS = 'Add success'; const EDIT_SUCCESS = 'Edit success'; const CONFIRM_DELETE = 'Are you sure to delete it?'; const DELETE_SUCCESS = 'Delete success'; +const REQUIRED_FIELD_ERROR = 'This is required field'; export { invalidFormatMsg, @@ -18,4 +19,5 @@ export { EDIT_SUCCESS, CONFIRM_DELETE, DELETE_SUCCESS, + REQUIRED_FIELD_ERROR, }; diff --git a/hotel-management/src/constants/path.ts b/hotel-management/src/constants/path.ts index d4bd6b1..2f54b15 100644 --- a/hotel-management/src/constants/path.ts +++ b/hotel-management/src/constants/path.ts @@ -4,3 +4,4 @@ export const ROOM: string = '/room'; export const OTHER_PATH: string = '*'; export const BASE_URL: string = 'https://hotel-management-api.loiphan.com/'; export const USER_PATH = 'users'; +export const ROOM_PATH = 'rooms'; diff --git a/hotel-management/src/constants/variables.ts b/hotel-management/src/constants/variables.ts index d1fc6b2..b3b169a 100644 --- a/hotel-management/src/constants/variables.ts +++ b/hotel-management/src/constants/variables.ts @@ -34,4 +34,47 @@ const USER_PAGE = { ], }; -export { USER_PAGE }; +// prettier-ignore +const ROOM_PAGE = { + ORDERBY_OPTIONS: [ + { + value: 'asc', + label: 'Ascending', + }, + { + value: 'desc', + label: 'Descending', + }, + ], + SORTBY_OPTIONS: [ + { + value: 'id', + label: 'Sort by id', + }, + { + value: 'name', + label: 'Sort by name', + }, + { + value: 'amount', + label: 'Sort by amount', + }, + { + value: 'price', + label: 'Sort by price', + }, + { + value: 'discount', + label: 'Sort by discount', + }, + { + value: 'status', + label: 'Sort by status', + }, + ], +} + +const VALUE = 'value'; +const ERROR = 'error'; + +export { USER_PAGE, ROOM_PAGE, VALUE, ERROR }; diff --git a/hotel-management/src/globals/interfaces.ts b/hotel-management/src/globals/interfaces.ts index ef16998..2d0726c 100644 --- a/hotel-management/src/globals/interfaces.ts +++ b/hotel-management/src/globals/interfaces.ts @@ -1,6 +1,3 @@ -// Types -import { TUser } from './types'; - interface IMenusContext { openId?: string; close?: () => void; @@ -23,14 +20,14 @@ interface ITableBody { render?: (value: T) => JSX.Element; } -interface IDialogProps { +interface IDialogProps { title?: string; children?: JSX.Element[] | JSX.Element; onClose?: () => void; reload?: boolean; setReload?: React.Dispatch>; ref?: React.MutableRefObject; - user?: TUser | null; + data?: T | null; isAdd?: boolean; } diff --git a/hotel-management/src/globals/types.ts b/hotel-management/src/globals/types.ts index 8514620..d7176a0 100644 --- a/hotel-management/src/globals/types.ts +++ b/hotel-management/src/globals/types.ts @@ -7,6 +7,16 @@ type TUser = { roomId: string; }; +type TRoom = { + id: string; + name: string; + amount: string; + price: string; + discount: string; + description: string; + status: boolean; +}; + type TStateSchema = { [key: string]: { value?: string; @@ -15,7 +25,11 @@ type TStateSchema = { }; type TKeyValue = { - [key: string]: string | undefined | boolean; + [key: string]: boolean | undefined | string; +}; + +type TKeyString = { + [key: string]: string; }; type TPropValues = 'value' | 'error' | boolean; @@ -37,8 +51,10 @@ type TResponse = { export type { TUser, + TRoom, TStateSchema, TKeyValue, + TKeyString, TPropValues, TValidator, TResponse, diff --git a/hotel-management/src/helpers/sendRequest.ts b/hotel-management/src/helpers/sendRequest.ts index 4d2d264..4696504 100644 --- a/hotel-management/src/helpers/sendRequest.ts +++ b/hotel-management/src/helpers/sendRequest.ts @@ -1,8 +1,18 @@ // Constants import { BASE_URL } from '../constants/path'; + +// Types import { TResponse } from '../globals/types'; + type TMethodRequest = 'GET' | 'POST' | 'PUT' | 'DELETE'; +/** + * The send request method to the server + * @param path The path of URL + * @param body The content will push on + * @param method HTTP method + * @returns The status code and message from server + */ export const sendRequest = async ( path: string, body: BodyInit | null | undefined, diff --git a/hotel-management/src/helpers/utils.ts b/hotel-management/src/helpers/utils.ts index 6c3b585..1dcbbd7 100644 --- a/hotel-management/src/helpers/utils.ts +++ b/hotel-management/src/helpers/utils.ts @@ -1,26 +1,49 @@ // Constants -import { invalidFormatMsg } from '../constants/messages'; +import { REQUIRED_FIELD_ERROR, invalidFormatMsg } from '../constants/messages'; // Types -import { TKeyValue, TPropValues, TStateSchema, TUser } from '../globals/types'; - -const VALUE = 'value'; -const ERROR = 'error'; -const REQUIRED_FIELD_ERROR = 'This is required field'; +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'; }; +/** + * The function check value has type object or not + * @param value The value need to checked + * @returns A boolean indicating whether or not the argument has type object. + */ const isObject = (value: unknown) => { return typeof value === 'object' && value !== null; }; +/** + * Set required error for value + * @param value The value set required or not + * @param isRequired Set required for value + * @returns Return error text if value has required + */ const isRequired = (value: string | number, isRequired: unknown) => { if (!value && isRequired) return REQUIRED_FIELD_ERROR; 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) @@ -37,6 +60,11 @@ type TValidator = { required?: boolean; }; +/** + * Create validator object + * @param param0 Pass TValidator object + * @returns An object contains condition validator + */ const addValidator = ({ validatorFunc, prop, required = true }: TValidator) => { return { required, @@ -47,18 +75,46 @@ const addValidator = ({ validatorFunc, prop, required = true }: TValidator) => { }; }; -const getValueUser = (user: TUser | null = null, prop: string): string => { - if (user) { - return user[prop as keyof TUser]; +/** + * 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]; + const value: string | boolean | number = + typeof tempValue === 'boolean' || typeof tempValue === 'string' + ? tempValue + : ''; + + result = { ...result, [`${key}Value`]: value }; + } } - return ''; + return result; }; -const searchQuery = (phone: string, sort: string, order: string) => { +/** + * Create query url for search + * @param columnSearch Column want to search + * @param keySearch Keyword search + * @param sort Sort by + * @param order Order by + * @returns Return query url + */ +const searchQuery = ( + columnSearch: string, + keySearch: string, + sort: string, + order: string, +) => { // prettier-ignore - const phoneParams = phone - ? 'phone_like=' + phone + const phoneParams = keySearch + ? `${columnSearch}_like=` + keySearch : ''; // prettier-ignore @@ -92,10 +148,8 @@ export { isObject, isRequired, getPropValues, - getValueUser, + getValueFromObj, addValidator, searchQuery, - VALUE, - ERROR, REQUIRED_FIELD_ERROR, }; diff --git a/hotel-management/src/helpers/validators.ts b/hotel-management/src/helpers/validators.ts index 4157039..560de79 100644 --- a/hotel-management/src/helpers/validators.ts +++ b/hotel-management/src/helpers/validators.ts @@ -1,17 +1,49 @@ -const isValidString = (value: string): boolean => { - return /^[a-zA-Z]{4,}(?: [a-zA-Z]+){0,2}$/gm.test(value); +/** + * 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: string): boolean => { return /^[0-9]*$/.test(value); }; +/** + * Check value is valid phone number or not + * @param value Value need to be checked + * @returns A boolean indicating whether or not the argument has valid + */ const isValidPhoneNumber = (value: string): boolean => { return /(84|0[3|5|7|8|9])+([0-9]{8})\b/g.test(value); }; -const isValidAddress = (value: string): boolean => { - return value.trim().length >= 10; +/** + * Check value is valid string or not + * @param value Value need to be checked + * @returns A boolean indicating whether or not the argument has valid + */ +const isValidString = (value: string): boolean => { + return value.trim().length >= 5; }; -export { isValidString, isValidNumber, isValidPhoneNumber, isValidAddress }; +/** + * A method skip check value + * @returns Return true + */ +const skipCheck = () => true; + +export { + isValidName, + isValidNumber, + isValidPhoneNumber, + isValidString, + skipCheck, +};