[MySchedule project] 11. 관리자 - 사용자관리 로직 mui x-data-grid와 mui modal 사용
관리자용 페이지중에서 사용자 데이터를 관리하는 페이지를 만들려고 한다.
먼저 db에 저장되있는 사용자 데이터들을 조회해 오고, 조회해온 데이터를 수정, 삭제하는 기능과 사용자를 등록하는 기능까지 구현할 것이다.
사용 라이브러리는 mui/x-data grid 를 사용해서 테이블을 구현했고, row를 클릭할 경우 modal 이 뜨게 할 것이다.
modal 라이브러리는 mui/material의 modal을 사용했다.
Frontend
- 구현에 들어가기 앞서, 필요한 라이브러리( mui )를 먼저 다운로드 받아준다.
https://mui.com/material-ui/getting-started/installation/
Installation - Material UI
Install Material UI, the world's most popular React UI framework.
mui.com
- 설치
npm install @mui/x-data-grid
npm install @mui/material @emotion/react @emotion/styled
- import
import {
DataGrid,
GridColDef,
GridRowSelectionModel,
GridRowsProp,
} from "@mui/x-data-grid";
[ src / types / userManagement.ts ]
- 타입 지정
export interface userManagementInput {
textUserId: string;
textUserName: string;
}
export interface userData {
userId: string;
userEmail: string;
userName: string;
userPhone: string;
userImage: string;
//userPassword: string;
role: number;
}
export interface modalInsertData extends userData {
userPassword: string;
userPasswordCheck: string;
}
[ pages / UserManagement / index.tsx ]
1. 조회
- db에 있는 사용자데이터들을 가져와서 mui grid 양식에 맞게 넣어서 출력하였다.
- 관리자로부터 입력받는 input은 이름과 아이디에 따라 db에서 다르게 조회 할 수 있도록 하였음.
2. 수정
- 관리자가 특정 row 클릭시에 해당되는 사용자 데이터를 가져올수 있게 하였고, row 클릭시에는 모달창에 뜨도록 구현함.
- 업데이트의 modal은 한 사용자의 데이터만 들어가므로, 따로 state로 상태를 관리해 ModalUpdatePage.tsx 컴포넌트로 해당 사용자의 데이터를 props로 보내주었음.
- ModalUpdatePage.tsx 에서 props로 받은 데이터는 화면에 출력되고, 관리자가 id(pk)를 제외한 나머지 요소들을 수정할수 있게 하였음.
3. 추가
- 추가버튼 클릭 이벤트시에 ModalInsertPage.tsx컴포넌트의 modal이 open 됨.
- 새로운 사용자 데이터를 등록하는 것이므로, validation check(유효성검사) 부분을 작성해야되고, id중복확인 부분도 작성해야됨.
- validation check가 정상적으로 통과되었다면 db에 사용자를 추가할수 있게 구현하였음.
- 리덕스의 stroe부분은 회원가입 이후의 로그인 로직부터 토큰 생성후 사용자 데이터를 가져오므로, dispatch를 통해 따로 하진 않고, 이번에는 바로 axios를 사용함.
4. 삭제
- mui grid에서 제공해주는 checkbox 클릭시에 사용자 데이터를 가져올수 있는 기능인 rowSelectionModal을 이용해서 사용자 데이터를 파라미터에 담아 백앤드에 보낼수 있음.
- rowSelectionModal 타입이 배열이므로, 여러개의 체크가 된 상태에서도 삭제가 가능하도록 구현함.
import React, { ChangeEvent, useEffect, useState } from "react";
import {
DataGrid,
GridColDef,
GridRowSelectionModel,
GridRowsProp,
} from "@mui/x-data-grid";
import axiosInstance from "../../utils/axios";
import {
modalData,
responseUserData,
userManagementType,
} from "../../types/userManagementType";
import { toast } from "react-toastify";
import ModalUpdatePage from "./ModalUpdatePage";
import ModalInsertPage from "./ModalInsertPage";
const UserManagement = () => {
const [textUserData, setTextUserdata] = useState<userManagementType>({
textUserId: "",
textUserName: "",
});
const [response, setResponse] = useState<responseUserData[]>([]); //백앤드에서 조회해온 데이터
const [modalData, setModalData] = useState<modalData>(); //모달에 넣을 데이터
const [modalInsertYn, setModalInsertYn] = useState<boolean>(false);
const [open, setOpen] = React.useState(false);
const [insertOpen, setInsertOpen] = React.useState(false);
const handleUpdateOpen = () => setOpen(true);
const handleInsertOpen = () => setInsertOpen(true);
//화면 랜더링시 데이터조회 함수 호출
useEffect(() => {
handleSelectUserData();
}, []);
//input onChange 함수
const handleChangeInput = (e: ChangeEvent<HTMLInputElement>) => {
e.preventDefault();
const { name, value } = e.target;
setTextUserdata((prevState) => ({
...prevState,
[name]: value,
}));
};
//데이터 조회
const handleSelectUserData = async () => {
const body = {
...textUserData,
};
try {
const response = await axiosInstance.post(`/userManagement`, body);
setResponse(response.data);
} catch (error: any) {
console.log(error);
}
};
// console.log(response);
// 데이터 맵핑 start
// data 배열에 데이터 갯수만큼 push 해야 함
let rows: GridRowsProp = [];
rows = response.map((data) => {
//console.log(data);
return {
id: data.userId,
userId: data.userId,
userName: data.userName,
userEmail: data.userEmail,
userPhone: data.userPhone,
userImage: data.userImage,
};
});
const columns: GridColDef[] = [
{ field: "userId", headerName: "아이디", width: 150 },
{ field: "userName", headerName: "이름", width: 150 },
{ field: "userEmail", headerName: "이메일", width: 150 },
{ field: "userPhone", headerName: "폰번호", width: 150 },
{ field: "userImage", headerName: "이미지파일이름", width: 600 },
];
// 데이터 맵핑 end
//데이터 삭제 start
const [rowSelectionModel, setRowSelectionModel] =
useState<GridRowSelectionModel>([]); // checkbox 선택 후 데이터삭제
//console.log(rowSelectionModel);
const deleteUserData = async (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
e.preventDefault();
if (rowSelectionModel === null || rowSelectionModel.length <= 0) {
toast.info("삭제할 데이터를 체크해주세요.");
return;
}
const body = {
...rowSelectionModel,
};
// eslint-disable-next-line no-restricted-globals
const dataDeleteYn = confirm("데이터를 삭제하시겠습니까?");
if (dataDeleteYn === true) {
try {
const response = await axiosInstance.post(
`/userManagement/userDataDelete`,
body
);
console.log(response);
if (response.data.deleteSuccess === true) {
toast.success("사용자 데이터가 삭제되었습니다.");
handleSelectUserData(); //데이터 재조회
}
} catch (error: any) {
console.log(error);
}
}
};
//데이터삭제 end
//데이터 추가 start
const insertUserData = () => {
setModalInsertYn(true);
handleInsertOpen();
};
//데이터 추가 end
//더블클릭 이밴트시 팝업창 openn / 한 행의 데이터 불러오는 함수
const getSelectedRows = (object: any) => {
// console.log(object);
// console.log(object.row);
// console.log(response);
response.map((item, idx) => {
if (item.userId === object.row.id) {
// 그리드에 선택한 1개의 row를 찾아낼 수 있다.
console.log(item);
// 조건에 맞는 한행의 데이터만 저장
setModalData(item);
// 모달 open
handleUpdateOpen();
}
});
};
return (
<section>
<div className="m-auto p-4 my-6 ">
<div className="w-full">
<div className="sm:text-right my-4">
<input
className="placeholder:text-sm text-md my-2 mx-2 sm:w-2/12 w-11/12 rounded-md border-[1px] border-gray-200 border-t-[3px] h-[45px] p-3 hover:border-t-[3px] hover:border-t-gray-400 focus:focus:outline-none"
type="text"
placeholder="아이디를 입력해주세요."
id="textUserId"
name="textUserId"
onChange={handleChangeInput}
value={textUserData.textUserId}
/>{" "}
<input
className="placeholder:text-sm my-2 mx-2 sm:w-2/12 w-11/12 rounded-md text-md border-[1px] border-gray-200 border-t-[3px] h-[45px] p-3 hover:border-t-[3px] hover:border-t-gray-400 focus:focus:outline-none"
type="text"
placeholder="성함을 입력해주세요."
id="textUserName"
name="textUserName"
onChange={handleChangeInput}
value={textUserData.textUserName}
/>{" "}
<button
onClick={handleSelectUserData}
className="sm:w-2/12 w-3/12 bg-blue-500 h-[45px] mx-2 my-2 text-white sm:font-bold font-semibold sm:text-sm text-[12px] py-2 px-2 rounded-md hover:bg-blue-600"
>
조회
</button>
<button
onClick={insertUserData}
className="sm:w-2/12 w-3/12 bg-blue-500 h-[45px] mx-2 text-white sm:font-bold font-semibold sm:text-sm text-[12px] py-2 px-2 rounded-md hover:bg-blue-600"
>
추가
</button>
<button
onClick={deleteUserData}
className="sm:w-2/12 w-3/12 bg-blue-500 h-[45px] mx-2 text-white sm:font-bold font-semibold sm:text-sm text-[12px] py-2 px-2 rounded-md hover:bg-blue-600"
>
삭제
</button>
</div>
<p className="text-sm my-3">
- 한 행을 클릭 시 데이터를 수정 할 수 있습니다.
</p>
</div>
<div>
{" "}
{/* grid 사용 */}
<DataGrid
rows={rows}
columns={columns}
onRowClick={getSelectedRows}
checkboxSelection
//onRowDoubleClick={getSelectedRows}
onRowSelectionModelChange={(newRowSelectionModel) => {
setRowSelectionModel(newRowSelectionModel);
}}
rowSelectionModel={rowSelectionModel}
/>
{/* modal update 호출 */}
{modalData && (
<ModalUpdatePage
open={open}
setOpen={setOpen}
modalData={modalData}
handleSelectUserData={handleSelectUserData}
/>
)}
{/* modal insert 호출 */}
{modalInsertYn && (
<ModalInsertPage
insertOpen={insertOpen}
setInsertOpen={setInsertOpen}
handleSelectUserData={handleSelectUserData}
/>
)}
</div>
</div>
</section>
);
};
export default UserManagement;
[ pages / UserManagement / ModalUpdatePage.tsx ]
- modalData 는 관리자가 gird에서 한 행을 클릭시에 ModalUpdatePage.tsx컴포넌트의 props로 보내는 state값으로, 클릭된 한명의 사용자 데이터가 들어있다.
- useEffect를 사용해서 modalData의 값들이 바뀔 때마다(관리자가 다른 행을 클릭한 경우) myData로 새로운 값들이 들어오게 하였음.
- 들어온 값들은 modal 라이브러리를 통해 화면에 출력되게 하였고, 관리자는 출력된 데이터들을 수정할 수 있게 구현함.
import React, { ChangeEvent, useEffect, useState } from "react";
import { Backdrop, Box, Fade, Modal, Typography } from "@mui/material";
import { style } from "./ModalStyle";
import { modalData } from "../../types/userManagementType";
import axiosInstance from "../../utils/axios";
import { toast } from "react-toastify";
interface ownProps {
open: boolean;
setOpen: any;
modalData: modalData;
handleSelectUserData(): void;
}
const ModalUpdatePage = ({
modalData,
open,
setOpen,
handleSelectUserData,
}: ownProps) => {
console.log("111111");
console.log(modalData); //정상작동
const [myData, setMyData] = useState<modalData>({
userId: "",
userName: "",
role: 0,
userEmail: "",
userPhone: "",
userImage: "",
});
useEffect(() => {
setMyData({
userId: modalData.userId,
userName: modalData.userName,
role: modalData.role,
userEmail: modalData.userEmail,
userPhone: modalData.userPhone,
userImage: modalData.userImage,
});
}, [modalData]);
console.log(myData);
// const [open, setOpen] = React.useState(false);
// const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
//공통 onChange함수
const handleChange = (
e: ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLSelectElement>
) => {
console.log("run....>");
e.preventDefault();
console.log(e.target);
const { name, value } = e.target;
setMyData((prevState: modalData) => ({
...prevState,
[name]: value,
}));
};
//데이터 업데이트
const handleUpdate = async (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
e.preventDefault();
const body = {
...myData,
};
try {
const response = await axiosInstance.post(
`/userManagement/userDataUpdate`,
body
);
if (response.data.updateSuccess === true) {
toast.success("사용자 데이터가 정상적으로 수정되었습니다.");
handleClose();
handleSelectUserData(); //데이터 재조회
}
} catch (error) {
console.log(error);
}
};
return (
<div>
{/* <Button onClick={handleOpen}>Open modal</Button> */}
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
open={open}
onClose={handleClose}
closeAfterTransition
slots={{ backdrop: Backdrop }}
slotProps={{
backdrop: {
timeout: 500,
},
}}
>
<Fade in={open}>
<Box sx={style} className="rounded-md border-[1px] border-gray-300 ">
<button onClick={handleClose} className="float-right text-md ">
X
</button>
<Typography
id="transition-modal-title"
variant="h6"
component="h2"
className="text-center"
>
사용자관리
</Typography>
<div className="w-full my-3">
<div>
<label className="text-left">아이디</label>
</div>
<div>
<input
className="w-full border-b-[1px] h-9 bg-gray-200 border-gray-300 outline-none "
type="text"
onChange={handleChange}
value={myData.userId}
name="userId"
readOnly
/>
</div>
</div>
<div className="w-full my-3">
<div>
<label className="text-left">이름</label>
</div>
<div>
<input
className="w-full border-b-[1px] h-9 border-gray-300 outline-none "
type="text"
onChange={handleChange}
value={myData.userName}
name="userName"
/>
</div>
</div>
<div className="w-full my-3">
<div>
<label className="text-left">폰번호</label>
</div>
<div>
<input
className="w-full border-b-[1px] h-9 border-gray-300 outline-none "
type="text"
onChange={handleChange}
value={myData.userPhone}
name="userPhone"
/>
</div>
</div>
<div className="w-full my-3">
<div>
<label className="text-left">이메일</label>
</div>
<div>
<input
className="w-full border-b-[1px] h-9 border-gray-300 outline-none "
type="text"
onChange={handleChange}
value={myData.userEmail}
name="userEmail"
/>
</div>
</div>
<div className="w-full my-3">
<div>
<label className="text-left">권한 설정</label>
</div>
<div>
<select
className="border-[1px] border-gray-300 rounded-md w-full h-7 my-2"
value={myData.role}
name="role"
onChange={handleChange}
>
<option value="1">관리자</option>
<option value="0">사용자</option>
</select>
</div>
</div>
<div className="w-full my-3">
<div>
<button
onClick={handleUpdate}
className="bg-blue-600 w-full text-gray-50 rounded-md h-10 hover:bg-blue-700"
>
UPDATE
</button>
</div>
</div>
</Box>
</Fade>
</Modal>
</div>
);
};
export default ModalUpdatePage;
[ pages / UserManagement / ModalInsertPage.tsx ]
- 사용자추가 버튼 클릭했을때 해당되는 컴포넌트로 이부분 역시 modal이 뜨게 하였다.
- 회원가입 로직과 비슷해서 useForm을 사용했고, 추가적으로 mui/material에서 제공해주는 modal라이브러리를 사용했다.
import React, { ChangeEvent, useEffect, useRef, useState } from "react";
import { Backdrop, Box, Fade, Modal, Typography } from "@mui/material";
import { style } from "./ModalStyle";
import { modalInsertData } from "../../types/userManagementType";
import axiosInstance from "../../utils/axios";
import { toast } from "react-toastify";
import { useForm } from "react-hook-form";
interface ownProps {
insertOpen: boolean;
setInsertOpen: any;
handleSelectUserData(): void;
}
const ModalInsertPage = ({
insertOpen,
setInsertOpen,
handleSelectUserData,
}: ownProps) => {
const {
register, //등록함수
handleSubmit,
formState: { errors },
reset,
watch,
} = useForm<modalInsertData>({ mode: "onChange" });
// const [open, setOpen] = React.useState(false);
// const handleOpen = () => setOpen(true);
const handleClose = () => setInsertOpen(false);
const [userEmail, setUserEmail] = useState("");
const [emailList, setEmailList] = useState<string[]>([]);
const [idcheck, setIdCheck] = useState(false);
const domainEmails = [
"@naver.com",
"@gmail.com",
"@daum.net",
"@nate.com",
"@kakao.com",
];
const emailForm =
/^(([^<>()\[\].,;:\s@"]+(\.[^<>()\[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;
//이메일 자동완성 함수
const emailHandleChange = (e: ChangeEvent<HTMLInputElement>) => {
e.preventDefault();
const userEmails = domainEmails.map((email) =>
e.target.value.includes("@")
? e.target.value.split("@")[0] + email
: e.target.value + email
);
setUserEmail(e.target.value);
setEmailList(userEmails);
};
useEffect(() => {
reset();
setIdCheck(false);
setUserEmail("");
}, [insertOpen, reset]);
// VALIDATION CHECK START
// register등록함수와 함께 사용한다. {...register("userId", userId)}
const userId = {
required: "필수입력 요소입니다.",
minLength: {
value: 3,
message: "최소 3글자 이상으로 입력해 주세요.",
},
};
const userPassword = {
required: "필수입력 요소입니다.",
pattern: {
value:
/^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{11,20}$/,
message: "영문, 숫자, 특수문자 포함 11자 이상 20 자 이하로 입력해 주세요",
},
};
const userName = {
required: "필수입력 요소입니다.",
};
const userPhone = {
required: "필수입력 요소입니다.",
minLength: {
value: 11,
message: "숫자 11자리 이상으로 입력해 주세요.",
},
};
//비밀번호 일치여부 체크 - watch사용해서 input의 userPwd의 값을 가져옴
const passwordRef = useRef<string | null>(null);
passwordRef.current = watch("userPassword");
//VALIDATION CHECK END
//아이디 체크
const handleIdCheck = async (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
e.preventDefault();
let id = watch("userId");
if (id === "" || id === null) {
toast.info("아이디를 입력해주세요.");
return;
}
const body = {
userId: id,
};
try {
const idCheckValue = await axiosInstance.post(
"/userManagement/idCheck",
body
);
console.log(idCheckValue);
if (idCheckValue.data !== "") {
//값이 있으면
toast.info("이미 등록된 아이디 입니다.");
} else {
toast.info("사용가능한 아이디 입니다.");
setIdCheck(true);
}
} catch (error) {
console.error(error);
}
};
//데이터 추가
const onSubmit = async ({
userId,
userPassword,
userName,
userPhone,
}: modalInsertData) => {
const body = {
userId,
userName,
userPhone,
userEmail,
userPassword: userPassword,
userImage: "",
};
if (idcheck) {
try {
await axiosInstance.post(`/userManagement/userDataInsert`, body);
reset();
setIdCheck(false);
setUserEmail("");
toast.success("사용자 데이터가 저장되었습니다.");
handleClose(); //모달 닫기
handleSelectUserData(); //데이터 재조회
} catch (error) {
console.log(error);
}
} else {
toast.info("아이디 중복확인을 먼저 해주세요.");
}
};
return (
<div>
{/* <Button onClick={handleOpen}>Open modal</Button> */}
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
open={insertOpen}
onClose={handleClose}
closeAfterTransition
slots={{ backdrop: Backdrop }}
slotProps={{
backdrop: {
timeout: 500,
},
}}
>
<Fade in={insertOpen}>
<Box sx={style} className="rounded-md border-[1px] border-gray-300 ">
<button onClick={handleClose} className="float-right text-md ">
X
</button>
<Typography
id="transition-modal-title"
variant="h6"
component="h2"
className="text-center"
>
사용자 추가
</Typography>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="w-full my-3">
<div>
<label className="text-left">아이디</label>
</div>
<div>
<input
className="w-8/12 mr-3 border-b-[1px] h-9 border-gray-300 outline-none "
type="text"
id="userId"
disabled={idcheck}
{...register("userId", userId)}
/>
{idcheck ? (
<button disabled={idcheck}></button>
) : (
<button
onClick={handleIdCheck}
className="float-right sm:w-18 w-3/12 m-auto bg-blue-500 h-[37px] text-white sm:font-bold font-semibold sm:text-sm text-xs px-2 rounded-md hover:bg-blue-600"
>
중복확인
</button>
)}
{errors?.userId && (
<div className="py-1">
<span className="text-red-500 pl-2 text-sm">
{errors.userId.message}
</span>
</div>
)}
</div>
</div>
<div className="w-full my-3">
<div>
<label className="text-left">비밀번호</label>
</div>
<div>
<input
className="w-full border-b-[1px] h-9 border-gray-300 outline-none "
type="password"
id="userPassword"
{...register("userPassword", userPassword)}
/>
{errors?.userPassword && (
<div className="py-1">
<span className="text-red-500 pl-2 text-sm">
{errors.userPassword.message}
</span>
</div>
)}
</div>
</div>
<div className="w-full my-3">
<div>
<label className="text-left">비밀번호 확인</label>
</div>
<div>
<input
className="w-full border-b-[1px] h-9 border-gray-300 outline-none "
type="password"
id="userPasswordCheck"
minLength={11}
{...register("userPasswordCheck", {
required: "필수입력 요소입니다.",
validate: (value) => value === passwordRef.current,
})}
/>
{errors?.userPasswordCheck?.type === "required" && (
<div className="py-1">
<span className="text-red-500 pl-2 text-sm">
{errors.userPasswordCheck.message}
</span>
</div>
)}
{errors?.userPasswordCheck?.type === "validate" && (
<div className="py-1">
<span className="text-red-500 pl-2 text-sm">
비밀번호가 맞지 않습니다. 한번더 확인해 주세요.
</span>
</div>
)}
</div>
</div>
<div className="w-full my-3">
<div>
<label className="text-left">사용자명</label>
</div>
<div>
<input
className="w-full border-b-[1px] h-9 border-gray-300 outline-none "
type="text"
id="userName"
{...register("userName", userName)}
/>
{errors?.userName && (
<div className="py-1">
<span className="text-red-500 pl-2 text-sm">
{errors.userName.message}
</span>
</div>
)}
</div>
</div>
<div className="w-full my-3">
<div>
<label className="text-left">휴대폰번호</label>
</div>
<div>
<input
className="w-full border-b-[1px] h-9 border-gray-300 outline-none "
type="number"
id="userPhone"
{...register("userPhone", userPhone)}
/>
{errors?.userPhone && (
<div className="py-1">
<span className="text-red-500 pl-2 text-sm">
{errors.userPhone.message}
</span>
</div>
)}
</div>
</div>
<div className="w-full my-3">
<div>
<label className="text-left">이메일</label>
</div>
<div>
<input
className="w-full border-b-[1px] h-9 border-gray-300 outline-none "
type="text"
list="email"
value={userEmail}
onChange={emailHandleChange}
/>
<datalist id="email">
{emailList &&
emailList.map((email, idx) => (
<option value={email} key={idx} />
))}
</datalist>
{userEmail && !emailForm.test(userEmail) && (
<p className="p-2 text-red-500 text-sm">
이메일 형식을 확인해주세요.
</p>
)}
</div>
</div>
<div className="w-full my-3">
<div>
<button
type="submit"
className="bg-blue-600 w-full text-gray-50 rounded-md h-10 hover:bg-blue-700"
>
추가
</button>
</div>
</div>
</form>
</Box>
</Fade>
</Modal>
</div>
);
};
export default ModalInsertPage;
[ pages / UserManagement / ModalStyle.tsx ]
export const style = {
position: "absolute" as "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
//border: "2px solid #000",
//boxShadow: 24,
p: 4,
};
Backend
[ src / index.js ]
- rouet 추가
//route start
app.use("/userManagement", require("./routes/userManagement"));
//route end
[ src / routes / userManagement.js ]
1. 조회
- 관리자가 입력한 사용자 아이디와 이름에 해당되는 데이터를 찾는 로직인데, 특정 데이터를 찾기 위해 $regex 를 사용했다.
- $regex는 mysql의 like연산자와 같은 기능으로 만약 이름으로 th를 써서 조회 버튼을 누를경우에 이름이 th가 들어있는 데이터들을 불러온다.
2. 업데이트
- 관리자로부터 수정된 데이터들을 받아와 업데이트하였음.
3. 추가
- id중복확인을 거쳐야됨. id중복확인은 입력받은 데이터가 db에 있는지 확인하는 것으로, db에 데이터가 있으면 중복되는 것이므로 데이터의 추가가 되지 않도록 구현함.
4. 삭제
- 전달받은 데이터가 mui grid에서 제공해주는 checkbox 기능으로 배열로 들어온다.
- 배열의 데이터가 여러개일수 있으므로, for문을 돌려서 req.body의 인덱스번호를 넣어 데이터를 한개씩 삭제하도록 구현했다.
const express = require("express");
const User = require("../models/User");
const router = express.Router();
//사용자관리 조회
router.post("/", async (req, res, next) => {
console.log(req.body);
let textUserId = req.body.textUserId;
let textUserName = req.body.textUserName;
let userData = {};
try {
//$regex -> mysql의 like연산자
userData = await User.find({
userId: { $regex: textUserId },
userName: { $regex: textUserName },
});
console.log(userData);
return res.status(200).send(userData);
} catch (error) {
next(error);
}
});
//사용자 데이터 업데이트
router.post("/userDataUpdate", async (req, res, next) => {
try {
console.log(req.body);
let commonData = {
userName: req.body.userName,
userPhone: req.body.userPhone,
userEmail: req.body.userEmail,
role: req.body.role,
};
console.log(commonData);
const updateUser = await User.findOneAndUpdate(
{ userId: req.body.userId },
commonData,
{ new: true }
);
console.log(updateUser);
return res.json({
updateSuccess: true,
});
} catch (error) {
next(error);
}
});
//사용자 데이터 추가 - id중복확인
router.post("/idCheck", async (req, res, next) => {
let userId = req.body.userId;
console.log(userId);
try {
const userIdCheck = await User.findOne({ userId: userId });
console.log(userIdCheck);
return res.status(200).send(userIdCheck);
} catch (error) {
next(error);
}
});
//사용자 데이터 추가 - 데이터등록
router.post("/userDataInsert", async (req, res, next) => {
console.log(req.body);
try {
const user = new User(req.body);
await user.save();
return res.sendStatus(200);
} catch (error) {
next(error);
}
});
//사용자 데이터 삭제
router.post("/userDataDelete", async (req, res, next) => {
console.log(req.body);
try {
for (let index in req.body) {
console.log(index);
console.log(req.body[index]);
const delYn = await User.deleteOne({
userId: req.body[index],
});
console.log(delYn);
}
return res.json({ deleteSuccess: true });
} catch (error) {
next(error);
}
});
module.exports = router;
[ 결과화면 ]
- 사용자 데이터 조회
- 데이터 추가
- 데이터 수정
- 데이터 삭제