mirror of
https://github.com/Nezumi-2711/react-training.git
synced 2026-09-22 13:38:51 +00:00
Merge pull request #16 from Nez27/feat/edit-delete-user
Implement add and edit user function
This commit is contained in:
@@ -12,6 +12,8 @@ dist
|
|||||||
dist-ssr
|
dist-ssr
|
||||||
*.local
|
*.local
|
||||||
|
|
||||||
|
src/db.json
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
{
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"id": "123",
|
|
||||||
"name": "Nezumi",
|
|
||||||
"identifiedCode": "123",
|
|
||||||
"phone": "0937425123",
|
|
||||||
"roomId": 246,
|
|
||||||
"address": "Da Nang"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "231",
|
|
||||||
"name": "Phan Huu Loi",
|
|
||||||
"identifiedCode": "123",
|
|
||||||
"phone": "0937425123",
|
|
||||||
"roomId": 246,
|
|
||||||
"address": "Ho Chi Minh"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "312",
|
|
||||||
"name": "Nezumi",
|
|
||||||
"identifiedCode": "123",
|
|
||||||
"phone": "0937425123",
|
|
||||||
"roomId": 246,
|
|
||||||
"address": "Da Nang"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "523",
|
|
||||||
"name": "Nezumi",
|
|
||||||
"identifiedCode": "123",
|
|
||||||
"phone": "0937425123",
|
|
||||||
"roomId": 246,
|
|
||||||
"address": "Da Nang"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "534",
|
|
||||||
"name": "Nezumi",
|
|
||||||
"identifiedCode": "123",
|
|
||||||
"phone": "0937425123",
|
|
||||||
"roomId": 246,
|
|
||||||
"address": "Da Nang"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "756",
|
|
||||||
"name": "Nezumi",
|
|
||||||
"identifiedCode": "123",
|
|
||||||
"phone": "0937425123",
|
|
||||||
"roomId": 246,
|
|
||||||
"address": "Da Nang"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "23",
|
|
||||||
"name": "Nezumi",
|
|
||||||
"identifiedCode": "123",
|
|
||||||
"phone": "0937425123",
|
|
||||||
"roomId": 246,
|
|
||||||
"address": "Da Nang"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "756",
|
|
||||||
"name": "Nezumi",
|
|
||||||
"identifiedCode": "123",
|
|
||||||
"phone": "0937425123",
|
|
||||||
"roomId": 246,
|
|
||||||
"address": "Da Nang"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "756",
|
|
||||||
"name": "Nezumi",
|
|
||||||
"identifiedCode": "123",
|
|
||||||
"phone": "0937425123",
|
|
||||||
"roomId": 246,
|
|
||||||
"address": "Da Nang"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -2,10 +2,20 @@ const invalidFormatMsg = (field: string) => {
|
|||||||
return `Invalid ${field} format`;
|
return `Invalid ${field} format`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ADD_SUCCESS = 'Add success';
|
|
||||||
|
|
||||||
const errorMsg = (errorCode: number, msg: string) => {
|
const errorMsg = (errorCode: number, msg: string) => {
|
||||||
return `Error code: ${errorCode}. Message: ${msg}`;
|
return `Error code: ${errorCode}. Message: ${msg}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { invalidFormatMsg, ADD_SUCCESS, errorMsg };
|
const ADD_SUCCESS = 'Add success';
|
||||||
|
const EDIT_SUCCESS = 'Edit success';
|
||||||
|
const CONFIRM_DELETE = 'Are you sure to delete it?';
|
||||||
|
const DELETE_SUCCESS = 'Delete success';
|
||||||
|
|
||||||
|
export {
|
||||||
|
invalidFormatMsg,
|
||||||
|
ADD_SUCCESS,
|
||||||
|
errorMsg,
|
||||||
|
EDIT_SUCCESS,
|
||||||
|
CONFIRM_DELETE,
|
||||||
|
DELETE_SUCCESS,
|
||||||
|
};
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ 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 = 'https://hotel-management-api.loiphan.com/';
|
||||||
|
export const USER_PATH = 'users';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const STATUS_CODE = {
|
const STATUS_CODE = {
|
||||||
|
OK: 200,
|
||||||
CREATE: 201,
|
CREATE: 201,
|
||||||
NOT_FOUND: 404,
|
NOT_FOUND: 404,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Types
|
||||||
|
import { TUser } from './types';
|
||||||
|
|
||||||
interface IMenusContext {
|
interface IMenusContext {
|
||||||
openId?: string;
|
openId?: string;
|
||||||
close?: () => void;
|
close?: () => void;
|
||||||
@@ -27,6 +30,8 @@ interface IDialogProps {
|
|||||||
reload?: boolean;
|
reload?: boolean;
|
||||||
setReload?: React.Dispatch<React.SetStateAction<boolean>>;
|
setReload?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
ref?: React.MutableRefObject<HTMLDialogElement | undefined>;
|
ref?: React.MutableRefObject<HTMLDialogElement | undefined>;
|
||||||
|
user?: TUser | null;
|
||||||
|
isAdd?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { IMenusContext, IButton, ITable, ITableBody, IDialogProps };
|
export type { IMenusContext, IButton, ITable, ITableBody, IDialogProps };
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
// Constants
|
||||||
import { invalidFormatMsg } from '../constants/messages';
|
import { invalidFormatMsg } from '../constants/messages';
|
||||||
import { TKeyValue, TPropValues, TStateSchema } from '../globals/types';
|
|
||||||
|
// Types
|
||||||
|
import { TKeyValue, TPropValues, TStateSchema, TUser } from '../globals/types';
|
||||||
|
|
||||||
const VALUE = 'value';
|
const VALUE = 'value';
|
||||||
const ERROR = 'error';
|
const ERROR = 'error';
|
||||||
@@ -44,10 +47,19 @@ const addValidator = ({ validatorFunc, prop, required = true }: TValidator) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getValueUser = (user: TUser | null = null, prop: string): string => {
|
||||||
|
if (user) {
|
||||||
|
return user[prop as keyof TUser];
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
isObject,
|
isObject,
|
||||||
isRequired,
|
isRequired,
|
||||||
getPropValues,
|
getPropValues,
|
||||||
|
getValueUser,
|
||||||
addValidator,
|
addValidator,
|
||||||
VALUE,
|
VALUE,
|
||||||
ERROR,
|
ERROR,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ const useForm = (
|
|||||||
stateSchema = {},
|
stateSchema = {},
|
||||||
stateValidatorSchema = {} as TValidator,
|
stateValidatorSchema = {} as TValidator,
|
||||||
submitFormCallback: (values: TKeyValue) => void,
|
submitFormCallback: (values: TKeyValue) => void,
|
||||||
|
initialValue: string = '',
|
||||||
) => {
|
) => {
|
||||||
const [values, setValues] = useState(getPropValues(stateSchema, VALUE));
|
const [values, setValues] = useState(getPropValues(stateSchema, VALUE));
|
||||||
const [errors, setErrors] = useState(getPropValues(stateSchema, ERROR));
|
const [errors, setErrors] = useState(getPropValues(stateSchema, ERROR));
|
||||||
@@ -33,8 +34,17 @@ const useForm = (
|
|||||||
|
|
||||||
// Get a local copy of stateSchema
|
// Get a local copy of stateSchema
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setInitialErrorState();
|
setInitialErrorState(initialValue);
|
||||||
}, []); // eslint-disable-line
|
setDisable(true);
|
||||||
|
|
||||||
|
// If initial value true, setValues again from stateSchema
|
||||||
|
// and enabled button
|
||||||
|
if (initialValue) {
|
||||||
|
setValues({});
|
||||||
|
setValues(getPropValues(stateSchema, VALUE));
|
||||||
|
setDisable(false);
|
||||||
|
}
|
||||||
|
}, [initialValue]); // eslint-disable-line
|
||||||
|
|
||||||
// Validate fields in forms
|
// Validate fields in forms
|
||||||
const validateFormFields = useCallback(
|
const validateFormFields = useCallback(
|
||||||
@@ -47,15 +57,19 @@ const useForm = (
|
|||||||
const field = validator[name];
|
const field = validator[name];
|
||||||
|
|
||||||
let error = '';
|
let error = '';
|
||||||
error = isRequired(value, field!.required);
|
|
||||||
|
|
||||||
if (isObject(field['validator']) && error === '') {
|
// Skip check id field
|
||||||
const fieldValidator = field['validator'];
|
if (name !== 'id') {
|
||||||
|
error = isRequired(value, field!.required);
|
||||||
|
|
||||||
// Test the function callback if the value is meet the criteria
|
if (isObject(field['validator']) && error === '') {
|
||||||
const testFunc = fieldValidator!['func'];
|
const fieldValidator = field['validator'];
|
||||||
if (!testFunc!(value)) {
|
|
||||||
error = fieldValidator!['error']!;
|
// Test the function callback if the value is meet the criteria
|
||||||
|
const testFunc = fieldValidator!['func'];
|
||||||
|
if (!testFunc!(value)) {
|
||||||
|
error = fieldValidator!['error']!;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,14 +80,19 @@ const useForm = (
|
|||||||
|
|
||||||
// Set Initial Error State
|
// Set Initial Error State
|
||||||
// When hooks was first rendered...
|
// When hooks was first rendered...
|
||||||
const setInitialErrorState = useCallback(() => {
|
const setInitialErrorState = useCallback(
|
||||||
Object.keys(errors).map((name) =>
|
(initialValue: string) => {
|
||||||
setErrors((prevState) => ({
|
Object.keys(errors).map((name) =>
|
||||||
...prevState,
|
setErrors((prevState) => ({
|
||||||
[name]: validateFormFields(name, values[name] as string),
|
...prevState,
|
||||||
})),
|
[name]: !initialValue // Skip error when initialValue have values
|
||||||
);
|
? validateFormFields(name, values[name] as string)
|
||||||
}, [errors, values, validateFormFields]);
|
: '',
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[errors, values, validateFormFields],
|
||||||
|
);
|
||||||
|
|
||||||
// Used to disable submit button if there's a value in errors
|
// Used to disable submit button if there's a value in errors
|
||||||
// or the required field in state has no value.
|
// or the required field in state has no value.
|
||||||
@@ -116,6 +135,7 @@ const useForm = (
|
|||||||
// Making sure that there's no error in the state
|
// Making sure that there's no error in the state
|
||||||
// before calling the submit callback function
|
// before calling the submit callback function
|
||||||
// and disabled button
|
// and disabled button
|
||||||
|
|
||||||
if (!validateErrorState()) {
|
if (!validateErrorState()) {
|
||||||
submitFormCallback(values);
|
submitFormCallback(values);
|
||||||
setDisable(true);
|
setDisable(true);
|
||||||
|
|||||||
@@ -11,7 +11,14 @@ const UserDialog = forwardRef((props, ref) => {
|
|||||||
const dialogRef = ref as React.MutableRefObject<
|
const dialogRef = ref as React.MutableRefObject<
|
||||||
HTMLDialogElement | undefined
|
HTMLDialogElement | undefined
|
||||||
>;
|
>;
|
||||||
const { onClose, setReload, reload } = props;
|
// prettier-ignore
|
||||||
|
const {
|
||||||
|
onClose,
|
||||||
|
setReload,
|
||||||
|
reload,
|
||||||
|
user,
|
||||||
|
isAdd
|
||||||
|
} = props;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dialogRef.current) {
|
if (dialogRef.current) {
|
||||||
@@ -31,7 +38,13 @@ const UserDialog = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog title={'Add user'} onClose={onClose} ref={dialogRef}>
|
<Dialog title={'Add user'} onClose={onClose} ref={dialogRef}>
|
||||||
<UserForm onClose={onClose!} reload={reload!} setReload={setReload!} />
|
<UserForm
|
||||||
|
onClose={onClose!}
|
||||||
|
reload={reload!}
|
||||||
|
setReload={setReload!}
|
||||||
|
user={user}
|
||||||
|
isAdd={isAdd!}
|
||||||
|
/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}) as React.FC<IDialogProps>;
|
}) as React.FC<IDialogProps>;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
@@ -14,8 +14,8 @@ import Button from '../../commons/styles/Button.ts';
|
|||||||
// Types
|
// Types
|
||||||
import {
|
import {
|
||||||
TKeyValue,
|
TKeyValue,
|
||||||
TResponse,
|
|
||||||
TStateSchema,
|
TStateSchema,
|
||||||
|
TUser,
|
||||||
TValidator,
|
TValidator,
|
||||||
} from '../../globals/types';
|
} from '../../globals/types';
|
||||||
|
|
||||||
@@ -29,12 +29,17 @@ import {
|
|||||||
isValidPhoneNumber,
|
isValidPhoneNumber,
|
||||||
isValidString,
|
isValidString,
|
||||||
} from '../../helpers/validators';
|
} from '../../helpers/validators';
|
||||||
import { addValidator } from '../../helpers/utils.ts';
|
import { addValidator, getValueUser } from '../../helpers/utils.ts';
|
||||||
import { sendRequest } from '../../helpers/sendRequest.ts';
|
import { sendRequest } from '../../helpers/sendRequest.ts';
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
import { STATUS_CODE } from '../../constants/statusCode.ts';
|
import { STATUS_CODE } from '../../constants/statusCode.ts';
|
||||||
import { ADD_SUCCESS, errorMsg } from '../../constants/messages.ts';
|
import {
|
||||||
|
ADD_SUCCESS,
|
||||||
|
EDIT_SUCCESS,
|
||||||
|
errorMsg,
|
||||||
|
} from '../../constants/messages.ts';
|
||||||
|
import { USER_PATH } from '../../constants/path.ts';
|
||||||
|
|
||||||
const FormBtn = styled(Button)`
|
const FormBtn = styled(Button)`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -49,18 +54,32 @@ interface IUserFormProp {
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
reload: boolean;
|
reload: boolean;
|
||||||
setReload: React.Dispatch<React.SetStateAction<boolean>>;
|
setReload: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
|
user?: TUser | null;
|
||||||
|
isAdd: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
|
const UserForm = ({
|
||||||
|
onClose,
|
||||||
|
reload,
|
||||||
|
setReload,
|
||||||
|
user,
|
||||||
|
isAdd,
|
||||||
|
}: IUserFormProp) => {
|
||||||
const [reset, setReset] = useState(true);
|
const [reset, setReset] = useState(true);
|
||||||
|
// prettier-ignore
|
||||||
|
const initialValue: string = isAdd
|
||||||
|
? ''
|
||||||
|
: user!
|
||||||
|
&& user.id;
|
||||||
|
|
||||||
// Define your state schema
|
// Define your state schema
|
||||||
const stateSchema: TStateSchema = {
|
const stateSchema: TStateSchema = {
|
||||||
name: { value: '', error: '' },
|
id: { value: getValueUser(user, 'id') },
|
||||||
identifiedCode: { value: '', error: '' },
|
name: { value: getValueUser(user, 'name'), error: '' },
|
||||||
phone: { value: '', error: '' },
|
identifiedCode: { value: getValueUser(user, 'identifiedCode'), error: '' },
|
||||||
roomId: { value: '', error: '' },
|
phone: { value: getValueUser(user, 'phone'), error: '' },
|
||||||
address: { value: '', error: '' },
|
roomId: { value: getValueUser(user, 'roomId'), error: '' },
|
||||||
|
address: { value: getValueUser(user, 'address'), error: '' },
|
||||||
};
|
};
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@@ -90,31 +109,51 @@ const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
|
|||||||
// Submit form
|
// Submit form
|
||||||
const onSubmitForm = async (state: TKeyValue) => {
|
const onSubmitForm = async (state: TKeyValue) => {
|
||||||
try {
|
try {
|
||||||
const response = await sendRequest(
|
if (isAdd) {
|
||||||
'users',
|
// Add request
|
||||||
JSON.stringify(state),
|
const response = await sendRequest(
|
||||||
'POST',
|
USER_PATH,
|
||||||
);
|
JSON.stringify(state),
|
||||||
|
'POST',
|
||||||
|
);
|
||||||
|
|
||||||
if (response.statusCode === STATUS_CODE.CREATE) {
|
if (response.statusCode === STATUS_CODE.CREATE) {
|
||||||
toast.success(ADD_SUCCESS);
|
toast.success(ADD_SUCCESS);
|
||||||
|
} else {
|
||||||
// Reload table data
|
throw new Error(errorMsg(response.statusCode, response.msg));
|
||||||
setReload(!reload);
|
}
|
||||||
} else {
|
} else {
|
||||||
toast.error(errorMsg(response.statusCode, response.msg));
|
// Edit request
|
||||||
}
|
const response = await sendRequest(
|
||||||
|
USER_PATH + `/${user!.id}`,
|
||||||
|
JSON.stringify(state),
|
||||||
|
'PUT',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == STATUS_CODE.OK) {
|
||||||
|
toast.success(EDIT_SUCCESS);
|
||||||
|
} else {
|
||||||
|
throw new Error(errorMsg(response.statusCode, response.msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Reload table data
|
||||||
|
setReload(!reload);
|
||||||
onResetForm();
|
onResetForm();
|
||||||
} catch (error) {
|
} catch (error: unknown) {
|
||||||
toast.error(
|
if (error instanceof Error) {
|
||||||
errorMsg((error as TResponse).statusCode, (error as TResponse).msg),
|
toast.error(error.message);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Close and reset form
|
||||||
|
const closeAndReset = () => {
|
||||||
|
onClose();
|
||||||
|
onResetForm();
|
||||||
|
};
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const {
|
const {
|
||||||
values,
|
values,
|
||||||
@@ -127,10 +166,12 @@ const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
|
|||||||
stateSchema,
|
stateSchema,
|
||||||
stateValidatorSchema,
|
stateValidatorSchema,
|
||||||
onSubmitForm,
|
onSubmitForm,
|
||||||
|
initialValue
|
||||||
);
|
);
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const {
|
const {
|
||||||
|
id,
|
||||||
name,
|
name,
|
||||||
identifiedCode,
|
identifiedCode,
|
||||||
phone,
|
phone,
|
||||||
@@ -138,6 +179,12 @@ const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
|
|||||||
address
|
address
|
||||||
} = values;
|
} = values;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isAdd) {
|
||||||
|
Object.keys(values).forEach((key) => (values[key] = ''));
|
||||||
|
}
|
||||||
|
}, [isAdd]); // eslint-disable-line
|
||||||
|
|
||||||
// Reset form
|
// Reset form
|
||||||
const onResetForm = () => {
|
const onResetForm = () => {
|
||||||
setReset(!reset);
|
setReset(!reset);
|
||||||
@@ -146,7 +193,7 @@ const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Form onSubmit={handleOnSubmit}>
|
<Form onSubmit={handleOnSubmit}>
|
||||||
<Input type="hidden" id="id" />
|
<Input type="hidden" name="id" value={id as string} />
|
||||||
<FormRow
|
<FormRow
|
||||||
label="Full Name"
|
label="Full Name"
|
||||||
error={
|
error={
|
||||||
@@ -235,7 +282,7 @@ const UserForm = ({ onClose, reload, setReload }: IUserFormProp) => {
|
|||||||
<FormBtn type="submit" name="submit" disabled={disable}>
|
<FormBtn type="submit" name="submit" disabled={disable}>
|
||||||
Add
|
Add
|
||||||
</FormBtn>
|
</FormBtn>
|
||||||
<FormBtn type="button" styled="secondary" onClick={onClose}>
|
<FormBtn type="button" styled="secondary" onClick={closeAndReset}>
|
||||||
Close
|
Close
|
||||||
</FormBtn>
|
</FormBtn>
|
||||||
</Form.Action>
|
</Form.Action>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { HiSquare2Stack } from 'react-icons/hi2';
|
import { HiSquare2Stack } from 'react-icons/hi2';
|
||||||
@@ -14,15 +15,51 @@ import { TUser } from '../../globals/types';
|
|||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
import { useFetch } from '../../hooks/useFetch';
|
import { useFetch } from '../../hooks/useFetch';
|
||||||
|
import { USER_PATH } from '../../constants/path';
|
||||||
|
import { STATUS_CODE } from '../../constants/statusCode';
|
||||||
|
import { CONFIRM_DELETE, DELETE_SUCCESS } from '../../constants/messages';
|
||||||
|
|
||||||
// Styled
|
// Styled
|
||||||
import Spinner from '../../commons/styles/Spinner';
|
import Spinner from '../../commons/styles/Spinner';
|
||||||
|
|
||||||
type TUserModal = { user: TUser };
|
// Utils
|
||||||
|
import { sendRequest } from '../../helpers/sendRequest';
|
||||||
|
|
||||||
const UserRow = ({ user }: TUserModal) => {
|
interface IUserRow {
|
||||||
const handleOnClick = (id: string) => {
|
user: TUser;
|
||||||
alert(`Id: ${id}`);
|
openFormDialog: () => void;
|
||||||
|
setUser: React.Dispatch<React.SetStateAction<TUser | null>>;
|
||||||
|
reload: boolean;
|
||||||
|
setReload: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserRow = ({
|
||||||
|
user,
|
||||||
|
openFormDialog,
|
||||||
|
setUser,
|
||||||
|
reload,
|
||||||
|
setReload,
|
||||||
|
}: IUserRow) => {
|
||||||
|
const handleOnEdit = (user: TUser) => {
|
||||||
|
setUser(user);
|
||||||
|
openFormDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnDelete = async (user: TUser) => {
|
||||||
|
if (confirm(CONFIRM_DELETE)) {
|
||||||
|
const response = await sendRequest(
|
||||||
|
USER_PATH + `/${user.id}`,
|
||||||
|
null,
|
||||||
|
'DELETE',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode === STATUS_CODE.OK) {
|
||||||
|
toast.success(DELETE_SUCCESS);
|
||||||
|
|
||||||
|
// Reload table
|
||||||
|
setReload(!reload);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const { id, name, identifiedCode, phone, roomId } = user;
|
const { id, name, identifiedCode, phone, roomId } = user;
|
||||||
@@ -41,11 +78,11 @@ const UserRow = ({ user }: TUserModal) => {
|
|||||||
<Menus.List id={id}>
|
<Menus.List id={id}>
|
||||||
<Menus.Button
|
<Menus.Button
|
||||||
icon={<HiSquare2Stack />}
|
icon={<HiSquare2Stack />}
|
||||||
onClick={() => handleOnClick(id)}
|
onClick={() => handleOnEdit(user)}
|
||||||
>
|
>
|
||||||
Edit
|
Edit
|
||||||
</Menus.Button>
|
</Menus.Button>
|
||||||
<Menus.Button icon={<HiTrash />} onClick={() => handleOnClick(id)}>
|
<Menus.Button icon={<HiTrash />} onClick={() => handleOnDelete(user)}>
|
||||||
Delete
|
Delete
|
||||||
</Menus.Button>
|
</Menus.Button>
|
||||||
</Menus.List>
|
</Menus.List>
|
||||||
@@ -56,9 +93,17 @@ const UserRow = ({ user }: TUserModal) => {
|
|||||||
|
|
||||||
interface IUserTable {
|
interface IUserTable {
|
||||||
reload: boolean;
|
reload: boolean;
|
||||||
|
setReload: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
|
openFormDialog: () => void;
|
||||||
|
setUser?: React.Dispatch<React.SetStateAction<TUser | null>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserTable = ({ reload }: IUserTable) => {
|
const UserTable = ({
|
||||||
|
reload,
|
||||||
|
setReload,
|
||||||
|
openFormDialog,
|
||||||
|
setUser,
|
||||||
|
}: IUserTable) => {
|
||||||
const { data, isPending, errorMsg } = useFetch('users', reload);
|
const { data, isPending, errorMsg } = useFetch('users', reload);
|
||||||
const [users, setUsers] = useState<TUser[]>([]);
|
const [users, setUsers] = useState<TUser[]>([]);
|
||||||
|
|
||||||
@@ -94,7 +139,16 @@ const UserTable = ({ reload }: IUserTable) => {
|
|||||||
</Table.Header>
|
</Table.Header>
|
||||||
<Table.Body<TUser>
|
<Table.Body<TUser>
|
||||||
data={users}
|
data={users}
|
||||||
render={(user: TUser) => <UserRow user={user} key={user.id} />}
|
render={(user: TUser) => (
|
||||||
|
<UserRow
|
||||||
|
user={user}
|
||||||
|
key={user.id}
|
||||||
|
reload={reload}
|
||||||
|
setReload={setReload}
|
||||||
|
openFormDialog={openFormDialog}
|
||||||
|
setUser={setUser!}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</Table>
|
</Table>
|
||||||
</Menus>
|
</Menus>
|
||||||
|
|||||||
@@ -9,15 +9,21 @@ import UserTable from './Table';
|
|||||||
import { StyledUser, Title } from './styled';
|
import { StyledUser, Title } from './styled';
|
||||||
import UserDialog from './Dialog';
|
import UserDialog from './Dialog';
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import { TUser } from '../../globals/types';
|
||||||
|
|
||||||
const User = () => {
|
const User = () => {
|
||||||
const dialogRef = useRef<HTMLDialogElement>();
|
const dialogRef = useRef<HTMLDialogElement>();
|
||||||
const [reload, setReload] = useState(true);
|
const [reload, setReload] = useState(true);
|
||||||
|
const [user, setUser] = useState<TUser | null>(null);
|
||||||
|
const [isAdd, setIsAdd] = useState(false);
|
||||||
|
|
||||||
const openDialog = () => {
|
const openFormDialog = (isAddForm: boolean = false) => {
|
||||||
|
setIsAdd(isAddForm);
|
||||||
dialogRef.current?.showModal();
|
dialogRef.current?.showModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeDialog = () => {
|
const closeFormDialog = () => {
|
||||||
dialogRef.current?.close();
|
dialogRef.current?.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -26,17 +32,24 @@ const User = () => {
|
|||||||
<StyledUser>
|
<StyledUser>
|
||||||
<Direction type="horizontal">
|
<Direction type="horizontal">
|
||||||
<Title>List User</Title>
|
<Title>List User</Title>
|
||||||
<Button onClick={openDialog}>Add user</Button>
|
<Button onClick={() => openFormDialog(true)}>Add user</Button>
|
||||||
</Direction>
|
</Direction>
|
||||||
|
|
||||||
<UserTable reload={reload} />
|
<UserTable
|
||||||
|
reload={reload}
|
||||||
|
setReload={setReload}
|
||||||
|
openFormDialog={() => openFormDialog()}
|
||||||
|
setUser={setUser}
|
||||||
|
/>
|
||||||
</StyledUser>
|
</StyledUser>
|
||||||
|
|
||||||
<UserDialog
|
<UserDialog
|
||||||
onClose={closeDialog}
|
onClose={closeFormDialog}
|
||||||
ref={dialogRef}
|
ref={dialogRef}
|
||||||
setReload={setReload}
|
setReload={setReload}
|
||||||
reload={reload}
|
reload={reload}
|
||||||
|
user={user}
|
||||||
|
isAdd={isAdd}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user