+
+
+ {children}
+ {error && {error}}
+
+
+ );
+};
+
+export default FormRow;
diff --git a/hotel-management/src/components/FormRow/styled.ts b/hotel-management/src/components/FormRow/styled.ts
new file mode 100644
index 0000000..6563746
--- /dev/null
+++ b/hotel-management/src/components/FormRow/styled.ts
@@ -0,0 +1,21 @@
+import styled from 'styled-components';
+
+const StyledFormRow = styled.div`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 100px;
+`;
+
+const Label = styled.label`
+ font-size: var(--fs-sm);
+ text-transform: capitalize;
+`;
+
+const Error = styled.p`
+ color: var(--error-text);
+ font-size: var(--fs-sm-2x);
+ margin-top: 5px;
+`;
+
+export { StyledFormRow, Label, Error };
diff --git a/hotel-management/src/hooks/useForm.ts b/hotel-management/src/hooks/useForm.ts
new file mode 100644
index 0000000..74be96e
--- /dev/null
+++ b/hotel-management/src/hooks/useForm.ts
@@ -0,0 +1,138 @@
+import { useState, useEffect, useCallback, ChangeEvent } from 'react';
+
+// Utils
+import {
+ ERROR,
+ VALUE,
+ getPropValues,
+ isObject,
+ isRequired,
+} from '../helpers/utils';
+
+// Types
+import { TKeyValue, TValidator } from '../globals/types';
+
+/**
+ * Custom hooks to validate your Form...
+ *
+ * @param stateSchema model you stateSchema.
+ * @param stateValidatorSchema model your validation.
+ * @param submitFormCallback function to be execute during form submission.
+ * @returns
+ */
+const useForm = (
+ stateSchema = {},
+ stateValidatorSchema = {} as TValidator,
+ submitFormCallback: (values: TKeyValue) => void,
+) => {
+ const [values, setValues] = useState(getPropValues(stateSchema, VALUE));
+ const [errors, setErrors] = useState(getPropValues(stateSchema, ERROR));
+ const [dirty, setDirty] = useState(getPropValues(stateSchema));
+ const [disable, setDisable] = useState(true);
+ const [isDirty, setIsDirty] = useState(false);
+
+ // Get a local copy of stateSchema
+ useEffect(() => {
+ setDisable(true); // Disable button in initial render.
+ setInitialErrorState();
+ }, []); // eslint-disable-line
+
+ // Validate fields in forms
+ const validateFormFields = useCallback(
+ (name: string, value: string) => {
+ const validator = stateValidatorSchema;
+ // Making sure that stateValidatorSchema name is same in
+ // stateSchema
+ if (!validator[name]) return;
+
+ const field = validator[name];
+
+ let error = '';
+ error = isRequired(value, field!.required);
+
+ if (isObject(field['validator']) && error === '') {
+ const fieldValidator = field['validator'];
+
+ // Test the function callback if the value is meet the criteria
+ const testFunc = fieldValidator!['func'];
+ if (!testFunc!(value)) {
+ error = fieldValidator!['error']!;
+ }
+ }
+
+ return error;
+ },
+ [stateValidatorSchema],
+ );
+
+ // Set Initial Error State
+ // When hooks was first rendered...
+ const setInitialErrorState = useCallback(() => {
+ Object.keys(errors).map((name) =>
+ setErrors((prevState) => ({
+ ...prevState,
+ [name]: validateFormFields(name, values[name] as string),
+ })),
+ );
+ }, [errors, values, validateFormFields]);
+
+ // Used to disable submit button if there's a value in errors
+ // or the required field in state has no value.
+ // Wrapped in useCallback to cached the function to avoid intensive memory leaked
+ // in every re-render in component
+ const validateErrorState = useCallback(
+ () => Object.values(errors).some((error) => error),
+ [errors],
+ );
+
+ // For every changed in our state this will be fired
+ // To be able to disable the button
+ useEffect(() => {
+ if (isDirty) {
+ setDisable(validateErrorState());
+ }
+ }, [errors, isDirty, validateErrorState]);
+
+ // Event handler for handling changes in input.
+ const handleOnChange = useCallback(
+ (event: ChangeEvent