mirror of
https://github.com/Nezumi-2711/react-training.git
synced 2026-09-22 20:01:59 +00:00
204 lines
5.1 KiB
TypeScript
204 lines
5.1 KiB
TypeScript
import { useSearchParams } from 'react-router-dom';
|
|
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
|
import toast from 'react-hot-toast';
|
|
|
|
// Components
|
|
import { RiEditBoxFill } from 'react-icons/ri';
|
|
import { IoExit } from 'react-icons/io5';
|
|
import Menus from '../../components/Menus';
|
|
import Table from '../../components/Table';
|
|
import Direction from '../../commons/styles/Direction';
|
|
import Message from '../../components/Message';
|
|
import Search from '../../components/Search';
|
|
import SortBy from '../../components/SortBy';
|
|
import OrderBy from '../../components/OrderBy';
|
|
|
|
// Types
|
|
import { Nullable } from '../../types/common';
|
|
import { IUser } from '../../types/users';
|
|
|
|
// Hooks
|
|
import { useFetch } from '../../hooks/useFetch';
|
|
|
|
// Constants
|
|
import { STATUS_CODE } from '../../constants/responseStatus';
|
|
import { ORDERBY_OPTIONS, USER_PAGE } from '../../constants/variables';
|
|
import { CONFIRM_MESSAGE, DENIED_ACTION } from '../../constants/messages';
|
|
|
|
// Styled
|
|
import { StyledOperationTable } from './styled';
|
|
import Spinner from '../../commons/styles/Spinner';
|
|
|
|
// Services
|
|
import { updateRoomStatus } from '../../services/roomServices';
|
|
import { checkOutUser } from '../../services/userServices';
|
|
|
|
interface IUserRow {
|
|
user: IUser;
|
|
openFormDialog: () => void;
|
|
setUser: Dispatch<SetStateAction<Nullable<IUser>>>;
|
|
reload: boolean;
|
|
setReload: Dispatch<SetStateAction<boolean>>;
|
|
}
|
|
|
|
const UserRow = ({
|
|
user,
|
|
openFormDialog,
|
|
setUser,
|
|
reload,
|
|
setReload,
|
|
}: IUserRow) => {
|
|
const handleEdit = (user: IUser) => {
|
|
setUser(user);
|
|
openFormDialog();
|
|
};
|
|
|
|
const handleCheckOut = async (user: IUser) => {
|
|
if(user.roomId !== 0) {
|
|
if (confirm(CONFIRM_MESSAGE)) {
|
|
const resUpdateStatus = await updateRoomStatus(user.roomId, false);
|
|
const resCheckoutUser = await checkOutUser(user);
|
|
|
|
if (
|
|
resCheckoutUser?.statusCode === STATUS_CODE.OK &&
|
|
resUpdateStatus?.statusCode === STATUS_CODE.OK
|
|
) {
|
|
toast.success('Check out complete!');
|
|
|
|
// Reload table
|
|
setReload(!reload);
|
|
}
|
|
}
|
|
} else {
|
|
toast.error(DENIED_ACTION);
|
|
}
|
|
|
|
};
|
|
|
|
const { id, name, identifiedCode, phone, roomId } = user;
|
|
|
|
return (
|
|
<Table.Row>
|
|
<div>{id}</div>
|
|
<div>{name}</div>
|
|
<div>{identifiedCode}</div>
|
|
<div>{phone}</div>
|
|
<div>{
|
|
roomId
|
|
? roomId
|
|
: 'None'
|
|
}</div>
|
|
|
|
<Menus.Menu>
|
|
<Menus.Toggle id={id.toString()} />
|
|
|
|
<Menus.List id={id.toString()}>
|
|
<Menus.Button
|
|
icon={<RiEditBoxFill />}
|
|
onClick={() => handleEdit(user)}
|
|
>
|
|
Edit
|
|
</Menus.Button>
|
|
<Menus.Button icon={<IoExit />} onClick={() => handleCheckOut(user)}>
|
|
Check out
|
|
</Menus.Button>
|
|
</Menus.List>
|
|
</Menus.Menu>
|
|
</Table.Row>
|
|
);
|
|
};
|
|
|
|
interface IUserTable {
|
|
reload: boolean;
|
|
setReload: Dispatch<SetStateAction<boolean>>;
|
|
openFormDialog: () => void;
|
|
setUser?: Dispatch<SetStateAction<Nullable<IUser>>>;
|
|
}
|
|
|
|
const UserTable = ({
|
|
reload,
|
|
setReload,
|
|
openFormDialog,
|
|
setUser,
|
|
}: IUserTable) => {
|
|
const [users, setUsers] = useState<IUser[]>([]);
|
|
const [phoneSearch, setPhoneSearch] = useState('');
|
|
const [searchParams] = useSearchParams();
|
|
const sortByValue = searchParams.get('sortBy')
|
|
? searchParams.get('sortBy')!
|
|
: '';
|
|
const orderByValue = searchParams.get('orderBy')
|
|
? searchParams.get('orderBy')!
|
|
: '';
|
|
|
|
const { data, isPending, errorFetchMsg } = useFetch(
|
|
'users',
|
|
'phone',
|
|
phoneSearch,
|
|
sortByValue,
|
|
orderByValue,
|
|
reload
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (data) {
|
|
setUsers(data);
|
|
} else {
|
|
setUsers([]);
|
|
}
|
|
|
|
if (errorFetchMsg) {
|
|
console.error(errorFetchMsg);
|
|
}
|
|
}, [data, errorFetchMsg, setUsers]);
|
|
|
|
return (
|
|
<>
|
|
<Direction>
|
|
<StyledOperationTable>
|
|
<OrderBy options={ORDERBY_OPTIONS} />
|
|
|
|
<SortBy options={USER_PAGE.SORTBY_OPTIONS} />
|
|
<Search
|
|
setValueSearch={setPhoneSearch}
|
|
setPlaceHolder="Search by phone..."
|
|
/>
|
|
</StyledOperationTable>
|
|
|
|
{isPending && <Spinner />}
|
|
|
|
{users.length ? (
|
|
<Menus>
|
|
<Table columns="10% 30% 20% 20% 10% 5%">
|
|
<Table.Header>
|
|
<div>Id</div>
|
|
<div>Name</div>
|
|
<div>Identified Code</div>
|
|
<div>Phone</div>
|
|
<div>Room Id</div>
|
|
</Table.Header>
|
|
<Table.Body<IUser>
|
|
data={users}
|
|
render={(user: IUser) => (
|
|
<UserRow
|
|
user={user}
|
|
key={user.id}
|
|
reload={reload}
|
|
setReload={setReload}
|
|
openFormDialog={openFormDialog}
|
|
setUser={setUser!}
|
|
/>
|
|
)}
|
|
/>
|
|
</Table>
|
|
</Menus>
|
|
) : (
|
|
!isPending && <Message>No data to show here!</Message>
|
|
)}
|
|
</Direction>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default UserTable;
|