import { Box, Button, Modal } from '@mui/material';
기존의 @mui/material에서 Box, Button, Modal을 추가로 불러왔다.
// 모달창 스타일
const style = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
border: "2px solid #000",
boxShadow: 24,
p: 4,
};
이거를 AccountList.js 파일에서 작성했는데, 다른 파일로 넘겨서 작성해야 할 것 같다. 현재는 임시방편으로 여기에 구현했다..
const [open, setOpen] = useState(false);
const [selectedRow, SetSelectedRow] = useState(null);
const handleOpen = (row) => {
selectedRow(row);
setOpen(true);
};
const handleClose = (row) => {
setOpen(false);
setSelectedRow(null);
};
const handleInputChange = (e) => {
const { name, value } = e.target;
setSelectedRow((prevRow) => ({ ...prevRow, [name]: value }));
};
useState()를 사용해서 모달창이 열려있는지, 닫혀있는지 구현할 수 있다. 기본적으로 false를 적용해주고 모달창이 열릴 때마다 true로 바꿔준다.
행을 클릭하면 데이터가 들어갈 수 있도록 selectedRow도 useState(null)로 기본적으로 아무 값도 나오지 않게 만들어준다.
handleInputChange를 만들어서 모달창이 열리면 값의 변화를 알려주도록 만들어준다. 클릭한 데이터의 name, value를 setSelectedRow에 반영하도록 했다. ...prevRow는 prevRow 객체의 모든 속성을 복사해서 prev(이전)값을 [name]: value로 새롭게 설정해서 값을 업데이트 해준다.
// 모달창 리스트 데이터 수정
const handleSave = async () => {
try {
const response = await axios.post(`http://localhost:4000/wallet/money/update/${selectedRow._id}`, selectedRow);
setRows(updatedRows);
handleClose();
console.log(response.data);
} catch(err) {
console.error(err);
}
};
모달창에서 데이터를 수정하고, 선택한 데이터의 ObjectId를 백엔드 라우터로 모달창에서 데이터를 수정한 selectedRow객체를 같이 전송한다.
그 후, rows에서 반복문을 돌려서 row._id와 selectedRow._id가 일치하면 selectedRow를 리턴해서 해당 행을 selectedRow로 바꾸고, 아니면 row를 리턴한다.
그리고 setRows(updatedRows) 훅을 호출해서 바뀐 값을 업데이트 해준다.
모달창을 나가면 handleClose()를 호출해서 모달창을 닫아주고, 선택한 행도 null로 바꿔준다. 그 후 window.location.reload()를 해준다.
const handleDelete = async () => {
try {
const response = await axios.post(`http://localhost:4000/wallet/delete/${selectedRow._id}`, selectedRow);
handleClose();
console.log(response.data);
} catch(err) {
console.error(err);
}
}
모달창에 있는 버튼 중 하나인 delete버튼을 누르면 백엔드로 전송되는 로직이다. selectedRow를 객체로 백엔드로 보낸 뒤, handleClose()를 호출해서 모달창을 닫고, 보낸 데이터를 출력한다.
rows.slice((page && page >= 0 ? page : 0) * (rowsPerPage && rowsPerPage > 0 ? rowsPerPage : 10), (page && page >= 0 ? page : 0) * (rowsPerPage && rowsPerPage > 0 ? rowsPerPage : 10) + (rowsPerPage && rowsPerPage > 0 ? rowsPerPage : 10)
이거는 page가 0보다 크면 page를 리턴하고, 아니면 0을 리턴한 값을 rowsPerPage도 같은 로직을 곱한 값을 시작 인덱스로 정하고, 끝 인덱스는 시작 인덱스 값에 rowsPerPage를 더해준 것을 끝 인덱스로 해주는 로직이다. 이렇게 추가한 이유는 .slice를 읽을 수 없다는 에러메세지가 나오기 때문에 이 로직을 추가했다.
원래는 모달창에서 category부분이 TextField로 되어있어서 원하는 대로 카테고리 수정이 안되는 버그가 생겼다. 이를 해결하기 위해 Mui/Material에서 제공하는 <Select> 태그와 그 안에 <option>을 대체할 <MenuItem> 태그를 사용해서 옵션 태그를 구현했다.
<Modal open={open} onClose={handleClose} aria-labelledby="modal=modal-title" aria-describedby="modal-modal-description">
<Box sx={{ ...style, width: 400 }}>
<Typography id="modal-modal-title" variant="h6" component="h2">
<FormLabel>
<TextField margin="normal" fullWidth type="date" name="date" value={selectedRow.date} onChange={handleInputChange}/>
<Select margin="normal" fullWidth name="category" value={selectedRow.category} onChange={handleInputChange}>
<MenuItem disabled>지출</MenuItem>
<MenuItem value="식비">식비</MenuItem>
<MenuItem value="생필품">생필품</MenuItem>
<MenuItem value="문화/교육비">문화/교육비</MenuItem>
<MenuItem value="기타">기타</MenuItem>
<MenuItem value="저축">저축</MenuItem>
<MenuItem value="수입">수입</MenuItem>
<MenuItem value="월급">월급</MenuItem>
<MenuItem value="기타소득">기타소득</MenuItem>
</Select>
<TextField margin="normal" fullWidth type="text" name="title" value={selectedRow.title} onChange={handleInputChange}/>
<TextField margin="normal" fullWidth name="amount" value={selectedRow.amount} onChange={handleInputChange}/>
<Button onClick={handleSave}>Save</Button>
<Button onClick={handleDelete}>Delete</Button>
</FormLabel>
}}
</Box>
</Modal>
open={open}을 클릭하면, 테이블이 클릭할 때, useState()에서 적은 open이 실행되서 모달창이 열린다.
variant="h6"는 텍스트 사이즈를 h6으로 변경하고, component="h2"는 Typography를 기본적으로 <span>태그로 인식하는데 이걸 h2로 바꿔서 렌더링 하게 해준다.
원래는 모달창의 category가 <TextField>였는데, 이걸 <Select>로 바꾸고, <Option>태그 대신 <MenuItem>으로 변경했다.