From dfd6582f942b7ae7051ee727d229484ffebdd3ee Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Fri, 27 Oct 2023 09:36:57 +0700 Subject: [PATCH 1/7] Add user form and fix bug --- hotel-management/src/hooks/useForm.ts | 3 +- hotel-management/src/pages/User/Dialog.tsx | 39 ++++ hotel-management/src/pages/User/Form.tsx | 193 ++++++++++++++++++ .../pages/User/{UserTable.tsx => Table.tsx} | 0 hotel-management/src/pages/User/index.tsx | 37 +++- 5 files changed, 261 insertions(+), 11 deletions(-) create mode 100644 hotel-management/src/pages/User/Dialog.tsx create mode 100644 hotel-management/src/pages/User/Form.tsx rename hotel-management/src/pages/User/{UserTable.tsx => Table.tsx} (100%) diff --git a/hotel-management/src/hooks/useForm.ts b/hotel-management/src/hooks/useForm.ts index 74be96e..fa5e71c 100644 --- a/hotel-management/src/hooks/useForm.ts +++ b/hotel-management/src/hooks/useForm.ts @@ -33,7 +33,6 @@ const useForm = ( // Get a local copy of stateSchema useEffect(() => { - setDisable(true); // Disable button in initial render. setInitialErrorState(); }, []); // eslint-disable-line @@ -116,8 +115,10 @@ const useForm = ( // Making sure that there's no error in the state // before calling the submit callback function + // and disabled button if (!validateErrorState()) { submitFormCallback(values); + setDisable(true); } }, [validateErrorState, submitFormCallback, values], diff --git a/hotel-management/src/pages/User/Dialog.tsx b/hotel-management/src/pages/User/Dialog.tsx new file mode 100644 index 0000000..a3d0427 --- /dev/null +++ b/hotel-management/src/pages/User/Dialog.tsx @@ -0,0 +1,39 @@ +import { forwardRef, useEffect } from 'react'; + +// Components +import Dialog from '../../components/Dialog'; +import UserForm from './Form'; + +// Interfaces +import { IDialogProps } from '../../globals/interfaces'; + +const UserDialog = forwardRef((props, ref) => { + const dialogRef = ref as React.MutableRefObject< + HTMLDialogElement | undefined + >; + const { onClose } = 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(); + } + }); + } + }); + + return ( + + + + ); +}) as React.FC; + +export default UserDialog; diff --git a/hotel-management/src/pages/User/Form.tsx b/hotel-management/src/pages/User/Form.tsx new file mode 100644 index 0000000..25f046f --- /dev/null +++ b/hotel-management/src/pages/User/Form.tsx @@ -0,0 +1,193 @@ +import styled from 'styled-components'; + +// Styled +import Input from '../../commons/styles/Input'; +import { useState } from 'react'; +import TextArea from '../../commons/styles/TextArea'; + +// Components +import Form from '../../components/Form'; +import FormRow from '../../components/FormRow'; +import Button from '../../commons/styles/Button.ts'; + +// Types +import { TKeyValue, TStateSchema } from '../../globals/types'; + +// Hooks +import useForm from '../../hooks/useForm'; + +// Utils +import { + isValidAddress, + isValidNumber, + isValidPhoneNumber, + isValidString, +} from '../../helpers/validators'; + +const FormBtn = styled(Button)` + width: 100%; + + &:disabled, + &[disabled] { + background-color: var(--disabled-btn-color); + } +`; + +interface IUserFormProp { + onClose: () => void; +} + +const UserForm = ({ onClose }: IUserFormProp) => { + const [reset, setReset] = useState(true); + + // Define your state schema + const stateSchema: TStateSchema = { + fullName: { value: '', error: '' }, + identifiedCode: { value: '', error: '' }, + phone: { value: '', error: '' }, + room: { value: '', error: '' }, + address: { value: '', error: '' }, + }; + + // Submit form + const onSubmitForm = (state: TKeyValue) => { + alert(JSON.stringify(state, null, 2)); + onClose(); + onResetForm(); + }; + + const { values, errors, dirty, handleOnChange, handleOnSubmit, disable } = + useForm( + stateSchema, + { + fullName: { + required: true, + validator: { + func: (input) => isValidString(input), + error: 'Invalid full name format.', + }, + }, + identifiedCode: { + required: true, + validator: { + func: (input) => isValidNumber(input), + error: 'Invalid identified code format.', + }, + }, + phone: { + required: true, + validator: { + func: (input) => isValidPhoneNumber(input), + error: 'Invalid phone format.', + }, + }, + room: { + required: true, + validator: { + func: (input) => isValidNumber(input), + error: 'Invalid room number format.', + }, + }, + address: { + required: true, + validator: { + func: (input) => isValidAddress(input), + error: 'Invalid address format.', + }, + }, + }, + onSubmitForm, + ); + + const { fullName, identifiedCode, phone, room, address } = values; + + // Reset form + const onResetForm = () => { + setReset(() => !reset); + Object.keys(values).forEach((key) => (values[key] = '')); + }; + + return ( +
+ + + + + + + + + + + + + + + + + + +