Update table component, remove unnecessary code

This commit is contained in:
2023-12-13 12:49:10 +07:00
parent d543558a01
commit ad0b2826e2
16 changed files with 350 additions and 400 deletions
+20 -75
View File
@@ -2,7 +2,6 @@ import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
import isPropValid from '@emotion/is-prop-valid'; import isPropValid from '@emotion/is-prop-valid';
import { StyleSheetManager } from 'styled-components'; import { StyleSheetManager } from 'styled-components';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useEffect, useMemo, useReducer } from 'react';
// Components // Components
import AppLayout from './components/AppLayout'; import AppLayout from './components/AppLayout';
@@ -21,87 +20,33 @@ import Account from '@src/pages/Account';
// Constants // Constants
import * as PATH from './constants/path'; import * as PATH from './constants/path';
// Hooks
import {
UserRoomAvailableContext,
initialState,
reducer,
} from '@src/contexts/UserRoomAvailableContext';
// Services
import { getAllUsers } from '@src/services/userServices';
import { getAllRooms } from '@src/services/roomServices';
const queryClient = new QueryClient(); const queryClient = new QueryClient();
function App() { function App() {
const [{ usersAvailable, roomsAvailable }, dispatch] = useReducer(
reducer,
initialState
);
// Init list user and room available
useEffect(() => {
const load = async () => {
const tempUser = await getAllUsers({
sortBy: 'id',
orderBy: 'asc',
phoneSearch: '',
page: 0,
});
if (tempUser) {
dispatch({ type: 'initUser', payload: tempUser.data });
}
const tempRoom = await getAllRooms({
sortBy: 'id',
orderBy: 'asc',
roomSearch: '',
page: 0,
});
if (tempRoom) {
dispatch({ type: 'initRoom', payload: tempRoom.data });
}
};
load();
}, []);
const store = useMemo(() => {
return { roomsAvailable, usersAvailable, dispatch };
}, [roomsAvailable, usersAvailable]);
return ( return (
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<StyleSheetManager shouldForwardProp={shouldForwardProp}> <StyleSheetManager shouldForwardProp={shouldForwardProp}>
<UserRoomAvailableContext.Provider value={store}> <BrowserRouter>
<BrowserRouter> <Routes>
<Routes> <Route element={<RootLayout />}>
<Route element={<RootLayout />}> <Route
<Route element={
element={ <RouteProtected>
<RouteProtected> <AppLayout />
<AppLayout /> </RouteProtected>
</RouteProtected> }
} >
> <Route index element={<Navigate replace to={PATH.BOOKING} />} />
<Route <Route path={PATH.BOOKING} element={<Booking />} />
index <Route path={PATH.USER} element={<User />} />
element={<Navigate replace to={PATH.BOOKING} />} <Route path={PATH.ROOM} element={<Room />} />
/> <Route path={PATH.ACCOUNT} element={<Account />} />
<Route path={PATH.BOOKING} element={<Booking />} />
<Route path={PATH.USER} element={<User />} />
<Route path={PATH.ROOM} element={<Room />} />
<Route path={PATH.ACCOUNT} element={<Account />} />
</Route>
<Route path={PATH.LOGIN} element={<Login />} />
<Route path={PATH.OTHER_PATH} element={<NotFound />} />
</Route> </Route>
</Routes> <Route path={PATH.LOGIN} element={<Login />} />
</BrowserRouter> <Route path={PATH.OTHER_PATH} element={<NotFound />} />
</UserRoomAvailableContext.Provider> </Route>
</Routes>
</BrowserRouter>
</StyleSheetManager> </StyleSheetManager>
<Toast /> <Toast />
@@ -16,7 +16,6 @@ const Spinner = styled.div`
top/10px 10px no-repeat, top/10px 10px no-repeat,
conic-gradient(#0000 30%, var(--primary-color)); conic-gradient(#0000 30%, var(--primary-color));
-webkit-mask: radial-gradient(farthest-side, #0000 calc(100% - 10px), #000 0); -webkit-mask: radial-gradient(farthest-side, #0000 calc(100% - 10px), #000 0);
mask: none;
animation: ${rotate} 1.5s infinite linear; animation: ${rotate} 1.5s infinite linear;
`; `;
@@ -10,17 +10,62 @@ import { Main, StyledAppLayout } from './styled';
// Hooks // Hooks
import { useAccount } from '@src/hooks/authentication/useAccount'; import { useAccount } from '@src/hooks/authentication/useAccount';
// Contexts
import { initialState, reducer, UserRoomAvailableContext } from '@src/contexts/UserRoomAvailableContext.ts';
import { useEffect, useReducer } from 'react';
// Services
import { getAllUsers } from '@src/services/userServices.ts';
import { getAllRooms } from '@src/services/roomServices.ts';
const AppLayout = () => { const AppLayout = () => {
const { account } = useAccount(); const { account } = useAccount();
const [{ usersAvailable, roomsAvailable }, dispatch] = useReducer(
reducer,
initialState
);
// Init list user and room available
// Init list user and room available
useEffect(() => {
const load = async () => {
const tempUser = await getAllUsers({
sortBy: 'id',
orderBy: 'asc',
phoneSearch: '',
page: 0,
});
if (tempUser) {
dispatch({ type: 'initUser', payload: tempUser.data });
}
const tempRoom = await getAllRooms({
sortBy: 'id',
orderBy: 'asc',
roomSearch: '',
page: 0,
});
if (tempRoom) {
dispatch({ type: 'initRoom', payload: tempRoom.data });
}
};
load();
}, []);
return ( return (
<StyledAppLayout> <UserRoomAvailableContext.Provider value={{usersAvailable, roomsAvailable}}>
<Header accountName={account?.user_metadata.fullName} /> <StyledAppLayout>
<Sidebar heading="Hotel Management" /> <Header accountName={account?.user_metadata.fullName} />
<Main> <Sidebar heading="Hotel Management" />
<Outlet /> <Main>
</Main> <Outlet />
</StyledAppLayout> </Main>
</StyledAppLayout>
</UserRoomAvailableContext.Provider>
); );
}; };
@@ -7,7 +7,9 @@ interface IButtonIcon extends ButtonHTMLAttributes<HTMLButtonElement> {
icon: ReactNode; icon: ReactNode;
iconSize?: string; iconSize?: string;
iconColor?: string; iconColor?: string;
fontSize?: string;
text?: string; text?: string;
variations?: string;
} }
const ButtonIcon = ({ const ButtonIcon = ({
@@ -15,12 +17,16 @@ const ButtonIcon = ({
iconSize, iconSize,
iconColor, iconColor,
text, text,
fontSize,
variations,
...props ...props
}: IButtonIcon) => { }: IButtonIcon) => {
return ( return (
<StyledButtonIcon <StyledButtonIcon
iconColor={iconColor} iconColor={iconColor}
iconSize={iconSize} iconSize={iconSize}
fontSize={fontSize}
variations={variations}
{...props} {...props}
> >
{icon} {text && <span>{text}</span>} {icon} {text && <span>{text}</span>}
@@ -1,10 +1,56 @@
import styled, { css } from 'styled-components'; import styled, { css, RuleSet } from 'styled-components';
interface IStyledButtonIcon { interface IStyledButtonIcon {
iconSize?: string; iconSize?: string;
iconColor?: string; iconColor?: string;
fontSize?: string;
variations?: string;
} }
export interface IVariations {
[key: string]: RuleSet<object>;
}
const variations: IVariations = {
success: css`
background-color: var(--success-btn-color);
color: var(--light-text);
&:hover {
background-color: var(--success-btn-hover-color);
}
&:disabled {
background-color: var(--success-btn-hover-color);
}
`,
primary: css`
background-color: var(--primary-color);
color: var(--light-text);
&:hover {
background-color: var(--primary-hover-color);
}
`,
danger: css`
background-color: var(--danger-btn-color);
color: var(--light-text);
&:hover {
background-color: var(--danger-btn-hover-color);
}
&:disabled {
background-color: var(--danger-btn-hover-color);
}
`,
default: css`
&:hover {
background-color: var(--hover-background-color);
}
`,
};
const StyledButtonIcon = styled.button<IStyledButtonIcon>` const StyledButtonIcon = styled.button<IStyledButtonIcon>`
background: none; background: none;
@@ -12,18 +58,24 @@ const StyledButtonIcon = styled.button<IStyledButtonIcon>`
align-items: center; align-items: center;
gap: 8px; gap: 8px;
font-size: var(--fs-sm-2x); ${(props) =>
props.fontSize &&
css`
font-size: ${props.fontSize};
`}
padding: 10px; padding: 10px 20px;
transition: all 0.2s; transition: all 0.2s;
width: 100%;
border: none; border: none;
border-radius: var(--radius-md);
&:hover {
background-color: var(--hover-background-color); &:disabled {
cursor: not-allowed;
} }
${(props) => variations[props.variations!]}
& svg { & svg {
${(props) => ${(props) =>
props.iconSize && props.iconSize &&
@@ -45,6 +97,8 @@ const StyledButtonIcon = styled.button<IStyledButtonIcon>`
StyledButtonIcon.defaultProps = { StyledButtonIcon.defaultProps = {
iconSize: '16px', iconSize: '16px',
iconColor: '#000', iconColor: '#000',
fontSize: 'var(--fs-sm-2x)',
variations: 'default',
}; };
export { StyledButtonIcon }; export { StyledButtonIcon };
+66 -32
View File
@@ -1,13 +1,22 @@
// Types
import { ColumnProps } from '@src/types/common'; import { ColumnProps } from '@src/types/common';
// Styled
import { import {
StyledBody, StyledBody, StyledFooter, StyledHeader, StyledRow, StyledTable
StyledFooter,
StyledHeader,
StyledRow,
StyledTable,
} from './styled'; } from './styled';
// Components
import Pagination from '../Pagination'; import Pagination from '../Pagination';
import { TbArrowNarrowRight } from 'react-icons/tb'; import { TbArrowNarrowRight } from 'react-icons/tb';
import { StyledTableOption } from '@src/pages/Room/styled.ts';
import OrderBy from '@src/components/OrderBy';
import { ORDERBY_OPTIONS, ROOM_PAGE } from '@src/constants/commons.ts';
import SortBy from '@src/components/SortBy';
import Search from '@src/components/Search';
import Message from '@src/components/Message';
import Direction from '@src/commons/styles/Direction.ts';
import { Dispatch, SetStateAction } from 'react';
const parseWidthString = (columnsWidth: number[]): string => { const parseWidthString = (columnsWidth: number[]): string => {
let result: string = ''; let result: string = '';
@@ -23,61 +32,86 @@ const parseWidthString = (columnsWidth: number[]): string => {
type Props<T> = { type Props<T> = {
columns: ColumnProps[]; columns: ColumnProps[];
rows: T[]; rows: T[];
stateSelected: {
itemSelected: T | undefined;
setItemSelected: Dispatch<SetStateAction<T | undefined>>
};
count?: number | null; count?: number | null;
onRowClick?: (rowData: T) => void;
enabledOrder?: boolean;
enabledSort?: boolean;
enabledSearch?: boolean;
}; };
const Table = <T,>({ rows, columns, count }: Props<T>) => { const Table = <T, >({
rows,
columns,
count,
onRowClick,
stateSelected,
enabledSort = false,
enabledSearch = false,
enabledOrder = false
}: Props<T>) => {
const width = parseWidthString(columns.map((item) => item.width)); const width = parseWidthString(columns.map((item) => item.width));
const { itemSelected, setItemSelected } = stateSelected;
const headers = columns.map((column, index) => { const headers = columns.map((column, index) => {
return <div key={`headCell-${index}`}>{column.title}</div>; return <div key={`headCell-${index}`}>{column.title}</div>;
}); });
const renderRows = rows.map((row, rowIndex) => { const renderRows = rows.map((row, rowIndex) => {
const handleRowClick = () => {
if (onRowClick) {
onRowClick(row);
setItemSelected(row);
}
};
return ( return (
<StyledRow <StyledRow
key={`row-${rowIndex}`} key={`row-${rowIndex}`}
width={width} width={width}
onClick={ onDoubleClick={handleRowClick}
row[ className={JSON.stringify(itemSelected) === JSON.stringify(row)
'onClick' as keyof typeof row ? 'selected'
] as React.MouseEventHandler<HTMLDivElement> : ''
} }>
>
{columns.map((column, columnIndex) => { {columns.map((column, columnIndex) => {
const value = row[column.key as keyof typeof row] as string; const value = row[column.key as keyof typeof row] as string;
if (column.isDateValue) { if (column.isDateValue) {
return ( return (<div
<div style={{ display: 'flex', alignItems: 'center' }}
style={{ display: 'flex', alignItems: 'center' }} key={`cell-${columnIndex}`}
key={`cell-${columnIndex}`} >
> {value[0]} &nbsp; <TbArrowNarrowRight />
{value[0]} &nbsp; <TbArrowNarrowRight /> &nbsp; {value[1]}
&nbsp; {value[1]} </div>);
</div>
);
} }
return <div key={`cell-${columnIndex}`}>{value}</div>; return <div key={`cell-${columnIndex}`}>{value}</div>;
})} })}
</StyledRow> </StyledRow>);
);
}); });
return ( return (<Direction>
<StyledTable> <StyledTableOption>
{enabledOrder && <OrderBy options={ORDERBY_OPTIONS} />}
{enabledSort && <SortBy options={ROOM_PAGE.SORTBY_OPTIONS} />}
{enabledSearch && <Search setPlaceHolder="Search by name..." />}
</StyledTableOption>
{rows && rows.length ? (<StyledTable>
<StyledHeader width={width}>{headers}</StyledHeader> <StyledHeader width={width}>{headers}</StyledHeader>
<StyledBody>{renderRows}</StyledBody> <StyledBody>{renderRows}</StyledBody>
{Boolean(count) && ( {Boolean(count) && (<StyledFooter>
<StyledFooter> <Pagination count={count!} />
<Pagination count={count!} /> </StyledFooter>)}
</StyledFooter> </StyledTable>) : (<Message>No data to show here!</Message>)}
)} </Direction>);
</StyledTable>
);
}; };
export default Table; export default Table;
@@ -26,8 +26,8 @@ const StyledBody = styled.div`
const StyledRow = styled(CommonRow)` const StyledRow = styled(CommonRow)`
padding: 20px; padding: 20px;
&.active { &.selected {
background-color: red; background-color: var(--item-selected);
} }
&:not(:last-child) { &:not(:last-child) {
-113
View File
@@ -1,113 +0,0 @@
import { useCallback, useMemo } from 'react';
// Helpers
import { formatCurrency } from '@src/helpers/helper';
// Types
import { IRoom } from '@src/types/room';
// Components
import RoomForm from './RoomForm';
import Modal from '@src/components/Modal';
import Table from '@src/components/Table';
import Menus from '@src/components/Menus';
import { RiEditBoxFill } from 'react-icons/ri';
import { HiTrash } from 'react-icons/hi';
import ConfirmMessage from '@src/components/ConfirmMessage';
// Hooks
import { useSetIsDeleteRoom } from '@src/hooks/rooms/useSetIsDeleteRoom';
// Constants
import { FORM } from '@src/constants/commons';
interface IRoomRow {
room: IRoom;
}
const RoomRow = ({ room }: IRoomRow) => {
const { id, name, price, status } = room;
const { setIsDeleteRoom } = useSetIsDeleteRoom();
const formattedPrice = useMemo(() => formatCurrency(price), [price]);
const renderEditBtn = useCallback(
(onOpenModal: () => void) => (
<Menus.Button
onClick={onOpenModal}
icon={<RiEditBoxFill />}
label={'Edit'}
/>
),
[]
);
const renderDeleteBtn = useCallback(
(onOpenModal: () => void) => (
<Menus.Button
icon={<HiTrash />}
onClick={onOpenModal}
disabled={status}
label={'Delete'}
/>
),
[status]
);
const renderRow = useCallback(
(onCloseModal: () => void) => (
<RoomForm room={room} onCloseModal={onCloseModal} />
),
[room]
);
const renderConfirmMessage = useCallback(
(onCloseModal: () => void) => (
<ConfirmMessage
message={`Are you sure to delete ${name}?`}
onConfirm={() => setIsDeleteRoom(id)}
onCloseModal={onCloseModal}
/>
),
[id, name, setIsDeleteRoom]
);
return (
<Table.Row>
<div>{id}</div>
<div>{name}</div>
<div>{formattedPrice}</div>
<div>{status ? 'Unavailable' : 'Available'}</div>
<div>
<Modal>
<Menus.Menu>
<Menus.Toggle id={id.toString()} />
<Menus.List id={id.toString()}>
<Modal.Open
modalName={FORM.EDIT}
renderChildren={renderEditBtn}
/>
<Modal.Open
modalName={FORM.DELETE}
renderChildren={renderDeleteBtn}
/>
</Menus.List>
<Modal.Window
name={FORM.EDIT}
title="Edit Room"
renderChildren={renderRow}
/>
<Modal.Window
name={FORM.DELETE}
title="Delete Room"
renderChildren={renderConfirmMessage}
/>
</Menus.Menu>
</Modal>
</div>
</Table.Row>
);
};
export default RoomRow;
@@ -1,83 +0,0 @@
// Components
import Table from '@src/components/Table';
import Message from '@src/components/Message';
import Search from '@src/components/Search';
import SortBy from '@src/components/SortBy';
import OrderBy from '@src/components/OrderBy';
// Types
import { IRoom } from '@src/types/room';
import { ColumnProps } from '@src/types/common';
// Constants
import { ORDERBY_OPTIONS, ROOM_PAGE } from '@src/constants/commons';
// Styled
import { StyledOperationTable } from './styled';
import Direction from '@src/commons/styles/Direction';
import Spinner from '@src/commons/styles/Spinner';
// Hooks
import { useRooms } from '@src/hooks/rooms/useRooms';
interface IRoomTable extends Omit<IRoom, 'status'>{
status: string;
onClick: () => void;
}
const RoomTable = () => {
const columns: ColumnProps[] = [
{
key: 'id',
title: 'Id',
width: 10,
},
{
key: 'name',
title: 'Name',
width: 40,
},
{
key: 'price',
title: 'Price',
width: 20,
},
{
key: 'status',
title: 'Status',
width: 20,
},
];
const { isLoading, rooms, count } = useRooms();
const tempRooms = rooms?.map((room) => ({
...room,
status: room.status
? 'Unavailable'
: 'Available',
onClick: () => console.log(room),
}));
return (
<>
<Direction>
<StyledOperationTable>
<OrderBy options={ORDERBY_OPTIONS} />
<SortBy options={ROOM_PAGE.SORTBY_OPTIONS} />
<Search setPlaceHolder="Search by name..." />
</StyledOperationTable>
{isLoading && <Spinner />}
{tempRooms && tempRooms.length ? (
<Table<IRoomTable> columns={columns} rows={tempRooms} count={count}/>
) : (
!isLoading && <Message>No data to show here!</Message>
)}
</Direction>
</>
);
};
export default RoomTable;
@@ -1,29 +0,0 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { render } from '@testing-library/react';
// Types
import { IRoom } from '@src/types/room';
// Components
import RoomRow from '../RoomRow';
describe('RoomRow', () => {
const tempRoom: IRoom = {
id: 1,
name: 'Temp Room',
price: 2399,
status: false,
isDelete: true,
};
const queryClient = new QueryClient();
const wrapper = render(
<QueryClientProvider client={queryClient}>
<RoomRow room={tempRoom} />
</QueryClientProvider>
);
test('Should render correctly', () => {
expect(wrapper).toMatchSnapshot();
});
});
@@ -1,22 +0,0 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BrowserRouter } from 'react-router-dom';
import { render } from '@testing-library/react';
// Components
import RoomTable from '@src/pages/Room/RoomTable';
describe('UserTable', () => {
const queryClient = new QueryClient();
const wrapper = render(
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<RoomTable />
</BrowserRouter>
</QueryClientProvider>
);
test('Should render correctly', () => {
expect(wrapper).toMatchSnapshot();
});
});
+119 -18
View File
@@ -1,37 +1,138 @@
// Components // Components
import RoomTable from './RoomTable';
import RoomForm from './RoomForm'; import RoomForm from './RoomForm';
import Modal from '@src/components/Modal'; import Modal from '@src/components/Modal';
import ButtonIcon from '@src/components/ButtonIcon';
import Direction from '@src/commons/styles/Direction';
import { FiEdit } from 'react-icons/fi';
import { FaRegTrashAlt } from 'react-icons/fa';
import { MdOutlineAddCircleOutline } from 'react-icons/md';
import Table from '@src/components/Table';
// Styled // Styled
import { StyledRoom, Title } from './styled'; import { ActionTable, StyledRoom, Title } from './styled';
import Direction from '@src/commons/styles/Direction'; import Spinner from '@src/commons/styles/Spinner.ts';
import Button from '@src/commons/styles/Button';
// Types
import { ColumnProps } from '@src/types/common.ts';
import { IRoom } from '@src/types/room.ts';
// Hooks
import { useRooms } from '@src/hooks/rooms/useRooms.ts';
import { useEffect, useState } from 'react';
interface IRoomTable extends Omit<IRoom, 'status'> {
status: string;
}
const Room = () => { const Room = () => {
const [itemSelected, setItemSelected] = useState<IRoomTable>();
const columns: ColumnProps[] = [
{
key: 'id',
title: 'Id',
width: 10
},
{
key: 'name',
title: 'Name',
width: 40
},
{
key: 'price',
title: 'Price',
width: 20
},
{
key: 'status',
title: 'Status',
width: 20
}
];
const { isLoading, rooms, count } = useRooms();
// Reset value when rooms changed.
useEffect(() => {
setItemSelected(undefined);
}, [rooms]);
const tempRooms = rooms?.map((room) => ({
...room,
status: room.status
? 'Unavailable'
: 'Available'
}));
return ( return (
<StyledRoom> <StyledRoom>
<Direction type="horizontal"> <Direction type="horizontal">
<Title>List Room</Title> <Title>List Room</Title>
<Modal> <Modal>
<Modal.Open <ActionTable>
modalName="room-form" <Modal.Open
renderChildren={(onCloseModal) => ( modalName="room-form"
<Button onClick={onCloseModal}>Add room</Button> renderChildren={(onCloseModal) => (
)} <ButtonIcon
/> icon={<MdOutlineAddCircleOutline />}
<Modal.Window text={'Add Room'}
name="room-form" iconSize={'18px'}
title="Add form" fontSize={'var(--fs-sm)'}
renderChildren={(onCloseModal) => ( variations={'primary'}
<RoomForm onCloseModal={onCloseModal} /> iconColor={'white'}
)} onClick={onCloseModal}
/> />
)}
/>
<Modal.Window
name="room-form"
title="Add form"
renderChildren={(onCloseModal) => (
<RoomForm onCloseModal={onCloseModal} />
)}
/>
<ButtonIcon
icon={<FiEdit />}
text={'Edit'}
iconSize={'18px'}
fontSize={'var(--fs-sm)'}
variations={'success'}
iconColor={'white'}
disabled={Boolean(!itemSelected)}
/>
<ButtonIcon
icon={<FaRegTrashAlt />}
text={'Delete'}
iconSize={'18px'}
fontSize={'var(--fs-sm)'}
variations={'danger'}
iconColor={'white'}
disabled={Boolean(!itemSelected)}
/>
</ActionTable>
</Modal> </Modal>
</Direction> </Direction>
<RoomTable /> {isLoading && <Spinner />}
{
tempRooms &&
Boolean(tempRooms.length) &&
<Table<IRoomTable>
columns={columns}
rows={tempRooms}
count={count}
enabledSort={true}
enabledOrder={true}
enabledSearch={true}
stateSelected={{
itemSelected,
setItemSelected,
}}
onRowClick={(data) => {
setItemSelected(data);
}} />}
</StyledRoom> </StyledRoom>
); );
}; };
+8 -2
View File
@@ -14,14 +14,20 @@ const Title = styled.h2`
text-transform: capitalize; text-transform: capitalize;
`; `;
const StyledOperationTable = styled.div` const StyledTableOption = styled.div`
display: flex; display: flex;
gap: 30px; gap: 30px;
justify-content: flex-end; justify-content: flex-end;
`; `;
const ActionTable = styled.div`
display: flex;
gap: 30px;
`
export { export {
StyledRoom, StyledRoom,
Title, Title,
StyledOperationTable StyledTableOption,
ActionTable
}; };
@@ -1,9 +1,9 @@
import { render } from '@testing-library/react'; import { render } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import UserTable from '@src/pages/User/UserTable.tsx';
// Components // Components
import RoomTable from '@src/pages/Room/RoomTable';
describe('UserTable', () => { describe('UserTable', () => {
const queryClient = new QueryClient(); const queryClient = new QueryClient();
@@ -11,7 +11,7 @@ describe('UserTable', () => {
const wrapper = render( const wrapper = render(
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<BrowserRouter> <BrowserRouter>
<RoomTable /> <UserTable />
</BrowserRouter> </BrowserRouter>
</QueryClientProvider> </QueryClientProvider>
); );
@@ -11,7 +11,7 @@ import {
ERROR_DELETE_ROOM, ERROR_DELETE_ROOM,
ERROR_FETCHING_ROOM, ERROR_FETCHING_ROOM,
ERROR_UPDATE_ROOM, ERROR_UPDATE_ROOM,
ROOMS_TABLE, ROOMS_TABLE
} from '@src/constants/messages'; } from '@src/constants/messages';
interface IGetAllRooms { interface IGetAllRooms {
@@ -26,11 +26,11 @@ interface IGetAllRooms {
* @returns Return all rooms in database * @returns Return all rooms in database
*/ */
const getAllRooms = async ({ const getAllRooms = async ({
sortBy, sortBy,
orderBy, orderBy,
roomSearch, roomSearch,
page, page
}: IGetAllRooms): Promise<{ data: IRoom[]; count: number | null }> => { }: IGetAllRooms): Promise<{ data: IRoom[]; count: number | null }> => {
const from = (page - 1) * DEFAULT_PAGE_SIZE; const from = (page - 1) * DEFAULT_PAGE_SIZE;
const to = from + DEFAULT_PAGE_SIZE - 1; const to = from + DEFAULT_PAGE_SIZE - 1;
@@ -157,5 +157,5 @@ export {
createRoom, createRoom,
setIsDeleteRoom, setIsDeleteRoom,
getRoomById, getRoomById,
updateRoomStatus, updateRoomStatus
}; };
@@ -1,13 +1,20 @@
:root { :root {
--primary-color: #0010ba; --primary-color: #0010ba;
--primary-hover-color: #0010ba8c;
--header-table-color: #ebebeb; --header-table-color: #ebebeb;
--item-selected: #f5f5f5;
--border-color: #8c8c8c; --border-color: #8c8c8c;
--footer-table-color: #ebebeb; --footer-table-color: #ebebeb;
--secondary-btn-color: #d1d1d1; --secondary-btn-color: #d1d1d1;
--disabled-btn-color: #7f82a6; --disabled-btn-color: #7f82a6;
--danger-btn-color: #ff4f4f; --danger-btn-color: #ff4f4f;
--danger-btn-hover-color: #ff4f4f8c;
--success-btn-color: #228b22;
--success-btn-hover-color: #228b2299;
--hover-background-color: #f3f4f6; --hover-background-color: #f3f4f6;
--hover-dark-background-color: #d0d0d0; --hover-dark-background-color: #d0d0d0;