mirror of
https://github.com/Nezumi-2711/react-training.git
synced 2026-09-22 20:01:59 +00:00
Update method for user pages and format code
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
// Components
|
||||
import Menus from '@component/Menus';
|
||||
@@ -21,24 +20,18 @@ import { StyledOperationTable } from './styled';
|
||||
import Direction from '@commonStyle/Direction';
|
||||
import Spinner from '@commonStyle/Spinner';
|
||||
|
||||
// Hooks
|
||||
import { useRooms } from '@hook/rooms/useRooms';
|
||||
|
||||
interface IRoomTable {
|
||||
reload: boolean;
|
||||
setReload: Dispatch<SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
const RoomTable = ({ reload, setReload }: IRoomTable) => {
|
||||
const RoomTable = () => {
|
||||
const columnName = ['Id', 'Name', 'Price', 'Status'];
|
||||
const [nameSearch, setNameSearch] = useState('');
|
||||
const [searchParams] = useSearchParams();
|
||||
const [rooms, setRooms] = useState<IRoom[]>([]);
|
||||
const sortByValue = searchParams.get('sortBy')
|
||||
? searchParams.get('sortBy')!
|
||||
: '';
|
||||
const orderByValue = searchParams.get('orderBy')
|
||||
? searchParams.get('orderBy')!
|
||||
: '';
|
||||
|
||||
const { isLoading, rooms } = useRooms();
|
||||
|
||||
const renderRoomRow = useCallback(
|
||||
(room: IRoom) => <RoomRow room={room} key={room.id} />,
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Direction>
|
||||
@@ -46,33 +39,20 @@ const RoomTable = ({ reload, setReload }: IRoomTable) => {
|
||||
<OrderBy options={ORDERBY_OPTIONS} />
|
||||
|
||||
<SortBy options={ROOM_PAGE.SORTBY_OPTIONS} />
|
||||
<Search
|
||||
setValueSearch={setNameSearch}
|
||||
setPlaceHolder="Search by name..."
|
||||
/>
|
||||
<Search setPlaceHolder="Search by name..." />
|
||||
</StyledOperationTable>
|
||||
|
||||
{isPending && <Spinner />}
|
||||
{isLoading && <Spinner />}
|
||||
|
||||
{rooms.length ? (
|
||||
{rooms && rooms.length ? (
|
||||
<Menus>
|
||||
<Table columns="10% 40% 20% 20% 5%">
|
||||
<Table.Header headerColumn={columnName}/>
|
||||
<Table.Body<IRoom>
|
||||
data={rooms}
|
||||
render={(room: IRoom) => (
|
||||
<RoomRow
|
||||
room={room}
|
||||
key={room.id}
|
||||
reload={reload}
|
||||
setReload={setReload}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Table.Header headerColumn={columnName} />
|
||||
<Table.Body<IRoom> data={rooms} render={renderRoomRow} />
|
||||
</Table>
|
||||
</Menus>
|
||||
) : (
|
||||
!isPending && <Message>No data to show here!</Message>
|
||||
!isLoading && <Message>No data to show here!</Message>
|
||||
)}
|
||||
</Direction>
|
||||
</>
|
||||
|
||||
@@ -1,40 +1,30 @@
|
||||
import { Dispatch, SetStateAction, useEffect } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import styled from 'styled-components';
|
||||
|
||||
// Hooks
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
// Styled
|
||||
import Button from '@commonStyle/Button.ts';
|
||||
import Input from '@commonStyle/Input.ts';
|
||||
|
||||
// Types
|
||||
import { Nullable } from '@type/common.ts';
|
||||
import { IRoom } from '@type/rooms.ts';
|
||||
|
||||
// Constants
|
||||
import { ADD_SUCCESS, EDIT_SUCCESS } from '@constant/messages.ts';
|
||||
import {
|
||||
INVALID_DISCOUNT,
|
||||
INVALID_FIELD,
|
||||
REQUIRED_FIELD_ERROR,
|
||||
} from '@constant/formValidateMessage.ts';
|
||||
import { INIT_VALUE_ROOM_FORM, REGEX } from '../../constants/commons.ts';
|
||||
import { REGEX } from '../../constants/commons.ts';
|
||||
|
||||
// Helpers
|
||||
import {
|
||||
isValidDiscount,
|
||||
isValidRegex,
|
||||
isValidString,
|
||||
} from '@helper/validators.ts';
|
||||
import { isValidRegex, isValidString } from '@helper/validators.ts';
|
||||
|
||||
// Components
|
||||
import FormRow from '@component/LabelControl/index.tsx';
|
||||
import Form from '@component/Form/index.tsx';
|
||||
|
||||
// Services
|
||||
import { addRoom, updateRoom } from '@service/roomServices.ts';
|
||||
// Hooks
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useCreateRoom } from '@hook/rooms/useCreateRoom.ts';
|
||||
import { useUpdateRoom } from '@hook/rooms/useUpdateRoom.ts';
|
||||
|
||||
const FormBtn = styled(Button)`
|
||||
width: 100%;
|
||||
@@ -48,65 +38,51 @@ const FormBtn = styled(Button)`
|
||||
|
||||
interface IRoomFormProp {
|
||||
onCloseModal?: () => void;
|
||||
reload?: boolean;
|
||||
setReload?: Dispatch<SetStateAction<boolean>>;
|
||||
roomEdit?: Nullable<IRoom>;
|
||||
room?: IRoom;
|
||||
}
|
||||
|
||||
const RoomForm = ({
|
||||
onCloseModal,
|
||||
reload,
|
||||
setReload,
|
||||
roomEdit,
|
||||
}: IRoomFormProp) => {
|
||||
const formMethods = useForm<IRoom>();
|
||||
const RoomForm = ({ onCloseModal, room }: IRoomFormProp) => {
|
||||
const { isCreating, createRoom } = useCreateRoom();
|
||||
const { isUpdating, updateRoom } = useUpdateRoom();
|
||||
const isLoading = isCreating || isUpdating;
|
||||
const { id: editId, ...editValues } = { ...room };
|
||||
const formMethods = useForm<IRoom>({
|
||||
defaultValues: editId
|
||||
? editValues
|
||||
: {},
|
||||
});
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { errors, isDirty, isValid, isSubmitting },
|
||||
formState: { errors, isDirty, isValid },
|
||||
trigger,
|
||||
} = formMethods;
|
||||
|
||||
useEffect(() => {
|
||||
if (roomEdit) {
|
||||
reset(roomEdit);
|
||||
} else {
|
||||
reset(INIT_VALUE_ROOM_FORM);
|
||||
}
|
||||
}, [roomEdit, reset]);
|
||||
|
||||
// Submit form
|
||||
const onSubmit = async (room: IRoom) => {
|
||||
// Calculate final price
|
||||
room.finalPrice = room.price - (room.price * room.discount) / 100;
|
||||
|
||||
if (!roomEdit) {
|
||||
const onSubmit = async (newRoom: IRoom) => {
|
||||
if (!editId) {
|
||||
// Add request
|
||||
const response = await addRoom(room);
|
||||
|
||||
if (response) {
|
||||
toast.success(ADD_SUCCESS);
|
||||
}
|
||||
createRoom(newRoom, {
|
||||
onSuccess: () => {
|
||||
reset();
|
||||
onCloseModal?.();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// Edit request
|
||||
const response = await updateRoom(room);
|
||||
|
||||
if (response) {
|
||||
toast.success(EDIT_SUCCESS);
|
||||
}
|
||||
newRoom.id = editId!;
|
||||
updateRoom(newRoom, {
|
||||
onSuccess: () => {
|
||||
reset();
|
||||
onCloseModal?.();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Reload table data
|
||||
setReload!(!reload);
|
||||
|
||||
reset();
|
||||
onCloseModal!();
|
||||
};
|
||||
|
||||
return (
|
||||
<Form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Input type="hidden" id="id" {...register('id')} />
|
||||
<FormRow label="Name" error={errors?.name?.message}>
|
||||
<Input
|
||||
type="text"
|
||||
@@ -114,7 +90,8 @@ const RoomForm = ({
|
||||
{...register('name', {
|
||||
required: REQUIRED_FIELD_ERROR,
|
||||
validate: {
|
||||
checkValidRoomName: (value) => isValidString(value) || INVALID_FIELD,
|
||||
checkValidRoomName: (value) =>
|
||||
isValidString(value) || INVALID_FIELD,
|
||||
},
|
||||
onChange: () => trigger('name'),
|
||||
})}
|
||||
@@ -130,41 +107,27 @@ const RoomForm = ({
|
||||
required: REQUIRED_FIELD_ERROR,
|
||||
validate: {
|
||||
checkPrice: (v) =>
|
||||
isValidRegex(new RegExp(REGEX.NUMBER), v.toString()) || INVALID_FIELD,
|
||||
isValidRegex(new RegExp(REGEX.NUMBER), v.toString()) ||
|
||||
INVALID_FIELD,
|
||||
},
|
||||
onChange: () => trigger('price'),
|
||||
})}
|
||||
/>
|
||||
</FormRow>
|
||||
|
||||
<FormRow label="discount" error={errors?.discount?.message}>
|
||||
<Input
|
||||
type="text"
|
||||
id="phone"
|
||||
{...register('discount', {
|
||||
valueAsNumber: true,
|
||||
required: REQUIRED_FIELD_ERROR,
|
||||
validate: {
|
||||
checkDiscount: (v) => isValidDiscount(v) || INVALID_DISCOUNT,
|
||||
},
|
||||
onChange: () => trigger('discount'),
|
||||
})}
|
||||
/>
|
||||
</FormRow>
|
||||
|
||||
<Form.Action>
|
||||
<FormBtn
|
||||
type="submit"
|
||||
name="submit"
|
||||
disabled={!isDirty || !isValid || isSubmitting}
|
||||
disabled={!isDirty || !isValid || isLoading}
|
||||
>
|
||||
{
|
||||
!roomEdit
|
||||
!editId
|
||||
? 'Add'
|
||||
: 'Save'
|
||||
}
|
||||
</FormBtn>
|
||||
<FormBtn type="button" styled="secondary" onClick={onCloseModal}>
|
||||
<FormBtn type="button" variations="secondary" onClick={onCloseModal}>
|
||||
Close
|
||||
</FormBtn>
|
||||
</Form.Action>
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
// Constants
|
||||
import { ROOM_PATH } from '@constant/path';
|
||||
import { STATUS_CODE } from '@constant/responseStatus';
|
||||
import { CONFIRM_DELETE, DELETE_SUCCESS } from '@constant/messages';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
// Helpers
|
||||
import { sendRequest } from '@helper/sendRequest';
|
||||
import { formatCurrency } from '@helper/helper';
|
||||
|
||||
// Types
|
||||
@@ -20,38 +13,47 @@ import Table from '@component/Table';
|
||||
import Menus from '@component/Menus';
|
||||
import { RiEditBoxFill } from 'react-icons/ri';
|
||||
import { HiTrash } from 'react-icons/hi';
|
||||
import ConfirmMessage from '@component/ConfirmMessage';
|
||||
|
||||
// Hooks
|
||||
import { useDeleteRoom } from '@hook/rooms/useDeleteRoom';
|
||||
|
||||
// Constants
|
||||
import { FORM } from '@constant/commons';
|
||||
|
||||
interface IRoomRow {
|
||||
room: IRoom;
|
||||
reload: boolean;
|
||||
setReload: Dispatch<SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
const RoomRow = ({ room, reload, setReload }: IRoomRow) => {
|
||||
const handleDelete = async (room: IRoom) => {
|
||||
if (confirm(CONFIRM_DELETE)) {
|
||||
const response = await sendRequest(ROOM_PATH + `/${room.id}`, 'DELETE');
|
||||
|
||||
if (response.statusCode === STATUS_CODE.OK) {
|
||||
toast.success(DELETE_SUCCESS);
|
||||
|
||||
// Reload table
|
||||
setReload(!reload);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const { id, name, finalPrice, status } = room;
|
||||
|
||||
const RoomRow = ({ room }: IRoomRow) => {
|
||||
const { id, name, price, status } = room;
|
||||
const { isDeleting, deleteRoom } = useDeleteRoom();
|
||||
const statusText = status
|
||||
? 'Unavailable'
|
||||
: 'Available';
|
||||
const formattedPrice = useMemo(() => formatCurrency(price), [price]);
|
||||
const renderEditBtn = useCallback(
|
||||
(onCloseModal: () => void) => (
|
||||
<Menus.Button onClick={onCloseModal} icon={<RiEditBoxFill />}>
|
||||
Edit
|
||||
</Menus.Button>
|
||||
),
|
||||
[]
|
||||
);
|
||||
const renderDeleteBtn = useCallback(
|
||||
(onCloseModal: () => void) => (
|
||||
<Menus.Button icon={<HiTrash />} onClick={onCloseModal}>
|
||||
Delete
|
||||
</Menus.Button>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
<div>{id}</div>
|
||||
<div>{name}</div>
|
||||
<div>{formatCurrency(finalPrice)}</div>
|
||||
<div>{formattedPrice}</div>
|
||||
<div>{statusText}</div>
|
||||
|
||||
<div>
|
||||
@@ -61,24 +63,25 @@ const RoomRow = ({ room, reload, setReload }: IRoomRow) => {
|
||||
|
||||
<Menus.List id={id.toString()}>
|
||||
<Modal.Open
|
||||
modalName="edit"
|
||||
renderChildren={(onCloseModal) => (
|
||||
<Menus.Button onClick={onCloseModal} icon={<RiEditBoxFill />}>
|
||||
Edit
|
||||
</Menus.Button>
|
||||
)}
|
||||
modalName={FORM.EDIT}
|
||||
renderChildren={renderEditBtn}
|
||||
/>
|
||||
<Modal.Open
|
||||
modalName={FORM.DELETE}
|
||||
renderChildren={renderDeleteBtn}
|
||||
/>
|
||||
|
||||
<Menus.Button
|
||||
icon={<HiTrash />}
|
||||
onClick={() => handleDelete(room)}
|
||||
>
|
||||
Delete
|
||||
</Menus.Button>
|
||||
</Menus.List>
|
||||
|
||||
<Modal.Window name="edit" title="Edit Room">
|
||||
<RoomForm roomEdit={room} setReload={setReload} reload={reload} />
|
||||
<Modal.Window name={FORM.EDIT} title="Edit Room">
|
||||
<RoomForm room={room} />
|
||||
</Modal.Window>
|
||||
|
||||
<Modal.Window name={FORM.DELETE} title="Delete Room">
|
||||
<ConfirmMessage
|
||||
disabled={isDeleting}
|
||||
message={`Are you sure to delete ${name}?`}
|
||||
onConfirm={() => deleteRoom(id)}
|
||||
/>
|
||||
</Modal.Window>
|
||||
</Menus.Menu>
|
||||
</Modal>
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
// Components
|
||||
import RoomTable from './RomTable';
|
||||
import RoomForm from './RoomForm';
|
||||
import Modal from '@component/Modal';
|
||||
|
||||
// Styled
|
||||
import { StyledRoom, Title } from './styled';
|
||||
import Direction from '@commonStyle/Direction.ts';
|
||||
import Button from '@commonStyle/Button';
|
||||
|
||||
// Types
|
||||
import Modal from '@component/Modal';
|
||||
|
||||
const Room = () => {
|
||||
const [reload, setReload] = useState(true);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledRoom>
|
||||
@@ -29,12 +23,12 @@ const Room = () => {
|
||||
)}
|
||||
/>
|
||||
<Modal.Window name="room-form" title="Add form">
|
||||
<RoomForm setReload={setReload} reload={reload} />
|
||||
<RoomForm />
|
||||
</Modal.Window>
|
||||
</Modal>
|
||||
</Direction>
|
||||
|
||||
<RoomTable reload={reload} setReload={setReload} />
|
||||
<RoomTable />
|
||||
</StyledRoom>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
// Hooks
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { useCreateUser } from '@hook/users/useCreateUser.ts';
|
||||
import { useUpdateUser } from '@hook/users/useUpdateUser.ts';
|
||||
|
||||
// Styled
|
||||
import Input from '@commonStyle/Input.ts';
|
||||
@@ -16,139 +9,73 @@ import Input from '@commonStyle/Input.ts';
|
||||
// Components
|
||||
import Form from '@component/Form/index.tsx';
|
||||
import FormRow from '@component/LabelControl/index.tsx';
|
||||
import Select, { ISelectOptions } from '@component/Select/index.tsx';
|
||||
|
||||
// Helpers
|
||||
import { isEmptyObj, isValidRegex } from '@helper/validators.ts';
|
||||
import { isValidRegex } from '@helper/validators.ts';
|
||||
|
||||
// Constants
|
||||
import { ADD_SUCCESS, EDIT_SUCCESS } from '@constant/messages.ts';
|
||||
import {
|
||||
INVALID_FIELD,
|
||||
INVALID_PHONE,
|
||||
REQUIRED_FIELD_ERROR,
|
||||
} from '@constant/formValidateMessage.ts';
|
||||
import { INIT_VALUE_USER_FORM, REGEX } from '@constant/commons.ts';
|
||||
import { REGEX } from '@constant/commons.ts';
|
||||
|
||||
// Styled
|
||||
import { FormBtn } from './styled.ts';
|
||||
|
||||
// Services
|
||||
import { getAllRoom, updateRoomStatus } from '@service/roomServices.ts';
|
||||
import { createUser, updateUser } from '@service/userServices.ts';
|
||||
|
||||
// Types
|
||||
import { Nullable } from '@type/common.ts';
|
||||
import { IUser } from '@type/users.ts';
|
||||
import { IRoom } from '@type/rooms.ts';
|
||||
|
||||
interface IUserFormProp {
|
||||
onCloseModal?: () => void;
|
||||
reload: boolean;
|
||||
setReload: Dispatch<SetStateAction<boolean>>;
|
||||
user?: Nullable<IUser>;
|
||||
user?: IUser;
|
||||
}
|
||||
|
||||
const UserForm = ({ onCloseModal, reload, setReload, user }: IUserFormProp) => {
|
||||
const formMethods = useForm<IUser>();
|
||||
const UserForm = ({ onCloseModal, user }: IUserFormProp) => {
|
||||
const { isCreating, createUser } = useCreateUser();
|
||||
const { isUpdating, updateUser } = useUpdateUser();
|
||||
const isLoading = isCreating || isUpdating;
|
||||
const {id: editId, ...editValues} = {...user};
|
||||
|
||||
const formMethods = useForm<IUser>({
|
||||
defaultValues: editId
|
||||
? editValues
|
||||
: {}
|
||||
});
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { errors, isDirty, isValid, isSubmitting },
|
||||
formState: { errors, isDirty, isValid },
|
||||
trigger,
|
||||
} = formMethods;
|
||||
const [rooms, setRooms] = useState<IRoom[]>([]);
|
||||
const [options, setOptions] = useState<ISelectOptions[]>();
|
||||
|
||||
// Init value when edit form and load options
|
||||
useEffect(() => {
|
||||
const load = async () => {
|
||||
const options: ISelectOptions[] = [];
|
||||
const tempUser = !user ? { roomId: 0 } : { ...user };
|
||||
|
||||
// Load and set default options room
|
||||
if (rooms.length > 0) {
|
||||
// Init first options
|
||||
options.push({
|
||||
label: '---Select---',
|
||||
value: '0',
|
||||
});
|
||||
|
||||
rooms.forEach((item) => {
|
||||
if (!item.status || tempUser?.roomId === item.id)
|
||||
options.push({
|
||||
label: item.name!,
|
||||
value: item.id!.toString(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (options.length > 0) {
|
||||
setOptions(options);
|
||||
}
|
||||
|
||||
if (!isEmptyObj(tempUser)) {
|
||||
// Init value
|
||||
reset(tempUser);
|
||||
} else {
|
||||
reset(INIT_VALUE_USER_FORM);
|
||||
}
|
||||
};
|
||||
|
||||
load();
|
||||
}, [reset, user, rooms]);
|
||||
|
||||
// Submit form
|
||||
const onSubmit = useCallback(
|
||||
async (newUser: IUser) => {
|
||||
const onSubmit =
|
||||
(newUser: IUser) => {
|
||||
if (!user) {
|
||||
// Add request
|
||||
const response = await createUser(newUser);
|
||||
|
||||
if (response) {
|
||||
toast.success(ADD_SUCCESS);
|
||||
}
|
||||
|
||||
// Update room status
|
||||
updateRoomStatus(newUser.roomId, true);
|
||||
createUser(newUser, {
|
||||
onSuccess: () => {
|
||||
reset();
|
||||
onCloseModal?.();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// Edit request
|
||||
const response = await updateUser(newUser);
|
||||
|
||||
if (response) {
|
||||
toast.success(EDIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Update room status
|
||||
updateRoomStatus(user!.roomId, true, newUser.roomId);
|
||||
}
|
||||
// Reload table data
|
||||
setReload(!reload);
|
||||
|
||||
reset();
|
||||
onCloseModal!();
|
||||
},
|
||||
[onCloseModal, reload, reset, setReload, user]
|
||||
);
|
||||
|
||||
// Load all rooms
|
||||
useEffect(() => {
|
||||
const loadRoom = async () => {
|
||||
const rooms = await getAllRoom();
|
||||
|
||||
if (rooms) {
|
||||
setRooms(rooms);
|
||||
newUser.id = editId!;
|
||||
updateUser(newUser, {
|
||||
onSuccess: () => {
|
||||
reset();
|
||||
onCloseModal?.();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
loadRoom();
|
||||
}, [onSubmit]);
|
||||
|
||||
return (
|
||||
<FormProvider {...formMethods}>
|
||||
<Form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Input type="hidden" id="id" {...register('id')} />
|
||||
<FormRow label="Full Name" error={errors?.name?.message}>
|
||||
<Input
|
||||
type="text"
|
||||
@@ -164,25 +91,6 @@ const UserForm = ({ onCloseModal, reload, setReload, user }: IUserFormProp) => {
|
||||
/>
|
||||
</FormRow>
|
||||
|
||||
<FormRow
|
||||
label="Identified Code"
|
||||
error={errors?.identifiedCode?.message}
|
||||
>
|
||||
<Input
|
||||
type="text"
|
||||
id="identifiedCode"
|
||||
{...register('identifiedCode', {
|
||||
required: REQUIRED_FIELD_ERROR,
|
||||
validate: {
|
||||
checkIdentifiedCode: (v) =>
|
||||
isValidRegex(new RegExp(REGEX.NUMBER), v.toString()) ||
|
||||
INVALID_FIELD,
|
||||
},
|
||||
onChange: () => trigger('identifiedCode'),
|
||||
})}
|
||||
/>
|
||||
</FormRow>
|
||||
|
||||
<FormRow label="Phone" error={errors?.phone?.message}>
|
||||
<Input
|
||||
type="text"
|
||||
@@ -198,32 +106,19 @@ const UserForm = ({ onCloseModal, reload, setReload, user }: IUserFormProp) => {
|
||||
/>
|
||||
</FormRow>
|
||||
|
||||
<FormRow label="Room">
|
||||
{options && options.length > 1 ? (
|
||||
<Select
|
||||
id="roomId"
|
||||
options={options!}
|
||||
ariaLabel="RoomId"
|
||||
optionsConfigForm={{
|
||||
valueAsNumber: true,
|
||||
onChange: () => trigger('roomId'),
|
||||
validate: (v) => v !== 0,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<p>No room available!</p>
|
||||
)}
|
||||
</FormRow>
|
||||
|
||||
<Form.Action>
|
||||
<FormBtn
|
||||
type="submit"
|
||||
name="submit"
|
||||
disabled={!isDirty || !isValid || isSubmitting}
|
||||
disabled={!isDirty || !isValid || isLoading}
|
||||
>
|
||||
{!user ? 'Add' : 'Save'}
|
||||
{
|
||||
!user
|
||||
? 'Add'
|
||||
: 'Save'
|
||||
}
|
||||
</FormBtn>
|
||||
<FormBtn type="button" styled="secondary" onClick={onCloseModal}>
|
||||
<FormBtn type="button" variations="secondary" onClick={onCloseModal}>
|
||||
Close
|
||||
</FormBtn>
|
||||
</Form.Action>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
// Components
|
||||
import { RiEditBoxFill } from 'react-icons/ri';
|
||||
import Modal from '@component/Modal';
|
||||
@@ -13,11 +11,9 @@ import { IUser } from '@type/users';
|
||||
|
||||
interface IUserRow {
|
||||
user: IUser;
|
||||
reload: boolean;
|
||||
setReload: Dispatch<SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
const UserRow = ({ user, reload, setReload }: IUserRow) => {
|
||||
const UserRow = ({ user }: IUserRow) => {
|
||||
const { id, name, phone } = user;
|
||||
|
||||
return (
|
||||
@@ -42,7 +38,7 @@ const UserRow = ({ user, reload, setReload }: IUserRow) => {
|
||||
</Menus.List>
|
||||
|
||||
<Modal.Window name="edit" title="Edit user">
|
||||
<UserForm user={user} setReload={setReload} reload={reload} />
|
||||
<UserForm user={user} />
|
||||
</Modal.Window>
|
||||
</Menus.Menu>
|
||||
</Modal>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { Dispatch, SetStateAction, useCallback, useState } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
// Components
|
||||
import Menus from '@component/Menus';
|
||||
@@ -21,50 +20,21 @@ import Direction from '@commonStyle/Direction';
|
||||
import { StyledOperationTable } from './styled';
|
||||
import Spinner from '@commonStyle/Spinner';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getAllUsers } from '@service/userServices';
|
||||
import toast from 'react-hot-toast';
|
||||
// Hooks
|
||||
import { useUsers } from '@hook/users/useUsers';
|
||||
|
||||
interface IUserTable {
|
||||
reload: boolean;
|
||||
setReload: Dispatch<SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
const UserTable = ({ reload, setReload }: IUserTable) => {
|
||||
const UserTable = () => {
|
||||
const columnName = ['Id', 'Name', 'Phone'];
|
||||
|
||||
const [phoneSearch, setPhoneSearch] = useState('');
|
||||
const [searchParams] = useSearchParams();
|
||||
const sortByValue = searchParams.get('sortBy')
|
||||
? searchParams.get('sortBy')!
|
||||
: 'id';
|
||||
const orderByValue = searchParams.get('orderBy')
|
||||
? searchParams.get('orderBy')!
|
||||
: 'asc';
|
||||
|
||||
const {
|
||||
isLoading,
|
||||
data: users,
|
||||
error,
|
||||
} = useQuery({
|
||||
queryKey: ['cabins', sortByValue, orderByValue, phoneSearch],
|
||||
queryFn: () => getAllUsers(sortByValue, orderByValue, phoneSearch),
|
||||
});
|
||||
|
||||
if(error) {
|
||||
toast.error(error.message);
|
||||
}
|
||||
const { isLoading, users } = useUsers();
|
||||
|
||||
const renderUserRow = useCallback(
|
||||
(user: IUser) => (
|
||||
<UserRow
|
||||
user={user}
|
||||
key={user.id}
|
||||
reload={reload}
|
||||
setReload={setReload}
|
||||
/>
|
||||
),
|
||||
[reload, setReload]
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -74,10 +44,7 @@ const UserTable = ({ reload, setReload }: IUserTable) => {
|
||||
<OrderBy options={ORDERBY_OPTIONS} />
|
||||
|
||||
<SortBy options={USER_PAGE.SORTBY_OPTIONS} />
|
||||
<Search
|
||||
setValueSearch={setPhoneSearch}
|
||||
setPlaceHolder="Search by phone..."
|
||||
/>
|
||||
<Search setPlaceHolder="Search by phone..." />
|
||||
</StyledOperationTable>
|
||||
|
||||
{isLoading && <Spinner />}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
// Components
|
||||
import UserTable from './UserTable';
|
||||
|
||||
@@ -17,7 +15,6 @@ import { FORM } from '@constant/commons';
|
||||
|
||||
const User = () => {
|
||||
const TITLE = 'Add user';
|
||||
const [reload, setReload] = useState(true);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -33,12 +30,12 @@ const User = () => {
|
||||
)}
|
||||
/>
|
||||
<Modal.Window name={FORM.USER} title={TITLE}>
|
||||
<UserForm setReload={setReload} reload={reload} />
|
||||
<UserForm />
|
||||
</Modal.Window>
|
||||
</Modal>
|
||||
</Direction>
|
||||
|
||||
<UserTable reload={reload} setReload={setReload} />
|
||||
<UserTable />
|
||||
</StyledUser>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user