mirror of
https://github.com/Nezumi-2711/react-training.git
synced 2026-09-22 13:38:51 +00:00
Fix comments
This commit is contained in:
@@ -49,6 +49,7 @@
|
||||
"husky": "^8.0.0",
|
||||
"lint-staged": "^15.0.1",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^4.4.5"
|
||||
"vite": "^4.4.5",
|
||||
"vite-tsconfig-paths": "^4.2.1"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+37
@@ -70,6 +70,9 @@ devDependencies:
|
||||
vite:
|
||||
specifier: ^4.4.5
|
||||
version: 4.4.11
|
||||
vite-tsconfig-paths:
|
||||
specifier: ^4.2.1
|
||||
version: 4.2.1(typescript@5.2.2)(vite@4.4.11)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -1406,6 +1409,10 @@ packages:
|
||||
slash: 3.0.0
|
||||
dev: true
|
||||
|
||||
/globrex@0.1.2:
|
||||
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
|
||||
dev: true
|
||||
|
||||
/goober@2.1.13(csstype@3.1.2):
|
||||
resolution: {integrity: sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ==}
|
||||
peerDependencies:
|
||||
@@ -2088,6 +2095,19 @@ packages:
|
||||
typescript: 5.2.2
|
||||
dev: true
|
||||
|
||||
/tsconfck@2.1.2(typescript@5.2.2):
|
||||
resolution: {integrity: sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==}
|
||||
engines: {node: ^14.13.1 || ^16 || >=18}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: ^4.3.5 || ^5.0.0
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
typescript: 5.2.2
|
||||
dev: true
|
||||
|
||||
/tslib@2.6.2:
|
||||
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
|
||||
dev: false
|
||||
@@ -2132,6 +2152,23 @@ packages:
|
||||
punycode: 2.3.0
|
||||
dev: true
|
||||
|
||||
/vite-tsconfig-paths@4.2.1(typescript@5.2.2)(vite@4.4.11):
|
||||
resolution: {integrity: sha512-GNUI6ZgPqT3oervkvzU+qtys83+75N/OuDaQl7HmOqFTb0pjZsuARrRipsyJhJ3enqV8beI1xhGbToR4o78nSQ==}
|
||||
peerDependencies:
|
||||
vite: '*'
|
||||
peerDependenciesMeta:
|
||||
vite:
|
||||
optional: true
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
globrex: 0.1.2
|
||||
tsconfck: 2.1.2(typescript@5.2.2)
|
||||
vite: 4.4.11
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: true
|
||||
|
||||
/vite@4.4.11:
|
||||
resolution: {integrity: sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const ButtonIcon = styled.button`
|
||||
background: none;
|
||||
|
||||
padding: 8px;
|
||||
transition: all 0.2s;
|
||||
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--hover-background-color);
|
||||
}
|
||||
|
||||
& svg {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default ButtonIcon;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
// Components
|
||||
import Header from '../Header';
|
||||
import Sidebar from '../Sidebar';
|
||||
import Header from '@component/Header';
|
||||
import Sidebar from '@component/Sidebar';
|
||||
|
||||
// Styled
|
||||
import { Main, StyledAppLayout } from './styled';
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import { COLOR, SIZE } from '@constant/styles';
|
||||
import { ReactNode } from 'react';
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
interface IStyledButtonIcon {
|
||||
isHaveChildren: boolean;
|
||||
style?: {
|
||||
fontSize?: string;
|
||||
backgroundColor?: string;
|
||||
color?: string;
|
||||
};
|
||||
iconStyle?: {
|
||||
color?: string;
|
||||
size?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const StyledButtonIcon = styled.button<IStyledButtonIcon>`
|
||||
background: none;
|
||||
|
||||
padding: 10px;
|
||||
transition: all 0.2s;
|
||||
|
||||
border: none;
|
||||
|
||||
${(props) =>
|
||||
props.style?.fontSize &&
|
||||
css`
|
||||
font-size: ${props.style.fontSize};
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.style?.fontSize &&
|
||||
css`
|
||||
font-size: ${props.style.fontSize};
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.color &&
|
||||
css`
|
||||
font-size: ${props.color};
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.isHaveChildren
|
||||
? css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
`
|
||||
: css`
|
||||
border-radius: var(--radius-md);
|
||||
`}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--hover-background-color);
|
||||
}
|
||||
|
||||
& svg {
|
||||
${(props) =>
|
||||
props.iconStyle?.size &&
|
||||
css`
|
||||
width: ${props.iconStyle.size};
|
||||
height: ${props.iconStyle.size};
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.iconStyle?.color &&
|
||||
css`
|
||||
color: ${props.iconStyle.color};
|
||||
`}
|
||||
transition: all 0.3s;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledButtonIcon.defaultProps = {
|
||||
style: {
|
||||
fontSize: SIZE.DEFAULT,
|
||||
backgroundColor: COLOR.DEFAULT,
|
||||
color: COLOR.BLACK,
|
||||
},
|
||||
iconStyle: {
|
||||
color: COLOR.BLACK,
|
||||
size: SIZE.DEFAULT,
|
||||
},
|
||||
};
|
||||
|
||||
interface IButtonIcon {
|
||||
icon: ReactNode;
|
||||
children?: ReactNode;
|
||||
style?: {
|
||||
fontSize?: string;
|
||||
backgroundColor?: string;
|
||||
color?: string;
|
||||
};
|
||||
iconStyle?: {
|
||||
color?: string;
|
||||
size?: string;
|
||||
};
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const ButtonIcon = ({
|
||||
icon,
|
||||
children,
|
||||
style,
|
||||
iconStyle,
|
||||
onClick,
|
||||
}: IButtonIcon) => {
|
||||
const isHaveChildren = Boolean(children);
|
||||
|
||||
return (
|
||||
<StyledButtonIcon
|
||||
isHaveChildren={isHaveChildren}
|
||||
style={{
|
||||
fontSize: style?.fontSize,
|
||||
backgroundColor: style?.backgroundColor,
|
||||
color: style?.color,
|
||||
}}
|
||||
iconStyle={iconStyle}
|
||||
onClick={onClick}
|
||||
>
|
||||
{icon} <span>{children}</span>
|
||||
</StyledButtonIcon>
|
||||
);
|
||||
};
|
||||
|
||||
export default ButtonIcon;
|
||||
@@ -1,7 +1,7 @@
|
||||
// Components
|
||||
import { IoPersonCircleOutline } from 'react-icons/io5';
|
||||
import { HiOutlineLogout } from 'react-icons/hi';
|
||||
import ButtonIcon from '../../commons/styles/ButtonIcon';
|
||||
import ButtonIcon from '@component/ButtonIcon/ButtonIcon';
|
||||
|
||||
// Styled
|
||||
import { StyledHeaderMenu } from './styled';
|
||||
@@ -10,14 +10,18 @@ const HeaderMenu = () => {
|
||||
return (
|
||||
<StyledHeaderMenu>
|
||||
<li>
|
||||
<ButtonIcon aria-label="Profile">
|
||||
<IoPersonCircleOutline />
|
||||
</ButtonIcon>
|
||||
<ButtonIcon
|
||||
aria-label="Profile"
|
||||
icon={<IoPersonCircleOutline />}
|
||||
iconStyle={{ size: '23px' }}
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<ButtonIcon aria-label="Logout">
|
||||
<HiOutlineLogout />
|
||||
</ButtonIcon>
|
||||
<ButtonIcon
|
||||
aria-label="Logout"
|
||||
icon={<HiOutlineLogout />}
|
||||
iconStyle={{size: '23px' }}
|
||||
/>
|
||||
</li>
|
||||
</StyledHeaderMenu>
|
||||
);
|
||||
|
||||
@@ -4,16 +4,18 @@ import { MouseEvent, ReactNode, useContext, useState } from 'react';
|
||||
import { HiEllipsisVertical } from 'react-icons/hi2';
|
||||
|
||||
// Hooks
|
||||
import { useOutsideClick } from '../../hooks/useOutsideClick';
|
||||
import { useOutsideClick } from '@hook/useOutsideClick';
|
||||
|
||||
// Styled
|
||||
import { StyledMenu, StyledButton, StyledList, StyledToggle } from './styled';
|
||||
import { StyledMenu, StyledList, StyledToggle } from './styled';
|
||||
|
||||
// Contexts
|
||||
import MenusContext from '../../contexts/MenuContext';
|
||||
import MenusContext from '@context/MenuContext';
|
||||
|
||||
// Types
|
||||
import { Nullable } from '../../types/common';
|
||||
import { Nullable } from '@type/common';
|
||||
import ButtonIcon from '@component/ButtonIcon/ButtonIcon';
|
||||
import { COLOR } from '@constant/styles';
|
||||
|
||||
interface IButton {
|
||||
children?: string;
|
||||
@@ -74,9 +76,14 @@ const Button = ({ children, icon, onClick }: IButton): ReactNode => {
|
||||
|
||||
return (
|
||||
<li>
|
||||
<StyledButton onClick={handleClick}>
|
||||
{icon} <span>{children}</span>
|
||||
</StyledButton>
|
||||
<ButtonIcon
|
||||
icon={icon}
|
||||
onClick={handleClick}
|
||||
iconStyle={{ color: COLOR.PRIMARY, size: '19px' }}
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
{children}
|
||||
</ButtonIcon>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,10 +8,10 @@ import {
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
// Hooks
|
||||
import { useOutsideClick } from '../../hooks/useOutsideClick';
|
||||
import { useOutsideClick } from '@hook/useOutsideClick';
|
||||
|
||||
// Contexts
|
||||
import { ModalContext } from '../../contexts/ModalContext';
|
||||
import { ModalContext } from '@context/ModalContext';
|
||||
|
||||
// Styled
|
||||
import { Overlay, StyledModal, StyledModalContent, TitleModal } from './styled';
|
||||
@@ -34,14 +34,14 @@ const Modal = ({ children }: IModal) => {
|
||||
};
|
||||
|
||||
interface IOpen {
|
||||
children: ReactElement;
|
||||
renderChildren: (onCloseModal: () => void) => ReactNode;
|
||||
modalName: string;
|
||||
}
|
||||
|
||||
const Open = ({ children, modalName }: IOpen) => {
|
||||
const Open = ({ renderChildren, modalName }: IOpen) => {
|
||||
const { open } = useContext(ModalContext);
|
||||
|
||||
return cloneElement(children, { onClick: () => open!(modalName) });
|
||||
return renderChildren(() => open!(modalName));
|
||||
};
|
||||
|
||||
interface IWindow {
|
||||
@@ -54,9 +54,6 @@ const Window = ({ children, name, title }: IWindow) => {
|
||||
const { openName, close } = useContext(ModalContext);
|
||||
const ref = useOutsideClick<HTMLDivElement>(close!);
|
||||
|
||||
console.log('name: ', name);
|
||||
console.log('openName: ', openName);
|
||||
|
||||
if (name !== openName) return null;
|
||||
|
||||
return createPortal(
|
||||
|
||||
@@ -7,7 +7,7 @@ import { BsHouseDoorFill } from 'react-icons/bs';
|
||||
import { StyledNav, StyledNavLink } from './styled';
|
||||
|
||||
// Constants
|
||||
import { DASHBOARD, ROOM, USER } from '../../constants/path';
|
||||
import { DASHBOARD, ROOM, USER } from '@constant/path';
|
||||
|
||||
const Nav = () => {
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { memo } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
// Styled
|
||||
@@ -11,7 +10,7 @@ interface IOrderProps {
|
||||
}[];
|
||||
}
|
||||
|
||||
const OrderBy = memo(({ options }: IOrderProps) => {
|
||||
const OrderBy = ({ options }: IOrderProps) => {
|
||||
const field = 'orderBy';
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const currentOrder = searchParams.get(field) || options[0].value;
|
||||
@@ -35,6 +34,6 @@ const OrderBy = memo(({ options }: IOrderProps) => {
|
||||
))}
|
||||
</StyledOrder>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export default OrderBy;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useEffect, useState } from 'react';
|
||||
import { StyledSearch } from './styled';
|
||||
|
||||
// Hooks
|
||||
import { useDebounce } from '../../hooks/useDebounce';
|
||||
import { useDebounce } from '@hook/useDebounce';
|
||||
|
||||
interface ISearch {
|
||||
setPlaceHolder: string;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import {
|
||||
FieldValues,
|
||||
RegisterOptions,
|
||||
UseFormRegister,
|
||||
useFormContext,
|
||||
} from 'react-hook-form';
|
||||
import { ChangeEventHandler, ReactNode } from 'react';
|
||||
import { ChangeEventHandler } from 'react';
|
||||
|
||||
// Styled
|
||||
import { StyledSelect } from './styled';
|
||||
@@ -22,46 +21,6 @@ interface ISelect {
|
||||
ariaLabel: string;
|
||||
}
|
||||
|
||||
interface IRender extends ISelect {
|
||||
register: UseFormRegister<FieldValues>;
|
||||
children: ReactNode[];
|
||||
}
|
||||
|
||||
const RenderSelect = ({
|
||||
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)}
|
||||
>
|
||||
{children}
|
||||
</StyledSelect>
|
||||
);
|
||||
};
|
||||
|
||||
const Select = ({
|
||||
options,
|
||||
id,
|
||||
@@ -75,21 +34,20 @@ const Select = ({
|
||||
if (!options) return;
|
||||
|
||||
return (
|
||||
<RenderSelect
|
||||
register={register}
|
||||
options={options}
|
||||
optionsConfigForm={optionsConfigForm}
|
||||
<StyledSelect
|
||||
aria-label={ariaLabel}
|
||||
id={id}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ariaLabel={ariaLabel}
|
||||
{...(register
|
||||
? { ...register(id!, optionsConfigForm) }
|
||||
: { onChange: onChange })}
|
||||
>
|
||||
{options.map((option) => (
|
||||
<option value={option.value} key={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</RenderSelect>
|
||||
</StyledSelect>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Components
|
||||
import Nav from '../Nav';
|
||||
import Nav from '@component/Nav';
|
||||
|
||||
// Styled
|
||||
import { Heading, StyledSidebar } from './styled';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { ChangeEvent, memo } from 'react';
|
||||
import { ChangeEvent } from 'react';
|
||||
|
||||
// Components
|
||||
import Select from '../Select';
|
||||
import Select from '@component/Select';
|
||||
|
||||
interface ISortByProps {
|
||||
options: {
|
||||
@@ -11,7 +11,7 @@ interface ISortByProps {
|
||||
}[];
|
||||
}
|
||||
|
||||
const SortBy = memo(({ options }: ISortByProps) => {
|
||||
const SortBy = ({ options }: ISortByProps) => {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const sortBy = searchParams.get('sortBy') || '';
|
||||
const handleChange = (event: ChangeEvent<HTMLSelectElement>) => {
|
||||
@@ -27,6 +27,6 @@ const SortBy = memo(({ options }: ISortByProps) => {
|
||||
ariaLabel="Sort"
|
||||
/>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export default SortBy;
|
||||
|
||||
@@ -4,13 +4,17 @@ import { ReactNode, useContext } from 'react';
|
||||
import { StyledBody, StyledHeader, StyledRow, StyledTable } from './styled';
|
||||
|
||||
// Contexts
|
||||
import TableContext from '../../contexts/TableContext';
|
||||
import TableContext from '@context/TableContext';
|
||||
|
||||
export interface ITable {
|
||||
columns?: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export interface IHeader {
|
||||
headerColumn: string[];
|
||||
}
|
||||
|
||||
interface ITableBody<T> {
|
||||
data?: T[];
|
||||
render?: CallbackMapFunc<T>;
|
||||
@@ -26,10 +30,12 @@ const Table = ({ columns, children }: ITable) => {
|
||||
);
|
||||
};
|
||||
|
||||
const Header = ({ children }: ITable) => {
|
||||
const Header = ({ headerColumn }: IHeader) => {
|
||||
const { columns } = useContext(TableContext);
|
||||
|
||||
return <StyledHeader columns={columns}>{children}</StyledHeader>;
|
||||
return <StyledHeader columns={columns}>
|
||||
{headerColumn.map((item) => <div key={item}>{item}</div>)}
|
||||
</StyledHeader>;
|
||||
};
|
||||
|
||||
const Body = <T,>({ data, render }: ITableBody<T>) => {
|
||||
|
||||
+14
-5
@@ -51,9 +51,6 @@ const ROOM_PAGE = {
|
||||
],
|
||||
};
|
||||
|
||||
const VALUE = 'value';
|
||||
const ERROR = 'error';
|
||||
|
||||
const INIT_VALUE_USER_FORM = {
|
||||
name: '',
|
||||
id: 0,
|
||||
@@ -68,11 +65,23 @@ const INIT_VALUE_ROOM_FORM = {
|
||||
discount: 0,
|
||||
};
|
||||
|
||||
const FORM = {
|
||||
EDIT: 'edit',
|
||||
USER: 'user-form',
|
||||
ROOM: 'room-form',
|
||||
};
|
||||
|
||||
const REGEX = {
|
||||
PHONE: /(84|0[3|5|7|8|9])+([0-9]{8})\b/g,
|
||||
NAME: /^[a-zA-Z]{2,}(?: [a-zA-Z]+){0,2}$/gm,
|
||||
NUMBER: /^[0-9]*$/,
|
||||
};
|
||||
|
||||
export {
|
||||
USER_PAGE,
|
||||
ROOM_PAGE,
|
||||
VALUE,
|
||||
ERROR,
|
||||
FORM,
|
||||
REGEX,
|
||||
ORDERBY_OPTIONS,
|
||||
INIT_VALUE_USER_FORM,
|
||||
INIT_VALUE_ROOM_FORM,
|
||||
@@ -0,0 +1,11 @@
|
||||
const COLOR = {
|
||||
PRIMARY: '#0010ba',
|
||||
BLACK: '#000',
|
||||
DEFAULT: 'transparent',
|
||||
};
|
||||
|
||||
const SIZE = {
|
||||
DEFAULT: '14px',
|
||||
};
|
||||
|
||||
export { COLOR, SIZE };
|
||||
@@ -1,8 +1,8 @@
|
||||
// Constants
|
||||
import { BASE_URL } from '../constants/path';
|
||||
import { BASE_URL } from '@constant/path';
|
||||
|
||||
// Types
|
||||
import { IResponse } from '../types/responses';
|
||||
import { IResponse } from '@type/responses';
|
||||
|
||||
type TMethodRequest = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
||||
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
/**
|
||||
* Check value is valid name or not
|
||||
* @param value Values need to be checked
|
||||
* @returns A boolean indicating whether or not the argument has valid
|
||||
*/
|
||||
const isValidName = (value: string): boolean => {
|
||||
return /^[a-zA-Z]{2,}(?: [a-zA-Z]+){0,2}$/gm.test(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check value is valid number or not
|
||||
* Compare the regex with value
|
||||
* @param regex The regex to compare
|
||||
* @param value Value need to be checked
|
||||
* @returns A boolean indicating whether or not the argument has valid
|
||||
* @returns A boolean indicating whether of not the argument has valid
|
||||
*/
|
||||
const isValidNumber = (value: string): boolean => {
|
||||
return /^[0-9]*$/.test(value);
|
||||
};
|
||||
const isValidRegex = (regex: RegExp, value: string): boolean => {
|
||||
return regex.test(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check value is valid discount or not
|
||||
@@ -25,14 +17,6 @@ const isValidDiscount = (value: number): boolean => {
|
||||
return value >= 0 && value <= 100;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check value is valid phone number or not
|
||||
* @param value Value need to be checked
|
||||
* @returns A boolean indicating whether or not the argument has valid
|
||||
*/
|
||||
const isValidPhoneNumber = (value: string): boolean => {
|
||||
return /(84|0[3|5|7|8|9])+([0-9]{8})\b/g.test(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check value is valid string or not
|
||||
@@ -43,12 +27,6 @@ const isValidString = (value: string): boolean => {
|
||||
return value.trim().length >= 5;
|
||||
};
|
||||
|
||||
/**
|
||||
* A method skip check value
|
||||
* @returns Return true
|
||||
*/
|
||||
const skipCheck = () => true;
|
||||
|
||||
/**
|
||||
* Check object is empty or not
|
||||
* @param obj Object need to be check
|
||||
@@ -59,11 +37,8 @@ const isEmptyObj = (obj: object) => {
|
||||
};
|
||||
|
||||
export {
|
||||
isValidName,
|
||||
isValidNumber,
|
||||
isValidPhoneNumber,
|
||||
isValidRegex,
|
||||
isValidString,
|
||||
skipCheck,
|
||||
isValidDiscount,
|
||||
isEmptyObj,
|
||||
};
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
// Constants
|
||||
import { BASE_URL } from '../constants/path';
|
||||
import { DEFAULT_ORDER_BY, DEFAULT_SORT_BY } from '../constants/config';
|
||||
import { BASE_URL } from '@constant/path';
|
||||
import { DEFAULT_ORDER_BY, DEFAULT_SORT_BY } from '@constant/config';
|
||||
|
||||
// Helpers
|
||||
import { searchQuery } from '../helpers/helper';
|
||||
import { searchQuery } from '@helper/helper';
|
||||
|
||||
// Types
|
||||
import { Nullable } from '../types/common';
|
||||
import { Nullable } from '@type/common';
|
||||
|
||||
/**
|
||||
* The function use to fetch data on server API.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ForwardedRef, useEffect, useRef } from 'react';
|
||||
|
||||
// Types
|
||||
import { Nullable } from '../types/common';
|
||||
import { Nullable } from '@type/common';
|
||||
|
||||
const useForwardRef = <T>(
|
||||
ref: ForwardedRef<T>,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MutableRefObject, useEffect, useRef } from 'react';
|
||||
|
||||
// Types
|
||||
import { Nullable } from '../types/common';
|
||||
import { Nullable } from '@type/common';
|
||||
|
||||
/**
|
||||
* Custom hook to call handler when click outside element
|
||||
|
||||
@@ -2,25 +2,26 @@ import { useSearchParams } from 'react-router-dom';
|
||||
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
||||
|
||||
// Components
|
||||
import { StyledOperationTable } from './styled';
|
||||
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';
|
||||
import Menus from '@component/Menus';
|
||||
import Table from '@component/Table';
|
||||
import Message from '@component/Message';
|
||||
import Search from '@component/Search';
|
||||
import SortBy from '@component/SortBy';
|
||||
import OrderBy from '@component/OrderBy';
|
||||
import RoomRow from './RoomRow';
|
||||
|
||||
// Types
|
||||
import { IRoom } from '../../types/rooms';
|
||||
import { IRoom } from '@type/rooms';
|
||||
|
||||
// Constants
|
||||
import { useFetch } from '../../hooks/useFetch';
|
||||
import { ORDERBY_OPTIONS, ROOM_PAGE } from '../../constants/variables';
|
||||
import { useFetch } from '@hook/useFetch';
|
||||
import { ORDERBY_OPTIONS, ROOM_PAGE } from '@constant/commons';
|
||||
|
||||
// Styled
|
||||
import Spinner from '../../commons/styles/Spinner';
|
||||
import RoomRow from './RoomRow';
|
||||
import { StyledOperationTable } from './styled';
|
||||
import Direction from '@commonStyle/Direction';
|
||||
import Spinner from '@commonStyle/Spinner';
|
||||
|
||||
|
||||
interface IRoomTable {
|
||||
reload: boolean;
|
||||
@@ -28,6 +29,7 @@ interface IRoomTable {
|
||||
}
|
||||
|
||||
const RoomTable = ({ reload, setReload }: IRoomTable) => {
|
||||
const columnName = ['Id', 'Name', 'Price', 'Status'];
|
||||
const [nameSearch, setNameSearch] = useState('');
|
||||
const [searchParams] = useSearchParams();
|
||||
const [rooms, setRooms] = useState<IRoom[]>([]);
|
||||
@@ -77,12 +79,7 @@ const RoomTable = ({ reload, setReload }: IRoomTable) => {
|
||||
{rooms.length ? (
|
||||
<Menus>
|
||||
<Table columns="10% 40% 20% 20% 5%">
|
||||
<Table.Header>
|
||||
<div>Id</div>
|
||||
<div>Name</div>
|
||||
<div>Price</div>
|
||||
<div>Status</div>
|
||||
</Table.Header>
|
||||
<Table.Header headerColumn={columnName}/>
|
||||
<Table.Body<IRoom>
|
||||
data={rooms}
|
||||
render={(room: IRoom) => (
|
||||
|
||||
@@ -6,36 +6,35 @@ import styled from 'styled-components';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
// Styled
|
||||
import Button from '../../commons/styles/Button.ts';
|
||||
import Input from '../../commons/styles/Input.ts';
|
||||
import Button from '@commonStyle/Button.ts';
|
||||
import Input from '@commonStyle/Input.ts';
|
||||
|
||||
// Types
|
||||
import { Nullable } from '../../types/common.ts';
|
||||
import { IRoom } from '../../types/rooms.ts';
|
||||
import { Nullable } from '@type/common.ts';
|
||||
import { IRoom } from '@type/rooms.ts';
|
||||
|
||||
// Constants
|
||||
import {
|
||||
ADD_SUCCESS,
|
||||
EDIT_SUCCESS,
|
||||
} from '../../constants/messages.ts';
|
||||
import { ADD_SUCCESS, EDIT_SUCCESS } from '@constant/messages.ts';
|
||||
import {
|
||||
INVALID_DISCOUNT,
|
||||
INVALID_FIELD,
|
||||
REQUIRED_FIELD_ERROR,
|
||||
} from '../../constants/formValidateMessage.ts';
|
||||
} from '@constant/formValidateMessage.ts';
|
||||
import { INIT_VALUE_ROOM_FORM, REGEX } from '../../constants/commons.ts';
|
||||
|
||||
// Helpers
|
||||
import {
|
||||
isValidDiscount,
|
||||
isValidNumber,
|
||||
isValidRegex,
|
||||
isValidString,
|
||||
} from '../../helpers/validators.ts';
|
||||
} from '@helper/validators.ts';
|
||||
|
||||
// Components
|
||||
import FormRow from '../../components/LabelControl/index.tsx';
|
||||
import Form from '../../components/Form/index.tsx';
|
||||
import { addRoom, updateRoom } from '../../services/roomServices.ts';
|
||||
import { INIT_VALUE_ROOM_FORM } from '../../constants/variables.ts';
|
||||
import FormRow from '@component/LabelControl/index.tsx';
|
||||
import Form from '@component/Form/index.tsx';
|
||||
|
||||
// Services
|
||||
import { addRoom, updateRoom } from '@service/roomServices.ts';
|
||||
|
||||
const FormBtn = styled(Button)`
|
||||
width: 100%;
|
||||
@@ -82,30 +81,25 @@ const RoomForm = ({
|
||||
// Calculate final price
|
||||
room.finalPrice = room.price - (room.price * room.discount) / 100;
|
||||
|
||||
try {
|
||||
if (!roomEdit) {
|
||||
// Add request
|
||||
const response = await addRoom(room);
|
||||
|
||||
if(response) {
|
||||
toast.success(ADD_SUCCESS);
|
||||
}
|
||||
} else {
|
||||
// Edit request
|
||||
const response = await updateRoom(room);
|
||||
if (!roomEdit) {
|
||||
// Add request
|
||||
const response = await addRoom(room);
|
||||
|
||||
if (response) {
|
||||
toast.success(EDIT_SUCCESS);
|
||||
}
|
||||
if (response) {
|
||||
toast.success(ADD_SUCCESS);
|
||||
}
|
||||
// Reload table data
|
||||
setReload!(!reload);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
toast.error(error.message);
|
||||
} else {
|
||||
// Edit request
|
||||
const response = await updateRoom(room);
|
||||
|
||||
if (response) {
|
||||
toast.success(EDIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
// Reload table data
|
||||
setReload!(!reload);
|
||||
|
||||
reset();
|
||||
onCloseModal!();
|
||||
};
|
||||
@@ -136,7 +130,7 @@ const RoomForm = ({
|
||||
required: REQUIRED_FIELD_ERROR,
|
||||
validate: {
|
||||
checkIdentifiedCode: (v) =>
|
||||
isValidNumber(v.toString()) || INVALID_FIELD,
|
||||
isValidRegex(REGEX.NUMBER, v.toString()) || INVALID_FIELD,
|
||||
},
|
||||
onChange: () => trigger('price'),
|
||||
})}
|
||||
@@ -159,7 +153,11 @@ const RoomForm = ({
|
||||
</FormRow>
|
||||
|
||||
<Form.Action>
|
||||
<FormBtn type="submit" name="submit" disabled={!isDirty || !isValid || isSubmitting}>
|
||||
<FormBtn
|
||||
type="submit"
|
||||
name="submit"
|
||||
disabled={!isDirty || !isValid || isSubmitting}
|
||||
>
|
||||
{
|
||||
!roomEdit
|
||||
? 'Add'
|
||||
|
||||
@@ -2,22 +2,22 @@ import { Dispatch, SetStateAction } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
// Constants
|
||||
import { ROOM_PATH } from '../../constants/path';
|
||||
import { STATUS_CODE } from '../../constants/responseStatus';
|
||||
import { CONFIRM_DELETE, DELETE_SUCCESS } from '../../constants/messages';
|
||||
import { ROOM_PATH } from '@constant/path';
|
||||
import { STATUS_CODE } from '@constant/responseStatus';
|
||||
import { CONFIRM_DELETE, DELETE_SUCCESS } from '@constant/messages';
|
||||
|
||||
// Helpers
|
||||
import { sendRequest } from '../../helpers/sendRequest';
|
||||
import { formatCurrency } from '../../helpers/helper';
|
||||
import Modal from '../../components/Modal';
|
||||
import RoomForm from './RoomForm';
|
||||
import { sendRequest } from '@helper/sendRequest';
|
||||
import { formatCurrency } from '@helper/helper';
|
||||
|
||||
// Types
|
||||
import { IRoom } from '../../types/rooms';
|
||||
import { IRoom } from '@type/rooms';
|
||||
|
||||
// Components
|
||||
import Table from '../../components/Table';
|
||||
import Menus from '../../components/Menus';
|
||||
import RoomForm from './RoomForm';
|
||||
import Modal from '@component/Modal';
|
||||
import Table from '@component/Table';
|
||||
import Menus from '@component/Menus';
|
||||
import { RiEditBoxFill } from 'react-icons/ri';
|
||||
import { HiTrash } from 'react-icons/hi';
|
||||
|
||||
@@ -43,7 +43,9 @@ const RoomRow = ({ room, reload, setReload }: IRoomRow) => {
|
||||
|
||||
const { id, name, finalPrice, status } = room;
|
||||
|
||||
const statusText = status ? 'Unavailable' : 'Available';
|
||||
const statusText = status
|
||||
? 'Unavailable'
|
||||
: 'Available';
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
@@ -58,9 +60,14 @@ const RoomRow = ({ room, reload, setReload }: IRoomRow) => {
|
||||
<Menus.Toggle id={id.toString()} />
|
||||
|
||||
<Menus.List id={id.toString()}>
|
||||
<Modal.Open modalName="edit">
|
||||
<Menus.Button icon={<RiEditBoxFill />}>Edit</Menus.Button>
|
||||
</Modal.Open>
|
||||
<Modal.Open
|
||||
modalName="edit"
|
||||
renderChildren={(onCloseModal) => (
|
||||
<Menus.Button onClick={onCloseModal} icon={<RiEditBoxFill />}>
|
||||
Edit
|
||||
</Menus.Button>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Menus.Button
|
||||
icon={<HiTrash />}
|
||||
|
||||
@@ -2,15 +2,15 @@ import { useState } from 'react';
|
||||
|
||||
// Components
|
||||
import RoomTable from './RomTable';
|
||||
import RoomForm from './RoomForm';
|
||||
|
||||
// Styled
|
||||
import { StyledRoom, Title } from './styled';
|
||||
import Direction from '../../commons/styles/Direction';
|
||||
import Button from '../../commons/styles/Button';
|
||||
import Direction from '@commonStyle/Direction.ts';
|
||||
import Button from '@commonStyle/Button';
|
||||
|
||||
// Types
|
||||
import Modal from '../../components/Modal';
|
||||
import RoomForm from './RoomForm';
|
||||
import Modal from '@component/Modal';
|
||||
|
||||
const Room = () => {
|
||||
const [reload, setReload] = useState(true);
|
||||
@@ -22,19 +22,19 @@ const Room = () => {
|
||||
<Title>List Room</Title>
|
||||
|
||||
<Modal>
|
||||
<Modal.Open modalName="room-form">
|
||||
<Button>Add room</Button>
|
||||
</Modal.Open>
|
||||
<Modal.Open
|
||||
modalName="room-form"
|
||||
renderChildren={(onCloseModal) => (
|
||||
<Button onClick={onCloseModal}>Add room</Button>
|
||||
)}
|
||||
/>
|
||||
<Modal.Window name="room-form" title="Add form">
|
||||
<RoomForm setReload={setReload} reload={reload} />
|
||||
</Modal.Window>
|
||||
</Modal>
|
||||
</Direction>
|
||||
|
||||
<RoomTable
|
||||
reload={reload}
|
||||
setReload={setReload}
|
||||
/>
|
||||
<RoomTable reload={reload} setReload={setReload} />
|
||||
</StyledRoom>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -11,41 +11,38 @@ import toast from 'react-hot-toast';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
|
||||
// Styled
|
||||
import Input from '../../commons/styles/Input.ts';
|
||||
import Input from '@commonStyle/Input.ts';
|
||||
|
||||
// Components
|
||||
import Form from '../../components/Form/index.tsx';
|
||||
import FormRow from '../../components/LabelControl/index.tsx';
|
||||
import Select, { ISelectOptions } from '../../components/Select/index.tsx';
|
||||
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,
|
||||
isValidName,
|
||||
isValidNumber,
|
||||
isValidPhoneNumber,
|
||||
} from '../../helpers/validators.ts';
|
||||
isEmptyObj, isValidRegex,
|
||||
} from '@helper/validators.ts';
|
||||
|
||||
// Constants
|
||||
import { ADD_SUCCESS, EDIT_SUCCESS } from '../../constants/messages.ts';
|
||||
import { ADD_SUCCESS, EDIT_SUCCESS } from '@constant/messages.ts';
|
||||
import {
|
||||
INVALID_FIELD,
|
||||
INVALID_PHONE,
|
||||
REQUIRED_FIELD_ERROR,
|
||||
} from '../../constants/formValidateMessage.ts';
|
||||
import { INIT_VALUE_USER_FORM } from '../../constants/variables.ts';
|
||||
} from '@constant/formValidateMessage.ts';
|
||||
import { INIT_VALUE_USER_FORM, REGEX } from '@constant/commons.ts';
|
||||
|
||||
// Styled
|
||||
import { FormBtn } from './styled.ts';
|
||||
|
||||
// Services
|
||||
import { getAllRoom, updateRoomStatus } from '../../services/roomServices.ts';
|
||||
import { getAllRoom, updateRoomStatus } from '@service/roomServices.ts';
|
||||
import { createUser, updateUser } from '@service/userServices.ts';
|
||||
|
||||
// Types
|
||||
import { Nullable } from '../../types/common.ts';
|
||||
import { IUser } from '../../types/users.ts';
|
||||
import { IRoom } from '../../types/rooms.ts';
|
||||
import { createUser, updateUser } from '../../services/userServices.ts';
|
||||
import { Nullable } from '@type/common.ts';
|
||||
import { IUser } from '@type/users.ts';
|
||||
import { IRoom } from '@type/rooms.ts';
|
||||
|
||||
interface IUserFormProp {
|
||||
onCloseModal?: () => void;
|
||||
@@ -109,35 +106,29 @@ const UserForm = ({ onCloseModal, reload, setReload, user }: IUserFormProp) => {
|
||||
// Submit form
|
||||
const onSubmit = useCallback(
|
||||
async (newUser: IUser) => {
|
||||
try {
|
||||
if (!user) {
|
||||
// Add request
|
||||
const response = await createUser(newUser);
|
||||
if (!user) {
|
||||
// Add request
|
||||
const response = await createUser(newUser);
|
||||
|
||||
if (response) {
|
||||
toast.success(ADD_SUCCESS);
|
||||
}
|
||||
|
||||
// Update room status
|
||||
updateRoomStatus(newUser.roomId, true);
|
||||
} else {
|
||||
// Edit request
|
||||
const response = await updateUser(newUser);
|
||||
|
||||
if (response) {
|
||||
toast.success(EDIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Update room status
|
||||
updateRoomStatus(user!.roomId, true, newUser.roomId);
|
||||
if (response) {
|
||||
toast.success(ADD_SUCCESS);
|
||||
}
|
||||
// Reload table data
|
||||
setReload(!reload);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
toast.error(error.message);
|
||||
|
||||
// Update room status
|
||||
updateRoomStatus(newUser.roomId, true);
|
||||
} 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!();
|
||||
@@ -169,7 +160,7 @@ const UserForm = ({ onCloseModal, reload, setReload, user }: IUserFormProp) => {
|
||||
{...register('name', {
|
||||
required: REQUIRED_FIELD_ERROR,
|
||||
validate: {
|
||||
checkValidName: (value) => isValidName(value) || INVALID_FIELD,
|
||||
checkValidName: (value) => isValidRegex(REGEX.NAME, value) || INVALID_FIELD,
|
||||
},
|
||||
onChange: () => trigger('name'),
|
||||
})}
|
||||
@@ -187,7 +178,7 @@ const UserForm = ({ onCloseModal, reload, setReload, user }: IUserFormProp) => {
|
||||
required: REQUIRED_FIELD_ERROR,
|
||||
validate: {
|
||||
checkIdentifiedCode: (v) =>
|
||||
isValidNumber(v.toString()) || INVALID_FIELD,
|
||||
isValidRegex(REGEX.NUMBER, v.toString()) || INVALID_FIELD,
|
||||
},
|
||||
onChange: () => trigger('identifiedCode'),
|
||||
})}
|
||||
@@ -201,7 +192,7 @@ const UserForm = ({ onCloseModal, reload, setReload, user }: IUserFormProp) => {
|
||||
{...register('phone', {
|
||||
required: REQUIRED_FIELD_ERROR,
|
||||
validate: {
|
||||
checkPhoneNum: (v) => isValidPhoneNumber(v) || INVALID_PHONE,
|
||||
checkPhoneNum: (v) => isValidRegex(REGEX.PHONE, v) || INVALID_PHONE,
|
||||
},
|
||||
onChange: () => trigger('phone'),
|
||||
})}
|
||||
|
||||
@@ -2,31 +2,27 @@ import { useSearchParams } from 'react-router-dom';
|
||||
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
||||
|
||||
// Components
|
||||
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 { IUser } from '../../types/users';
|
||||
|
||||
// Hooks
|
||||
import { useFetch } from '../../hooks/useFetch';
|
||||
|
||||
// Constants
|
||||
import { ORDERBY_OPTIONS, USER_PAGE } from '../../constants/variables';
|
||||
|
||||
// Styled
|
||||
import { StyledOperationTable } from './styled';
|
||||
import Spinner from '../../commons/styles/Spinner';
|
||||
import Menus from '@component/Menus';
|
||||
import Table from '@component/Table';
|
||||
import Message from '@component/Message';
|
||||
import Search from '@component/Search';
|
||||
import SortBy from '@component/SortBy';
|
||||
import OrderBy from '@component/OrderBy';
|
||||
import UserRow from './UserRow';
|
||||
|
||||
// Types
|
||||
import { IUser } from '@type/users';
|
||||
|
||||
// Hooks
|
||||
import { useFetch } from '@hook/useFetch';
|
||||
|
||||
// Constants
|
||||
import { ORDERBY_OPTIONS, USER_PAGE } from '@constant/commons';
|
||||
|
||||
// Styled
|
||||
import Direction from '@commonStyle/Direction';
|
||||
import { StyledOperationTable } from './styled';
|
||||
import Spinner from '@commonStyle/Spinner';
|
||||
|
||||
interface IUserTable {
|
||||
reload: boolean;
|
||||
@@ -34,6 +30,7 @@ interface IUserTable {
|
||||
}
|
||||
|
||||
const UserTable = ({ reload, setReload }: IUserTable) => {
|
||||
const columnName = ['Id', 'Name', 'Identified Code', 'Phone', 'Room Id'];
|
||||
const [users, setUsers] = useState<IUser[]>([]);
|
||||
const [phoneSearch, setPhoneSearch] = useState('');
|
||||
const [searchParams] = useSearchParams();
|
||||
@@ -83,13 +80,7 @@ const UserTable = ({ reload, setReload }: IUserTable) => {
|
||||
{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.Header headerColumn={columnName} />
|
||||
<Table.Body<IUser>
|
||||
data={users}
|
||||
render={(user: IUser) => (
|
||||
|
||||
@@ -4,21 +4,21 @@ import { Dispatch, SetStateAction } from 'react';
|
||||
// Components
|
||||
import { RiEditBoxFill } from 'react-icons/ri';
|
||||
import { IoExit } from 'react-icons/io5';
|
||||
import Modal from '../../components/Modal';
|
||||
import Modal from '@component/Modal';
|
||||
import Table from '@component/Table';
|
||||
import Menus from '@component/Menus';
|
||||
import UserForm from './FormUser';
|
||||
import Table from '../../components/Table';
|
||||
import Menus from '../../components/Menus';
|
||||
|
||||
// Constants
|
||||
import { STATUS_CODE } from '../../constants/responseStatus';
|
||||
import { CONFIRM_MESSAGE, DENIED_ACTION } from '../../constants/messages';
|
||||
import { STATUS_CODE } from '@constant/responseStatus';
|
||||
import { CONFIRM_MESSAGE, DENIED_ACTION } from '@constant/messages';
|
||||
|
||||
// Services
|
||||
import { updateRoomStatus } from '../../services/roomServices';
|
||||
import { checkOutUser } from '../../services/userServices';
|
||||
import { updateRoomStatus } from '@service/roomServices';
|
||||
import { checkOutUser } from '@service/userServices';
|
||||
|
||||
// Types
|
||||
import { IUser } from '../../types/users';
|
||||
import { IUser } from '@type/users';
|
||||
|
||||
interface IUserRow {
|
||||
user: IUser;
|
||||
@@ -56,17 +56,27 @@ const UserRow = ({ user, reload, setReload }: IUserRow) => {
|
||||
<div>{name}</div>
|
||||
<div>{identifiedCode}</div>
|
||||
<div>{phone}</div>
|
||||
<div>{roomId ? roomId : 'None'}</div>
|
||||
|
||||
<div>
|
||||
{
|
||||
roomId
|
||||
? roomId
|
||||
: 'None'
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
<Modal>
|
||||
<Menus.Menu>
|
||||
<Menus.Toggle id={id.toString()} />
|
||||
|
||||
<Menus.List id={id.toString()}>
|
||||
<Modal.Open modalName="edit">
|
||||
<Menus.Button icon={<RiEditBoxFill />}>Edit</Menus.Button>
|
||||
</Modal.Open>
|
||||
<Modal.Open
|
||||
modalName="edit"
|
||||
renderChildren={(onCloseModal) => (
|
||||
<Menus.Button onClick={onCloseModal} icon={<RiEditBoxFill />}>
|
||||
Edit
|
||||
</Menus.Button>
|
||||
)}
|
||||
/>
|
||||
<Menus.Button
|
||||
icon={<IoExit />}
|
||||
onClick={() => handleCheckOut(user)}
|
||||
|
||||
@@ -4,15 +4,19 @@ import { useState } from 'react';
|
||||
import UserTable from './TableUser';
|
||||
|
||||
// Styled
|
||||
import Button from '../../commons/styles/Button';
|
||||
import Direction from '../../commons/styles/Direction';
|
||||
import Button from '@commonStyle/Button';
|
||||
import Direction from '@commonStyle/Direction.ts';
|
||||
import { StyledUser, Title } from './styled';
|
||||
|
||||
// Types
|
||||
import Modal from '../../components/Modal';
|
||||
import Modal from '@component/Modal';
|
||||
import UserForm from './FormUser';
|
||||
|
||||
// Constants
|
||||
import { FORM } from '@constant/commons';
|
||||
|
||||
const User = () => {
|
||||
const ADD_ROOM = 'Add room';
|
||||
const [reload, setReload] = useState(true);
|
||||
|
||||
return (
|
||||
@@ -22,10 +26,13 @@ const User = () => {
|
||||
<Title>List User</Title>
|
||||
|
||||
<Modal>
|
||||
<Modal.Open modalName="user-form">
|
||||
<Button>Add user</Button>
|
||||
</Modal.Open>
|
||||
<Modal.Window name="user-form" title="Add form">
|
||||
<Modal.Open
|
||||
modalName={FORM.USER}
|
||||
renderChildren={(onCloseModal) => (
|
||||
<Button onClick={onCloseModal}>Add user</Button>
|
||||
)}
|
||||
/>
|
||||
<Modal.Window name={FORM.USER} title={ADD_ROOM}>
|
||||
<UserForm setReload={setReload} reload={reload} />
|
||||
</Modal.Window>
|
||||
</Modal>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
// Types
|
||||
import { Nullable } from '../types/common';
|
||||
import { IResponse } from '../types/responses';
|
||||
import { IRoom } from '../types/rooms';
|
||||
import { Nullable } from '@type/common';
|
||||
import { IResponse } from '@type/responses';
|
||||
import { IRoom } from '@type/rooms';
|
||||
|
||||
// Helpers
|
||||
import { sendRequest } from '../helpers/sendRequest';
|
||||
import { errorMsg } from '../helpers/helper';
|
||||
import { sendRequest } from '@helper/sendRequest';
|
||||
import { errorMsg } from '@helper/helper';
|
||||
|
||||
// Constants
|
||||
import { STATUS_CODE, RESPONSE_MESSAGE } from '../constants/responseStatus';
|
||||
import { ROOM_PATH } from '../constants/path';
|
||||
import { STATUS_CODE, RESPONSE_MESSAGE } from '@constant/responseStatus';
|
||||
import { ROOM_PATH } from '@constant/path';
|
||||
|
||||
/**
|
||||
* Get all rooms from server
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
// Constants
|
||||
import { USER_PATH } from '../constants/path';
|
||||
import { STATUS_CODE } from '../constants/responseStatus';
|
||||
import { USER_PATH } from '@constant/path';
|
||||
import { STATUS_CODE } from '@constant/responseStatus';
|
||||
|
||||
// Types
|
||||
import { Nullable } from '../types/common';
|
||||
import { IResponse } from '../types/responses';
|
||||
import { IUser } from '../types/users';
|
||||
import { Nullable } from '@type/common';
|
||||
import { IResponse } from '@type/responses';
|
||||
import { IUser } from '@type/users';
|
||||
|
||||
// Helpers
|
||||
import { sendRequest } from '../helpers/sendRequest';
|
||||
import { errorMsg } from '../helpers/helper';
|
||||
import { sendRequest } from '@helper/sendRequest';
|
||||
import { errorMsg } from '@helper/helper';
|
||||
|
||||
/**
|
||||
* Create user to the server
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
"types": ["node"],
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
@@ -18,7 +19,20 @@
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
/* Alias */
|
||||
"paths": {
|
||||
"@service/*": ["./src/services/*"],
|
||||
"@constant/*": ["./src/constants/*"],
|
||||
"@hook/*": ["./src/hooks/*"],
|
||||
"@helper/*": ["./src/helpers/*"],
|
||||
"@context/*": ["./src/contexts/*"],
|
||||
"@component/*": ["./src/components/*"],
|
||||
"@commonStyle/*": ["./src/commons/styles/*"],
|
||||
"@type/*": ["./src/types/*"],
|
||||
"@page/*": ["./src/pages/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import tsconfigPaths from 'vite-tsconfig-paths'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
plugins: [react(), tsconfigPaths()],
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user