mirror of
https://github.com/Nezumi-2711/react-training.git
synced 2026-09-22 13:38:51 +00:00
Apply form hook for room page
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
import { FieldValues, RegisterOptions, useFormContext } from 'react-hook-form';
|
import {
|
||||||
|
FieldValues,
|
||||||
|
RegisterOptions,
|
||||||
|
UseFormRegister,
|
||||||
|
useFormContext,
|
||||||
|
} from 'react-hook-form';
|
||||||
import { StyledSelect } from './styled';
|
import { StyledSelect } from './styled';
|
||||||
|
import React, { ReactNode } from 'react';
|
||||||
|
|
||||||
export interface ISelectOptions {
|
export interface ISelectOptions {
|
||||||
value: string;
|
value: string;
|
||||||
@@ -8,31 +14,81 @@ export interface ISelectOptions {
|
|||||||
interface ISelect {
|
interface ISelect {
|
||||||
options: ISelectOptions[];
|
options: ISelectOptions[];
|
||||||
optionsConfigForm?: RegisterOptions<FieldValues, string> | undefined;
|
optionsConfigForm?: RegisterOptions<FieldValues, string> | undefined;
|
||||||
value?: number;
|
value?: string;
|
||||||
id: string;
|
onChange?: React.ChangeEventHandler<HTMLSelectElement> | undefined;
|
||||||
|
id?: string;
|
||||||
|
ariaLabel: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Select = ({ options, id, optionsConfigForm }: ISelect) => {
|
interface IRender extends ISelect {
|
||||||
const { register } = useFormContext() ?? {};
|
register: UseFormRegister<FieldValues>;
|
||||||
|
children: ReactNode[];
|
||||||
|
}
|
||||||
|
|
||||||
if(!register) {
|
const RenderSelect = ({
|
||||||
return null;
|
options,
|
||||||
|
id,
|
||||||
|
value,
|
||||||
|
optionsConfigForm,
|
||||||
|
onChange,
|
||||||
|
register,
|
||||||
|
children,
|
||||||
|
ariaLabel,
|
||||||
|
}: IRender) => {
|
||||||
|
if (options && !register) {
|
||||||
|
return (
|
||||||
|
<StyledSelect
|
||||||
|
aria-label={ariaLabel}
|
||||||
|
id={id}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</StyledSelect>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledSelect
|
||||||
|
aria-label={ariaLabel}
|
||||||
|
id={id}
|
||||||
|
value={value}
|
||||||
|
{...register(id!, optionsConfigForm)}
|
||||||
|
onChange={onChange}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</StyledSelect>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Select = ({
|
||||||
|
options,
|
||||||
|
id,
|
||||||
|
optionsConfigForm,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
ariaLabel
|
||||||
|
}: ISelect) => {
|
||||||
|
const { register } = useFormContext() ?? {};
|
||||||
|
|
||||||
if (!options) return;
|
if (!options) return;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledSelect
|
<RenderSelect
|
||||||
aria-label="Sort"
|
register={register}
|
||||||
|
options={options}
|
||||||
|
optionsConfigForm={optionsConfigForm}
|
||||||
id={id}
|
id={id}
|
||||||
{...register(id, optionsConfigForm)}
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
ariaLabel={ariaLabel}
|
||||||
>
|
>
|
||||||
{options.map((option) => (
|
{options.map((option) => (
|
||||||
<option value={option.value} key={option.value}>
|
<option value={option.value} key={option.value}>
|
||||||
{option.label}
|
{option.label}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</StyledSelect>
|
</RenderSelect>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ const SortBy = memo(({ options }: ISortByProps) => {
|
|||||||
setSearchParams(searchParams);
|
setSearchParams(searchParams);
|
||||||
};
|
};
|
||||||
|
|
||||||
// prettier-ignore
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
options={options}
|
options={options}
|
||||||
value={sortBy}
|
value={sortBy}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
ariaLabel='Sort'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ export const DASHBOARD = '/dashboard';
|
|||||||
export const USER = '/user';
|
export const USER = '/user';
|
||||||
export const ROOM = '/room';
|
export const ROOM = '/room';
|
||||||
export const OTHER_PATH = '*';
|
export const OTHER_PATH = '*';
|
||||||
export const BASE_URL = 'http://localhost:3000/';
|
export const BASE_URL = 'https://hotel-management-api.loiphan.com/';
|
||||||
export const USER_PATH = 'users';
|
export const USER_PATH = 'users';
|
||||||
export const ROOM_PATH = 'rooms';
|
export const ROOM_PATH = 'rooms';
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ type TRoom = {
|
|||||||
name: string;
|
name: string;
|
||||||
price: number;
|
price: number;
|
||||||
discount: number;
|
discount: number;
|
||||||
description: string;
|
|
||||||
status: boolean;
|
status: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,15 +18,6 @@ const isBool = (value: unknown) => {
|
|||||||
return typeof value === 'boolean';
|
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
|
* Set required error for value
|
||||||
* @param value The value set required or not
|
* @param value The value set required or not
|
||||||
@@ -94,19 +85,16 @@ const searchQuery = (
|
|||||||
columnSearch: string,
|
columnSearch: string,
|
||||||
keySearch: string,
|
keySearch: string,
|
||||||
sort: string,
|
sort: string,
|
||||||
order: string,
|
order: string
|
||||||
) => {
|
) => {
|
||||||
// prettier-ignore
|
const phoneParams = keySearch
|
||||||
const phoneParams = keySearch
|
? `${columnSearch}_like=` + keySearch
|
||||||
? `${columnSearch}_like=` + keySearch
|
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
// prettier-ignore
|
const sortParams = sort
|
||||||
const sortParams = sort
|
? '_sort=' + sort
|
||||||
? '_sort=' + sort
|
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
// prettier-ignore
|
|
||||||
const orderParams = order
|
const orderParams = order
|
||||||
? '_order=' + order
|
? '_order=' + order
|
||||||
: '';
|
: '';
|
||||||
@@ -129,10 +117,9 @@ const searchQuery = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
isObject,
|
|
||||||
isRequired,
|
isRequired,
|
||||||
getPropValues,
|
getPropValues,
|
||||||
getValueFromObj,
|
getValueFromObj,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
REQUIRED_FIELD_ERROR,
|
REQUIRED_FIELD_ERROR
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
* @param value Value need to be checked
|
* @param value Value need to be checked
|
||||||
* @returns A boolean indicating whether or not the argument has valid
|
* @returns A boolean indicating whether or not the argument has valid
|
||||||
*/
|
*/
|
||||||
const isValidNumber = (value: string): boolean => {
|
const isValidNumber = (value: unknown): boolean => {
|
||||||
return /^[0-9]*$/.test(value);
|
return /^[0-9]*$/.test(value as string);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -54,10 +54,11 @@ const useFetch = (
|
|||||||
const response = await fetch(BASE_URL + path + '?' + query);
|
const response = await fetch(BASE_URL + path + '?' + query);
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
|
|
||||||
if (!response.ok)
|
if (!response.ok) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Error code: ${response.status} \n Messages: ${response.statusText}`,
|
`Error code: ${response.status} \n Messages: ${response.text}`,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
setIsPending(false);
|
setIsPending(false);
|
||||||
setData(json);
|
setData(json);
|
||||||
|
|||||||
@@ -1,170 +0,0 @@
|
|||||||
import { useState, useEffect, useCallback, ChangeEvent } from 'react';
|
|
||||||
|
|
||||||
// Utils
|
|
||||||
import { getPropValues, isObject, isRequired } from '../helpers/utils';
|
|
||||||
|
|
||||||
// Types
|
|
||||||
import { TKeyValue, TValidator } from '../globals/types';
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
import { ERROR, INITIAL_STATE_SCHEMA, VALUE } from '../constants/variables';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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,
|
|
||||||
initialValue: string = '',
|
|
||||||
) => {
|
|
||||||
const [values, setValues] = useState<TKeyValue>(INITIAL_STATE_SCHEMA);
|
|
||||||
const [errors, setErrors] = useState(getPropValues(stateSchema, ERROR));
|
|
||||||
const [valid, isValid] = useState(getPropValues(stateSchema));
|
|
||||||
const [disable, setDisable] = useState(true);
|
|
||||||
const [isDirty, setIsDirty] = useState(false);
|
|
||||||
|
|
||||||
// Get a local copy of stateSchema
|
|
||||||
useEffect(() => {
|
|
||||||
setInitialErrorState(initialValue);
|
|
||||||
setDisable(true);
|
|
||||||
isValid(getPropValues(stateSchema));
|
|
||||||
setValues(getPropValues(stateSchema, VALUE));
|
|
||||||
|
|
||||||
// If initial value true, setValues again from stateSchema
|
|
||||||
// and enabled button
|
|
||||||
if (initialValue) {
|
|
||||||
setValues(getPropValues(stateSchema, VALUE));
|
|
||||||
setDisable(false);
|
|
||||||
}
|
|
||||||
}, [initialValue]); // 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 = '';
|
|
||||||
|
|
||||||
// Skip check id field
|
|
||||||
if (name !== 'id' && name !== 'roomId') {
|
|
||||||
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(
|
|
||||||
(initialValue: string) => {
|
|
||||||
Object.keys(errors).map((name) =>
|
|
||||||
setErrors((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
[name]: !initialValue // Skip error when initialValue have values
|
|
||||||
? 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<
|
|
||||||
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
|
|
||||||
>,
|
|
||||||
) => {
|
|
||||||
setIsDirty(true);
|
|
||||||
|
|
||||||
let error = '';
|
|
||||||
const name = (event.target! as HTMLInputElement).name;
|
|
||||||
let value: string | boolean = '';
|
|
||||||
|
|
||||||
if ((event.target! as HTMLInputElement).type === 'checkbox') {
|
|
||||||
value = (event.target! as HTMLInputElement).checked;
|
|
||||||
} else {
|
|
||||||
value = (event.target! as HTMLInputElement).value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
error = validateFormFields(name, value)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
setValues((prevState) => ({ ...prevState, [name]: value }));
|
|
||||||
setErrors((prevState) => ({ ...prevState, [name]: error }));
|
|
||||||
isValid((prevState) => ({ ...prevState, [name]: true }));
|
|
||||||
},
|
|
||||||
[validateFormFields],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleOnSubmit = useCallback(
|
|
||||||
(event: React.FormEvent<HTMLFormElement>) => {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
// 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],
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
handleOnChange,
|
|
||||||
handleOnSubmit,
|
|
||||||
values,
|
|
||||||
errors,
|
|
||||||
disable,
|
|
||||||
setValues,
|
|
||||||
setErrors,
|
|
||||||
valid,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useForm;
|
|
||||||
@@ -1,11 +1,20 @@
|
|||||||
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import Button from '../../commons/styles/Button.ts';
|
import Button from '../../commons/styles/Button.ts';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import {
|
import { TRoom } from '../../globals/types.ts';
|
||||||
TRoom,
|
import { useForm } from 'react-hook-form';
|
||||||
} from '../../globals/types.ts';
|
import { ROOM_PATH } from '../../constants/path.ts';
|
||||||
|
import { STATUS_CODE } from '../../constants/statusCode.ts';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
import { ADD_SUCCESS, EDIT_SUCCESS, errorMsg } from '../../constants/messages.ts';
|
||||||
|
import { sendRequest } from '../../helpers/sendRequest.ts';
|
||||||
|
import Input from '../../commons/styles/Input.ts';
|
||||||
|
import FormRow from '../../components/LabelControl/index.tsx';
|
||||||
|
import { INVALID_DISCOUNT, INVALID_FIELD, REQUIRED_FIELD_ERROR } from '../../constants/formValidateMessage.ts';
|
||||||
|
import { isValidNumber, isValidString } from '../../helpers/validators.ts';
|
||||||
|
import Form from '../../components/Form/index.tsx';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
const FormBtn = styled(Button)`
|
const FormBtn = styled(Button)`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -32,272 +41,126 @@ const RoomForm = ({
|
|||||||
room,
|
room,
|
||||||
isAdd,
|
isAdd,
|
||||||
}: IRoomFormProp) => {
|
}: IRoomFormProp) => {
|
||||||
// const [reset, setReset] = useState(true);
|
const formMethods = useForm<TRoom>();
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
reset,
|
||||||
|
formState: { errors, isDirty, isValid },
|
||||||
|
trigger,
|
||||||
|
} = formMethods;
|
||||||
|
|
||||||
// if (isAdd) {
|
useEffect(() => {
|
||||||
// // If this is add form, reset value
|
if(room) {
|
||||||
// room = null;
|
reset(room);
|
||||||
// }
|
}
|
||||||
|
}, [room, reset]);
|
||||||
|
|
||||||
// // prettier-ignore
|
// Submit form
|
||||||
// const initialValue: string = isAdd
|
const onSubmit = async (room: TRoom) => {
|
||||||
// ? ''
|
try {
|
||||||
// : room!
|
if (isAdd) {
|
||||||
// && room.id.toString();
|
// Add request
|
||||||
|
const response = await sendRequest(
|
||||||
|
ROOM_PATH,
|
||||||
|
JSON.stringify(room),
|
||||||
|
'POST'
|
||||||
|
);
|
||||||
|
|
||||||
// const {
|
if (response.statusCode === STATUS_CODE.CREATE) {
|
||||||
// idValue,
|
toast.success(ADD_SUCCESS);
|
||||||
// nameValue,
|
} else {
|
||||||
// priceValue,
|
throw new Error(errorMsg(response.statusCode, response.msg));
|
||||||
// discountValue,
|
}
|
||||||
// statusValue,
|
} else {
|
||||||
// descriptionValue,
|
// Edit request
|
||||||
// } = getValueFromObj<TRoom>(room);
|
const response = await sendRequest(
|
||||||
|
ROOM_PATH + `/${room!.id}`,
|
||||||
|
JSON.stringify(room),
|
||||||
|
'PUT'
|
||||||
|
);
|
||||||
|
|
||||||
// // Define your state schema
|
if (response.statusCode == STATUS_CODE.OK) {
|
||||||
// // prettier-ignore
|
toast.success(EDIT_SUCCESS);
|
||||||
// const stateSchema: TStateSchema = {
|
} else {
|
||||||
// id: {
|
throw new Error(errorMsg(response.statusCode, response.msg));
|
||||||
// value: idValue || ''
|
}
|
||||||
// },
|
}
|
||||||
// name: {
|
// Reload table data
|
||||||
// value: nameValue || '',
|
setReload(!reload);
|
||||||
// error: ''
|
} catch (error: unknown) {
|
||||||
// },
|
if (error instanceof Error) {
|
||||||
// price: {
|
toast.error(error.message);
|
||||||
// value: priceValue || '',
|
}
|
||||||
// error: ''
|
}
|
||||||
// },
|
|
||||||
// discount: {
|
|
||||||
// value: discountValue || '',
|
|
||||||
// error: ''
|
|
||||||
// },
|
|
||||||
// status: {
|
|
||||||
// value: statusValue || '',
|
|
||||||
// error: ''
|
|
||||||
// },
|
|
||||||
// description: {
|
|
||||||
// value: descriptionValue || '',
|
|
||||||
// error: ''
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // prettier-ignore
|
reset();
|
||||||
// const stateValidatorSchema: TValidator = {
|
onClose();
|
||||||
// name: addValidator({
|
};
|
||||||
// validatorFunc: isValidString,
|
|
||||||
// prop: 'name'
|
|
||||||
// }),
|
|
||||||
// price: addValidator({
|
|
||||||
// validatorFunc: isValidNumber,
|
|
||||||
// prop: 'price',
|
|
||||||
// }),
|
|
||||||
// discount: addValidator({
|
|
||||||
// validatorFunc: isValidDiscount,
|
|
||||||
// customErrorMsg: DISCOUNT_FIELD_ERROR
|
|
||||||
// }),
|
|
||||||
// status: addValidator({
|
|
||||||
// validatorFunc: skipCheck,
|
|
||||||
// prop: 'status',
|
|
||||||
// required: false,
|
|
||||||
// }),
|
|
||||||
// description: addValidator({
|
|
||||||
// validatorFunc: isValidString,
|
|
||||||
// prop: 'description'
|
|
||||||
// }),
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Submit form
|
|
||||||
// const onSubmitForm = async (state: TKeyValue) => {
|
|
||||||
// // Convert to room type
|
|
||||||
// const data: TRoom = {
|
|
||||||
// id: +state.id!,
|
|
||||||
// name: '' + state.name,
|
|
||||||
// discount: +state.discount!,
|
|
||||||
// price: +state.price!,
|
|
||||||
// status: !!state.status,
|
|
||||||
// description: '' + state.description,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// if (isAdd) {
|
|
||||||
// // Add request
|
|
||||||
// const response = await sendRequest(
|
|
||||||
// ROOM_PATH,
|
|
||||||
// JSON.stringify(data),
|
|
||||||
// 'POST',
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if (response.statusCode === STATUS_CODE.CREATE) {
|
|
||||||
// toast.success(ADD_SUCCESS);
|
|
||||||
|
|
||||||
// onResetForm();
|
|
||||||
// } else {
|
|
||||||
// throw new Error(errorMsg(response.statusCode, response.msg));
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// // Edit request
|
|
||||||
// const response = await sendRequest(
|
|
||||||
// ROOM_PATH + `/${room!.id}`,
|
|
||||||
// JSON.stringify(data),
|
|
||||||
// 'PUT',
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if (response.statusCode == STATUS_CODE.OK) {
|
|
||||||
// toast.success(EDIT_SUCCESS);
|
|
||||||
// } else {
|
|
||||||
// throw new Error(errorMsg(response.statusCode, response.msg));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // Reload table data
|
|
||||||
// setReload(!reload);
|
|
||||||
// } catch (error: unknown) {
|
|
||||||
// if (error instanceof Error) {
|
|
||||||
// toast.error(error.message);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// onClose();
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Close and reset form
|
|
||||||
// const closeAndReset = () => {
|
|
||||||
// onClose();
|
|
||||||
// onResetForm();
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // prettier-ignore
|
|
||||||
// const {
|
|
||||||
// values,
|
|
||||||
// errors,
|
|
||||||
// valid,
|
|
||||||
// handleOnChange,
|
|
||||||
// handleOnSubmit,
|
|
||||||
// disable } =
|
|
||||||
// useForm(
|
|
||||||
// stateSchema,
|
|
||||||
// stateValidatorSchema,
|
|
||||||
// onSubmitForm,
|
|
||||||
// initialValue
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // prettier-ignore
|
|
||||||
// const {
|
|
||||||
// id,
|
|
||||||
// name,
|
|
||||||
// price,
|
|
||||||
// discount,
|
|
||||||
// status,
|
|
||||||
// description
|
|
||||||
// } = values;
|
|
||||||
|
|
||||||
// // Clear form value when this is a add form
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (isAdd) {
|
|
||||||
// Object.keys(values).forEach((key) => (values[key] = ''));
|
|
||||||
// }
|
|
||||||
// }, [isAdd]); // eslint-disable-line
|
|
||||||
|
|
||||||
// // Reset form
|
|
||||||
// const onResetForm = () => {
|
|
||||||
// setReset(!reset);
|
|
||||||
// Object.keys(values).forEach((key) => (values[key] = ''));
|
|
||||||
// };
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// <Form onSubmit={handleOnSubmit}>
|
<Form onSubmit={handleSubmit(onSubmit)}>
|
||||||
// <Input type="hidden" name="id" value={id as string} />
|
<Input type="hidden" id="id" {...register('id')} />
|
||||||
// <FormRow
|
<FormRow label="Name" error={errors?.name?.message}>
|
||||||
// label="Name"
|
<Input
|
||||||
// error={
|
type="text"
|
||||||
// // prettier-ignore
|
id="name"
|
||||||
// errors.name && valid.name
|
{...register('name', {
|
||||||
// ? (errors.name as string)
|
required: REQUIRED_FIELD_ERROR,
|
||||||
// : ''
|
validate: {
|
||||||
// }
|
checkValidName: (value) =>
|
||||||
// >
|
isValidString(value) || INVALID_FIELD,
|
||||||
// <Input
|
},
|
||||||
// type="text"
|
onChange: () => trigger('name'),
|
||||||
// name="name"
|
})}
|
||||||
// value={name as string}
|
/>
|
||||||
// onChange={handleOnChange}
|
</FormRow>
|
||||||
// />
|
|
||||||
// </FormRow>
|
|
||||||
// <FormRow
|
|
||||||
// label="Price"
|
|
||||||
// error={
|
|
||||||
// // prettier-ignore
|
|
||||||
// errors.price && valid.price
|
|
||||||
// ? (errors.price as string)
|
|
||||||
// : ''
|
|
||||||
// }
|
|
||||||
// >
|
|
||||||
// <Input
|
|
||||||
// type="text"
|
|
||||||
// name="price"
|
|
||||||
// value={price as string}
|
|
||||||
// onChange={handleOnChange}
|
|
||||||
// />
|
|
||||||
// </FormRow>
|
|
||||||
|
|
||||||
// <FormRow
|
<FormRow
|
||||||
// label="Discount"
|
label="Price"
|
||||||
// error={
|
error={errors?.price?.message}
|
||||||
// // prettier-ignore
|
>
|
||||||
// errors.discount && valid.discount
|
<Input
|
||||||
// ? (errors.discount as string)
|
type="text"
|
||||||
// : ''
|
id="price"
|
||||||
// }
|
{...register('price', {
|
||||||
// >
|
required: REQUIRED_FIELD_ERROR,
|
||||||
// <Input
|
validate: {
|
||||||
// type="text"
|
checkIdentifiedCode: (v) => isValidNumber(v) || INVALID_FIELD,
|
||||||
// name="discount"
|
},
|
||||||
// value={discount as string}
|
onChange: () => trigger('price'),
|
||||||
// onChange={handleOnChange}
|
})}
|
||||||
// />
|
/>
|
||||||
// </FormRow>
|
</FormRow>
|
||||||
|
|
||||||
// <FormRow label="Status">
|
<FormRow label="discount" error={errors?.discount?.message}>
|
||||||
// <Input
|
<Input
|
||||||
// type="checkbox"
|
type="text"
|
||||||
// name="status"
|
id="phone"
|
||||||
// checked={status as boolean}
|
{...register('discount', {
|
||||||
// onChange={handleOnChange}
|
required: REQUIRED_FIELD_ERROR,
|
||||||
// />
|
validate: {
|
||||||
// </FormRow>
|
checkPhoneNum: (v) => isValidNumber(v) || INVALID_DISCOUNT,
|
||||||
|
},
|
||||||
|
onChange: () => trigger('discount'),
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</FormRow>
|
||||||
|
|
||||||
// <FormRow
|
<Form.Action>
|
||||||
// label="Description"
|
<FormBtn type="submit" name="submit" disabled={!isDirty || !isValid}>
|
||||||
// error={
|
{
|
||||||
// // prettier-ignore
|
// prettier-ignore
|
||||||
// errors.description && valid.description
|
isAdd
|
||||||
// ? (errors.description as string)
|
? 'Add'
|
||||||
// : ''
|
: 'Save'
|
||||||
// }
|
}
|
||||||
// >
|
</FormBtn>
|
||||||
// <TextArea
|
<FormBtn type="button" styled="secondary" onClick={onClose}>
|
||||||
// name="description"
|
Close
|
||||||
// rows={3}
|
</FormBtn>
|
||||||
// value={description as string}
|
</Form.Action>
|
||||||
// onChange={handleOnChange}
|
</Form>
|
||||||
// />
|
|
||||||
// </FormRow>
|
|
||||||
|
|
||||||
// <Form.Action>
|
|
||||||
// <FormBtn type="submit" name="submit" disabled={disable}>
|
|
||||||
// {
|
|
||||||
// // prettier-ignore
|
|
||||||
// isAdd
|
|
||||||
// ? 'Add'
|
|
||||||
// : 'Save'
|
|
||||||
// }
|
|
||||||
// </FormBtn>
|
|
||||||
// <FormBtn type="button" styled="secondary" onClick={closeAndReset}>
|
|
||||||
// Close
|
|
||||||
// </FormBtn>
|
|
||||||
// </Form.Action>
|
|
||||||
// </Form>
|
|
||||||
<p></p>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ const RoomRow = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const { id, name, price, discount, status } = room;
|
const { id, name, price, status } = room;
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const statusText = status
|
const statusText = status
|
||||||
@@ -79,7 +79,6 @@ const RoomRow = ({
|
|||||||
<div>{id}</div>
|
<div>{id}</div>
|
||||||
<div>{name}</div>
|
<div>{name}</div>
|
||||||
<div>{price}</div>
|
<div>{price}</div>
|
||||||
<div>{discount}</div>
|
|
||||||
<div>{statusText}</div>
|
<div>{statusText}</div>
|
||||||
|
|
||||||
<Menus.Menu>
|
<Menus.Menu>
|
||||||
@@ -162,12 +161,11 @@ const RoomTable = ({
|
|||||||
|
|
||||||
{rooms.length ? (
|
{rooms.length ? (
|
||||||
<Menus>
|
<Menus>
|
||||||
<Table columns="10% 30% 20% 10% 20% 5%">
|
<Table columns="10% 40% 20% 20% 5%">
|
||||||
<Table.Header>
|
<Table.Header>
|
||||||
<div>Id</div>
|
<div>Id</div>
|
||||||
<div>Name</div>
|
<div>Name</div>
|
||||||
<div>Price</div>
|
<div>Price</div>
|
||||||
<div>Discount</div>
|
|
||||||
<div>Status</div>
|
<div>Status</div>
|
||||||
</Table.Header>
|
</Table.Header>
|
||||||
<Table.Body<TRoom>
|
<Table.Body<TRoom>
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ const UserForm = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO Update status when user create
|
// TODO Update status when user create
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Edit request
|
// Edit request
|
||||||
const response = await sendRequest(
|
const response = await sendRequest(
|
||||||
@@ -190,7 +191,7 @@ const UserForm = ({
|
|||||||
</FormRow>
|
</FormRow>
|
||||||
|
|
||||||
<FormRow label="Room">
|
<FormRow label="Room">
|
||||||
<Select id="roomId" options={options!} />
|
<Select id="roomId" options={options!} ariaLabel='RoomId'/>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
|
|
||||||
<FormRow label="Address" error={errors.address?.message}>
|
<FormRow label="Address" error={errors.address?.message}>
|
||||||
@@ -217,7 +218,7 @@ const UserForm = ({
|
|||||||
: 'Save'
|
: 'Save'
|
||||||
}
|
}
|
||||||
</FormBtn>
|
</FormBtn>
|
||||||
<FormBtn type="button" styled="secondary">
|
<FormBtn type="button" styled="secondary" onClick={onClose}>
|
||||||
Close
|
Close
|
||||||
</FormBtn>
|
</FormBtn>
|
||||||
</Form.Action>
|
</Form.Action>
|
||||||
|
|||||||
Reference in New Issue
Block a user