Refactor code, fix UI and logic code

This commit is contained in:
2023-11-02 11:51:26 +07:00
parent 4e7e731fbd
commit 895e96216d
37 changed files with 330 additions and 202 deletions
@@ -1,33 +0,0 @@
import styled from 'styled-components';
import { Outlet } from 'react-router-dom';
// Components
import Header from './Header';
import Sidebar from './Sidebar';
const StyledAppLayout = styled.div`
display: grid;
grid-template-columns: 300px 1fr;
grid-template-rows: auto 1fr;
height: 100vh;
`;
const Main = styled.main`
border: 1px solid var(--border-color);
overflow: scroll;
`;
const AppLayout = () => {
return (
<StyledAppLayout>
<Header />
<Sidebar />
<Main>
<Outlet />
</Main>
</StyledAppLayout>
);
};
export default AppLayout;
@@ -0,0 +1,22 @@
import { Outlet } from 'react-router-dom';
// Components
import Header from '../Header';
import Sidebar from '../Sidebar';
// Styled
import { Main, StyledAppLayout } from './styled';
const AppLayout = () => {
return (
<StyledAppLayout>
<Header />
<Sidebar />
<Main>
<Outlet />
</Main>
</StyledAppLayout>
);
};
export default AppLayout;
@@ -0,0 +1,16 @@
import styled from 'styled-components';
const StyledAppLayout = styled.div`
display: grid;
grid-template-columns: 300px 1fr;
grid-template-rows: auto 1fr;
height: 100vh;
`;
const Main = styled.main`
border: 1px solid var(--border-color);
overflow: scroll;
`;
export { StyledAppLayout, Main };
@@ -1,3 +1,4 @@
// Styled
import { StyledActionBtn, StyledForm } from './styled'; import { StyledActionBtn, StyledForm } from './styled';
interface IFormProps { interface IFormProps {
@@ -1,3 +1,4 @@
// Styled
import { Error, Label, StyledFormRow } from './styled'; import { Error, Label, StyledFormRow } from './styled';
interface IFormRow { interface IFormRow {
@@ -16,6 +16,8 @@ const Error = styled.p`
color: var(--error-text); color: var(--error-text);
font-size: var(--fs-sm-2x); font-size: var(--fs-sm-2x);
margin-top: 5px; margin-top: 5px;
padding-inline: 5px;
width: 220px;
`; `;
export { StyledFormRow, Label, Error }; export { StyledFormRow, Label, Error };
@@ -0,0 +1,16 @@
// Components
import HeaderMenu from '../HeaderMenu';
// Styled
import { StyledHeader } from './styled';
const Header = () => {
return (
<StyledHeader>
<p>Hi, Admin!</p>
<HeaderMenu />
</StyledHeader>
);
};
export default Header;
@@ -1,8 +1,5 @@
import styled from 'styled-components'; import styled from 'styled-components';
// Components
import HeaderMenu from './HeaderMenu';
const StyledHeader = styled.header` const StyledHeader = styled.header`
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
padding: 20px 40px; padding: 20px 40px;
@@ -13,13 +10,4 @@ const StyledHeader = styled.header`
gap: 30px; gap: 30px;
`; `;
const Header = () => { export { StyledHeader };
return (
<StyledHeader>
<p>Hi, Admin!</p>
<HeaderMenu />
</StyledHeader>
);
};
export default Header;
@@ -1,14 +1,10 @@
import styled from 'styled-components';
// Components // Components
import { IoPersonCircleOutline } from 'react-icons/io5'; import { IoPersonCircleOutline } from 'react-icons/io5';
import { HiOutlineLogout } from 'react-icons/hi'; import { HiOutlineLogout } from 'react-icons/hi';
import ButtonIcon from '../commons/styles/ButtonIcon'; import ButtonIcon from '../../commons/styles/ButtonIcon';
const StyledHeaderMenu = styled.ul` // Styled
display: flex; import { StyledHeaderMenu } from './styled';
gap: 10px;
`;
const HeaderMenu = () => { const HeaderMenu = () => {
return ( return (
@@ -0,0 +1,8 @@
import styled from 'styled-components';
const StyledHeaderMenu = styled.ul`
display: flex;
gap: 10px;
`;
export { StyledHeaderMenu };
@@ -0,0 +1,8 @@
// Styled
import { StyledMessage } from './styled';
const Message = ({ children }: { children: string }) => {
return <StyledMessage>{children}</StyledMessage>;
};
export default Message;
@@ -6,8 +6,4 @@ const StyledMessage = styled.p`
padding: 20px; padding: 20px;
`; `;
const Message = ({ children }: { children: string }) => { export { StyledMessage };
return <StyledMessage>{children}</StyledMessage>;
};
export default Message;
@@ -0,0 +1,28 @@
// Components
import { MdSpaceDashboard } from 'react-icons/md';
import { HiUsers } from 'react-icons/hi2';
import { BsHouseDoorFill } from 'react-icons/bs';
// Styled
import { StyledNav, StyledNavLink } from './styled';
const Nav = () => {
return (
<StyledNav>
<StyledNavLink to={'/dashboard'}>
<MdSpaceDashboard />
<span>Dashboard</span>
</StyledNavLink>
<StyledNavLink to={'/user'}>
<HiUsers />
<span>User</span>
</StyledNavLink>
<StyledNavLink to={'/room'}>
<BsHouseDoorFill />
<span>Room</span>
</StyledNavLink>
</StyledNav>
);
};
export default Nav;
@@ -1,11 +1,6 @@
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import styled from 'styled-components'; import styled from 'styled-components';
// Components
import { MdSpaceDashboard } from 'react-icons/md';
import { HiUsers } from 'react-icons/hi2';
import { BsHouseDoorFill } from 'react-icons/bs';
const StyledNav = styled.nav` const StyledNav = styled.nav`
margin-top: 70px; margin-top: 70px;
display: flex; display: flex;
@@ -38,23 +33,4 @@ const StyledNavLink = styled(NavLink)`
} }
`; `;
const Nav = () => { export { StyledNav, StyledNavLink };
return (
<StyledNav>
<StyledNavLink to={'/dashboard'}>
<MdSpaceDashboard />
<span>Dashboard</span>
</StyledNavLink>
<StyledNavLink to={'/user'}>
<HiUsers />
<span>User</span>
</StyledNavLink>
<StyledNavLink to={'/room'}>
<BsHouseDoorFill />
<span>Room</span>
</StyledNavLink>
</StyledNav>
);
};
export default Nav;
@@ -1,39 +1,8 @@
import { memo } from 'react'; import { memo } from 'react';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
import styled, { css } from 'styled-components';
const StyledOrder = styled.div` // Styled
border: 1px solid var(--border-color); import { OrderButton, StyledOrder } from './styled';
border-radius: var(--radius-sm);
padding: 5px;
display: flex;
gap: 10px;
`;
interface IOrderBtn {
active: boolean;
}
const OrderButton = styled.button<IOrderBtn>`
border: none;
${(props) =>
props.active &&
css`
background-color: var(--primary-color);
color: var(--light-text);
`}
border-radius: var(--radius-sm);
font-weight: 500;
font-size: var(--fs-sm-x);
padding: 5px 10px;
transition: all 0.3s;
&:hover:not(:disabled) {
background-color: var(--hover-dark-background-color);
}
`;
interface IOrderProps { interface IOrderProps {
options: { options: {
@@ -0,0 +1,38 @@
import styled, { css } from 'styled-components';
const StyledOrder = styled.div`
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
padding: 5px;
display: flex;
gap: 10px;
`;
interface IOrderBtn {
active: boolean;
}
const OrderButton = styled.button<IOrderBtn>`
border: none;
cursor: pointer;
${(props) =>
props.active &&
css`
background-color: var(--primary-color);
color: var(--light-text);
cursor: no-drop;
`}
border-radius: var(--radius-sm);
font-weight: 500;
font-size: var(--fs-sm-x);
padding: 5px 10px;
transition: all 0.3s;
&:hover:not(:disabled) {
background-color: var(--hover-dark-background-color);
}
`;
export { StyledOrder, OrderButton };
@@ -1,12 +1,5 @@
import { memo, useEffect, useState } from 'react'; import { memo, useEffect, useState } from 'react';
import styled from 'styled-components'; import { StyledSearch } from './styled';
const StyledSearch = styled.input`
border-radius: var(--radius-sm);
border: 1px solid var(--border-color);
font-size: var(--fs-sm-x);
padding: 5px 10px;
`;
interface ISearch { interface ISearch {
setPlaceHolder: string; setPlaceHolder: string;
@@ -0,0 +1,10 @@
import styled from 'styled-components';
const StyledSearch = styled.input`
border-radius: var(--radius-sm);
border: 1px solid var(--border-color);
font-size: var(--fs-sm-x);
padding: 5px 10px;
`;
export { StyledSearch };
@@ -1,32 +0,0 @@
import styled from 'styled-components';
interface ISelect {
options: {
value: string;
label: string;
}[];
value: string;
onChange: React.ChangeEventHandler<HTMLSelectElement>;
}
const StyledSelect = styled.select`
font-size: var(--fs-sm-x);
padding: 5px 10px;
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
font-weight: 500;
`;
const Select = ({ options, value, onChange }: ISelect) => {
return (
<StyledSelect value={value} onChange={onChange} aria-label="Sort">
{options.map((option) => (
<option value={option.value} key={option.value}>
{option.label}
</option>
))}
</StyledSelect>
);
};
export default Select;
@@ -0,0 +1,30 @@
import { ISelectOptions } from '../../globals/interfaces';
import { StyledSelect } from './styled';
interface ISelect {
options: ISelectOptions[];
value: string;
onChange: React.ChangeEventHandler<HTMLSelectElement>;
name?: string;
}
const Select = ({ options, value, onChange, name }: ISelect) => {
if (!options) return;
return (
<StyledSelect
value={value}
onChange={onChange}
aria-label="Sort"
name={name}
>
{options.map((option) => (
<option value={option.value} key={option.value}>
{option.label}
</option>
))}
</StyledSelect>
);
};
export default Select;
@@ -0,0 +1,11 @@
import styled from 'styled-components';
const StyledSelect = styled.select`
font-size: var(--fs-sm-x);
padding: 5px 10px;
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
font-weight: 500;
`;
export { StyledSelect };
@@ -0,0 +1,16 @@
// Components
import Nav from '../Nav';
// Styled
import { Heading, StyledSidebar } from './styled';
const Sidebar = () => {
return (
<StyledSidebar>
<Heading>Hotel Management</Heading>
<Nav />
</StyledSidebar>
);
};
export default Sidebar;
@@ -1,8 +1,5 @@
import styled from 'styled-components'; import styled from 'styled-components';
// Components
import Nav from './Nav';
const StyledSidebar = styled.aside` const StyledSidebar = styled.aside`
padding: 50px 20px; padding: 50px 20px;
@@ -17,13 +14,4 @@ const Heading = styled.h1`
color: var(--primary-color); color: var(--primary-color);
`; `;
const Sidebar = () => { export { StyledSidebar, Heading };
return (
<StyledSidebar>
<Heading>Hotel Management</Heading>
<Nav />
</StyledSidebar>
);
};
export default Sidebar;
@@ -1,7 +1,7 @@
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
// Components // Components
import Select from './Select'; import Select from '../Select';
import { memo } from 'react'; import { memo } from 'react';
interface ISortByProps { interface ISortByProps {
@@ -11,6 +11,8 @@ const EDIT_SUCCESS = 'Edit success';
const CONFIRM_DELETE = 'Are you sure to delete it?'; const CONFIRM_DELETE = 'Are you sure to delete it?';
const DELETE_SUCCESS = 'Delete success'; const DELETE_SUCCESS = 'Delete success';
const REQUIRED_FIELD_ERROR = 'This is required field'; const REQUIRED_FIELD_ERROR = 'This is required field';
const DISCOUNT_FIELD_ERROR =
'Discount should be greater than 0 and less than 100';
export { export {
invalidFormatMsg, invalidFormatMsg,
@@ -20,4 +22,5 @@ export {
CONFIRM_DELETE, CONFIRM_DELETE,
DELETE_SUCCESS, DELETE_SUCCESS,
REQUIRED_FIELD_ERROR, REQUIRED_FIELD_ERROR,
DISCOUNT_FIELD_ERROR,
}; };
+1 -1
View File
@@ -2,6 +2,6 @@ export const DASHBOARD: string = '/dashboard';
export const USER: string = '/user'; export const USER: string = '/user';
export const ROOM: string = '/room'; export const ROOM: string = '/room';
export const OTHER_PATH: string = '*'; export const OTHER_PATH: string = '*';
export const BASE_URL: string = 'https://hotel-management-api.loiphan.com/'; export const BASE_URL: string = 'http://localhost:3000/';
export const USER_PATH = 'users'; export const USER_PATH = 'users';
export const ROOM_PATH = 'rooms'; export const ROOM_PATH = 'rooms';
+13 -1
View File
@@ -20,6 +20,11 @@ interface ITableBody<T> {
render?: (value: T) => JSX.Element; render?: (value: T) => JSX.Element;
} }
interface ISelectOptions {
value: string;
label: string;
}
interface IDialogProps<T> { interface IDialogProps<T> {
title?: string; title?: string;
children?: JSX.Element[] | JSX.Element; children?: JSX.Element[] | JSX.Element;
@@ -31,4 +36,11 @@ interface IDialogProps<T> {
isAdd?: boolean; isAdd?: boolean;
} }
export type { IMenusContext, IButton, ITable, ITableBody, IDialogProps }; export type {
IMenusContext,
IButton,
ITable,
ITableBody,
IDialogProps,
ISelectOptions,
};
+12 -3
View File
@@ -56,7 +56,8 @@ const getPropValues = (stateSchema: TStateSchema, prop?: TPropValues) => {
type TValidator = { type TValidator = {
validatorFunc: (value: string) => boolean; validatorFunc: (value: string) => boolean;
prop: string; prop?: string;
customErrorMsg?: string;
required?: boolean; required?: boolean;
}; };
@@ -65,12 +66,20 @@ type TValidator = {
* @param param0 Pass TValidator object * @param param0 Pass TValidator object
* @returns An object contains condition validator * @returns An object contains condition validator
*/ */
const addValidator = ({ validatorFunc, prop, required = true }: TValidator) => { const addValidator = ({
validatorFunc,
prop = '',
customErrorMsg = '',
required = true,
}: TValidator) => {
return { return {
required, required,
validator: { validator: {
func: validatorFunc, func: validatorFunc,
error: invalidFormatMsg(prop), // prettier-ignore
error: customErrorMsg
? customErrorMsg
: invalidFormatMsg(prop),
}, },
}; };
}; };
+17 -1
View File
@@ -7,6 +7,16 @@ const isValidNumber = (value: string): boolean => {
return /^[0-9]*$/.test(value); return /^[0-9]*$/.test(value);
}; };
/**
* Check value is valid discount or not
* @param value Value need to be checked
* @returns A boolean indicating whether or not the argument has valid
*/
const isValidDiscount = (value: string): boolean => {
console.log(Boolean(+value >= 0 && +value <= 100));
return +value >= 0 && +value <= 100;
};
/** /**
* Check value is valid phone number or not * Check value is valid phone number or not
* @param value Value need to be checked * @param value Value need to be checked
@@ -31,4 +41,10 @@ const isValidString = (value: string): boolean => {
*/ */
const skipCheck = () => true; const skipCheck = () => true;
export { isValidNumber, isValidPhoneNumber, isValidString, skipCheck }; export {
isValidNumber,
isValidPhoneNumber,
isValidString,
skipCheck,
isValidDiscount,
};
+8 -8
View File
@@ -19,15 +19,15 @@ import { searchQuery } from '../helpers/utils';
*/ */
const useFetch = ( const useFetch = (
path: string, path: string,
columnSearch: string, columnSearch: string = '',
keyWord: string, keyWord: string = '',
tempSortBy: string, tempSortBy?: string,
tempOrderBy: string, tempOrderBy?: string,
reload?: boolean, reload?: boolean,
) => { ) => {
const [data, setData] = useState(null); const [data, setData] = useState(null);
const [isPending, setIsPending] = useState(false); const [isPending, setIsPending] = useState(false);
const [errorMsg, setErrorMsg] = useState<string | null>(null); const [errorFetchMsg, setErrorFetchMsg] = useState<string | null>(null);
useEffect(() => { useEffect(() => {
// Clear data // Clear data
@@ -61,16 +61,16 @@ const useFetch = (
setIsPending(false); setIsPending(false);
setData(json); setData(json);
setErrorMsg(null); setErrorFetchMsg(null);
} catch (error) { } catch (error) {
setErrorMsg(`Could not fetch data.\n ${error}`); setErrorFetchMsg(`Could not fetch data.\n ${error}`);
setIsPending(false); setIsPending(false);
} }
}; };
fetchData(); fetchData();
}, [path, reload, columnSearch, keyWord, tempOrderBy, tempSortBy]); }, [path, reload, columnSearch, keyWord, tempOrderBy, tempSortBy]);
return { data, isPending, errorMsg }; return { data, isPending, errorFetchMsg };
}; };
export { useFetch }; export { useFetch };
+5 -1
View File
@@ -110,7 +110,11 @@ const useForm = (
// Event handler for handling changes in input. // Event handler for handling changes in input.
const handleOnChange = useCallback( const handleOnChange = useCallback(
(event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => { (
event: ChangeEvent<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
>,
) => {
setIsDirty(true); setIsDirty(true);
let error = ''; let error = '';
+8 -5
View File
@@ -24,6 +24,7 @@ import useForm from '../../hooks/useForm.ts';
// Utils // Utils
import { import {
isValidDiscount,
isValidNumber, isValidNumber,
isValidString, isValidString,
skipCheck, skipCheck,
@@ -35,6 +36,7 @@ import { sendRequest } from '../../helpers/sendRequest.ts';
import { STATUS_CODE } from '../../constants/statusCode.ts'; import { STATUS_CODE } from '../../constants/statusCode.ts';
import { import {
ADD_SUCCESS, ADD_SUCCESS,
DISCOUNT_FIELD_ERROR,
EDIT_SUCCESS, EDIT_SUCCESS,
errorMsg, errorMsg,
} from '../../constants/messages.ts'; } from '../../constants/messages.ts';
@@ -46,6 +48,7 @@ const FormBtn = styled(Button)`
&:disabled, &:disabled,
&[disabled] { &[disabled] {
background-color: var(--disabled-btn-color); background-color: var(--disabled-btn-color);
cursor: no-drop;
} }
`; `;
@@ -134,8 +137,8 @@ const RoomForm = ({
prop: 'price', prop: 'price',
}), }),
discount: addValidator({ discount: addValidator({
validatorFunc: isValidNumber, validatorFunc: isValidDiscount,
prop: 'discount' customErrorMsg: DISCOUNT_FIELD_ERROR
}), }),
status: addValidator({ status: addValidator({
validatorFunc: skipCheck, validatorFunc: skipCheck,
@@ -305,8 +308,8 @@ const RoomForm = ({
label="Discount" label="Discount"
error={ error={
// prettier-ignore // prettier-ignore
errors.roomId && dirty.roomId errors.discount && dirty.discount
? (errors.roomId as string) ? (errors.discount as string)
: '' : ''
} }
> >
@@ -350,7 +353,7 @@ const RoomForm = ({
// prettier-ignore // prettier-ignore
isAdd isAdd
? 'Add' ? 'Add'
: 'Edit' : 'Save'
} }
</FormBtn> </FormBtn>
<FormBtn type="button" styled="secondary" onClick={closeAndReset}> <FormBtn type="button" styled="secondary" onClick={closeAndReset}>
+4 -4
View File
@@ -125,7 +125,7 @@ const RoomTable = ({
? searchParams.get('orderBy')! ? searchParams.get('orderBy')!
: ''; : '';
const { data, isPending, errorMsg } = useFetch( const { data, isPending, errorFetchMsg } = useFetch(
'rooms', 'rooms',
'name', 'name',
nameSearch, nameSearch,
@@ -141,10 +141,10 @@ const RoomTable = ({
setRooms([]); setRooms([]);
} }
if (errorMsg) { if (errorFetchMsg) {
console.error(errorMsg); console.error(errorFetchMsg);
} }
}, [data, errorMsg]); }, [data, errorFetchMsg]);
return ( return (
<> <>
+35 -2
View File
@@ -39,6 +39,11 @@ import {
errorMsg, errorMsg,
} from '../../constants/messages.ts'; } from '../../constants/messages.ts';
import { USER_PATH } from '../../constants/path.ts'; import { USER_PATH } from '../../constants/path.ts';
import Select from '../../components/Select/index.tsx';
import { useFetch } from '../../hooks/useFetch.ts';
// Interfaces
import { ISelectOptions } from '../../globals/interfaces.ts';
const FormBtn = styled(Button)` const FormBtn = styled(Button)`
width: 100%; width: 100%;
@@ -46,6 +51,7 @@ const FormBtn = styled(Button)`
&:disabled, &:disabled,
&[disabled] { &[disabled] {
background-color: var(--disabled-btn-color); background-color: var(--disabled-btn-color);
cursor: no-drop;
} }
`; `;
@@ -65,6 +71,27 @@ const UserForm = ({
isAdd, isAdd,
}: IUserFormProp) => { }: IUserFormProp) => {
const [reset, setReset] = useState(true); const [reset, setReset] = useState(true);
const [options, setOptions] = useState<ISelectOptions[]>();
const { data, errorFetchMsg } = useFetch('rooms');
useEffect(() => {
if (data) {
const tempData = data as TKeyValue[];
const tempOptions: ISelectOptions[] = [];
tempData.forEach((item) => {
tempOptions.push({
label: item.name! as string,
value: item.id! as string,
});
});
setOptions(tempOptions);
}
if (errorFetchMsg) {
toast.error(errorFetchMsg);
}
}, [data, errorFetchMsg]);
if (isAdd) { if (isAdd) {
// If this is add form, reset value // If this is add form, reset value
@@ -294,11 +321,17 @@ const UserForm = ({
: '' : ''
} }
> >
<Input {/* <Input
type="text" type="text"
name="roomId" name="roomId"
value={roomId as string} value={roomId as string}
onChange={handleOnChange} onChange={handleOnChange}
/> */}
<Select
name="roomId"
value={roomId as string}
onChange={handleOnChange}
options={options!}
/> />
</FormRow> </FormRow>
@@ -325,7 +358,7 @@ const UserForm = ({
// prettier-ignore // prettier-ignore
isAdd isAdd
? 'Add' ? 'Add'
: 'Edit' : 'Save'
} }
</FormBtn> </FormBtn>
<FormBtn type="button" styled="secondary" onClick={closeAndReset}> <FormBtn type="button" styled="secondary" onClick={closeAndReset}>
+6 -6
View File
@@ -22,13 +22,13 @@ import { useFetch } from '../../hooks/useFetch';
import { USER_PATH } from '../../constants/path'; import { USER_PATH } from '../../constants/path';
import { STATUS_CODE } from '../../constants/statusCode'; import { STATUS_CODE } from '../../constants/statusCode';
import { CONFIRM_DELETE, DELETE_SUCCESS } from '../../constants/messages'; import { CONFIRM_DELETE, DELETE_SUCCESS } from '../../constants/messages';
import { USER_PAGE } from '../../constants/variables';
// Styled // Styled
import Spinner from '../../commons/styles/Spinner'; import Spinner from '../../commons/styles/Spinner';
// Utils // Utils
import { sendRequest } from '../../helpers/sendRequest'; import { sendRequest } from '../../helpers/sendRequest';
import { USER_PAGE } from '../../constants/variables';
interface IUserRow { interface IUserRow {
user: TUser; user: TUser;
@@ -119,7 +119,7 @@ const UserTable = ({
? searchParams.get('orderBy')! ? searchParams.get('orderBy')!
: ''; : '';
const { data, isPending, errorMsg } = useFetch( const { data, isPending, errorFetchMsg } = useFetch(
'users', 'users',
'phone', 'phone',
phoneSearch, phoneSearch,
@@ -135,10 +135,10 @@ const UserTable = ({
setUsers([]); setUsers([]);
} }
if (errorMsg) { if (errorFetchMsg) {
console.error(errorMsg); console.error(errorFetchMsg);
} }
}, [data, errorMsg]); }, [data, errorFetchMsg]);
return ( return (
<> <>
@@ -163,7 +163,7 @@ const UserTable = ({
<div>Name</div> <div>Name</div>
<div>Identified Code</div> <div>Identified Code</div>
<div>Phone</div> <div>Phone</div>
<div>Room</div> <div>Room Id</div>
</Table.Header> </Table.Header>
<Table.Body<TUser> <Table.Body<TUser>
data={users} data={users}