diff --git a/hotel-management/src/constants/messages.ts b/hotel-management/src/constants/messages.ts
new file mode 100644
index 0000000..67eb3df
--- /dev/null
+++ b/hotel-management/src/constants/messages.ts
@@ -0,0 +1,5 @@
+const invalidFormatMessage = (field: string) => {
+ return `Invalid ${field} format`;
+};
+
+export { invalidFormatMessage };
diff --git a/hotel-management/src/helpers/utils.ts b/hotel-management/src/helpers/utils.ts
index 767a3d0..b5a3c19 100644
--- a/hotel-management/src/helpers/utils.ts
+++ b/hotel-management/src/helpers/utils.ts
@@ -1,3 +1,4 @@
+import { invalidFormatMessage } from '../constants/messages';
import { TKeyValue, TPropValues, TStateSchema } from '../globals/types';
const VALUE = 'value';
@@ -27,10 +28,27 @@ const getPropValues = (stateSchema: TStateSchema, prop?: TPropValues) => {
}, {} as TKeyValue);
};
+type TValidator = {
+ validatorFunc: (value: string) => boolean;
+ prop: string;
+ required?: boolean;
+};
+
+const addValidator = ({ validatorFunc, prop, required = true }: TValidator) => {
+ return {
+ required,
+ validator: {
+ func: validatorFunc,
+ error: invalidFormatMessage(prop),
+ },
+ };
+};
+
export {
isObject,
isRequired,
getPropValues,
+ addValidator,
VALUE,
ERROR,
REQUIRED_FIELD_ERROR,
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..defe696
--- /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();
+ }
+ });
+ }
+ }, [dialogRef]);
+
+ 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..01bf120
--- /dev/null
+++ b/hotel-management/src/pages/User/Form.tsx
@@ -0,0 +1,212 @@
+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, TValidator } from '../../globals/types';
+
+// Hooks
+import useForm from '../../hooks/useForm';
+
+// Utils
+import {
+ isValidAddress,
+ isValidNumber,
+ isValidPhoneNumber,
+ isValidString,
+} from '../../helpers/validators';
+import { addValidator } from '../../helpers/utils.ts';
+
+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: '' },
+ };
+
+ // prettier-ignore
+ const stateValidatorSchema: TValidator = {
+ fullName: addValidator({
+ validatorFunc: isValidString,
+ prop: 'full name'
+ }),
+ identifiedCode: addValidator({
+ validatorFunc: isValidNumber,
+ prop: 'identified code',
+ }),
+ phone: addValidator({
+ validatorFunc: isValidPhoneNumber,
+ prop: 'phone number',
+ }),
+ room: addValidator({
+ validatorFunc: isValidNumber,
+ prop: 'room number'
+ }),
+ address: addValidator({
+ validatorFunc: isValidAddress,
+ prop: 'address'
+ }),
+ };
+
+ // Submit form
+ const onSubmitForm = (state: TKeyValue) => {
+ alert(JSON.stringify(state, null, 2));
+ onClose();
+ onResetForm();
+ };
+
+ // prettier-ignore
+ const {
+ values,
+ errors,
+ dirty,
+ handleOnChange,
+ handleOnSubmit,
+ disable } =
+ useForm(
+ stateSchema,
+ stateValidatorSchema,
+ onSubmitForm,
+ );
+
+ // prettier-ignore
+ const {
+ fullName,
+ identifiedCode,
+ phone,
+ room,
+ address
+ } = values;
+
+ // Reset form
+ const onResetForm = () => {
+ setReset(!reset);
+ Object.keys(values).forEach((key) => (values[key] = ''));
+ };
+
+ return (
+
+
+ Add
+
+
+ Close
+
+
+
+ );
+};
+
+export default UserForm;
diff --git a/hotel-management/src/pages/User/UserTable.tsx b/hotel-management/src/pages/User/Table.tsx
similarity index 100%
rename from hotel-management/src/pages/User/UserTable.tsx
rename to hotel-management/src/pages/User/Table.tsx
diff --git a/hotel-management/src/pages/User/index.tsx b/hotel-management/src/pages/User/index.tsx
index d6cda30..8fa2d9a 100644
--- a/hotel-management/src/pages/User/index.tsx
+++ b/hotel-management/src/pages/User/index.tsx
@@ -1,21 +1,38 @@
+import { useRef } from 'react';
+
// Components
import Direction from '../../commons/styles/Direction';
import Button from '../../commons/styles/Button';
-import UserTable from './UserTable';
+import UserTable from './Table';
// Styled
import { StyledUser, Title } from './styled';
+import UserDialog from './Dialog';
const User = () => {
- return (
-
-
- List User
-
-
+ const dialogRef = useRef();
-
-
+ const openDialog = () => {
+ dialogRef.current?.showModal();
+ };
+
+ const closeDialog = () => {
+ dialogRef.current?.close();
+ };
+
+ return (
+ <>
+
+
+ List User
+
+
+
+
+
+
+
+ >
);
};