티스토리 뷰
💥 Modal Edit 컴포넌트 생성, 기능 생성, 스타일하기
const EditModal = () => {
const dispatch = useTypedDispatch()
const editingState = useTypedSelector(state => state.modal)
const [data, setData] = useState(editingState)
const handleCloseButton = () => {
dispatch(setModalActive(false))
}
const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {
setData({
...data,
task: {
...data.task,
taskName: e.target.value
}
})
}
const handleDescriptionChange = (e:ChangeEvent<HTMLInputElement>) => {
setData({
...data,
task: {
...data.task,
taskDescription: e.target.value
}
})
}
const handleAuthorChange = (e:ChangeEvent<HTMLInputElement>) => {
setData({
...data,
task: {
...data.task,
taskOwner: e.target.value
}
})
}
const handleUpdate = () => {
dispatch(
updateTask({
boardId: editingState.boardId,
listId: editingState.listId,
task: data.task,
})
)
dispatch(
addLog({
logId: v4(),
logMessage: `일 수정하기: ${editingState.task.taskName}`,
logAuthor: "User",
logTimestamp: String(Date.now())
})
)
dispatch(setModalActive(false))
}
const handleDelete = () => {
dispatch(
deleteTask({
boardId: editingState.boardId,
listId: editingState.listId,
taskId: editingState.task.taskId
})
)
dispatch(
addLog({
logId: v4(),
logMessage: `일 삭제하기: ${editingState.task.taskName}`,
logAuthor: "User",
logTimestamp: String(Date.now())
})
)
dispatch(setModalActive(false))
}
return (
<div className={wrapper}>
<div className={moadlWindow}>
<div className={header}>
<div className={title}>{editingState.task.taskName}</div>
<FiX className={closeButton} onClick={handleCloseButton}/>
</div>
<div className={title}>제목</div>
<input
className={input}
type="text"
value={data.task.taskName}
onChange={handleNameChange}
/>
<div className={title}>설명</div>
<input
className={input}
type="text"
value={data.task.taskDescription}
onChange={handleDescriptionChange}
/>
<div className={title}>생성한 사람</div>
<input
className={input}
type="text"
value={data.task.taskOwner}
onChange={handleAuthorChange}
/>
<div className={buttons}>
<button className={updateButton} onClick={handleUpdate}>
일 수정하기
</button>
<button className={deleteButton} onClick={handleDelete}>
일 삭제하기
</button>
</div>
</div>
</div>
)
}
export default EditModal
- EditModal.tsx
다른 컴포넌트와 크게 다를 것 없이 생성했기 때문에 큰 어려움은 없었다.
수정or삭제 하고자 하는 Task를 누르면 해당 Modal창이 뜨게끔 만들었다.
제목, 설명, 생성한 사람을 수정할 수 있었고, 제목에 적혀있는 Task 1 이 Modal창 가장 맨 위의 타이틀과 동일하게 나오게 만들었다.
그래서 Task1 을 Task 13으로 만들면 위의 Title도 Task 13으로 나타나게 된다.
💥 LoggerModal 컴포넌트 생성, LogItem 컴포넌트 생성&스타일 하기
type TLoggerModalProps = {
setIsLoggerOpen: React.Dispatch<React.SetStateAction<boolean>>
}
const LoggerModal: FC<TLoggerModalProps> = ({
setIsLoggerOpen
}) => {
const logs = useTypedSelector(state => state.logger.logArray)
return (
<div className={wrapper}>
<div className={moadlWindow}>
<div className={header}>
<div className={title}>활동 기록</div>
<FiX className={closeButton} onClick={() => setIsLoggerOpen(false)} />
</div>
<div className={body}>
{logs.map((log) => (
<LogItem key={log.logId} logItem={log}/>
))}
</div>
</div>
</div>
)
}
export default LoggerModal
- LoggerModal.tsx
LoggerModal 컴포넌트 역시 다른 파일과 크게 다르진 않다.
단, LogItem 부분을 보면 logitem을 배열의 객체 수만큼 렌더링 해주고있고, props로 내려주는 건 log데이터를 내려주고 있다.
type TLogItemProps = {
logItem: ILogItem
}
const LogItem: FC<TLogItemProps> = ({
logItem
}) => {
const timeOffset = new Date(Date.now() - Number(logItem.logTimestamp))
console.log('timeOffset : ', timeOffset)
console.log('timeOffset : ', timeOffset.getMinutes())
console.log('timeOffset : ', timeOffset.getSeconds())
const showOffsetTime = `
${timeOffset.getMinutes() > 0 ? `${timeOffset.getMinutes()}m` : ""}
${timeOffset.getSeconds() > 0 ? `${timeOffset.getSeconds()}s ago` : ""}
${timeOffset.getSeconds() === 0 ? `just now` : ""}
`
return (
<div className={logItemWrap}>
<div className={author}>
<BsFillPersonFill />
{logItem.logAuthor}
</div>
<div className={message}>{logItem.logMessage}</div>
<div className={date}>{showOffsetTime}</div>
</div>
)
}
export default LogItem
- LogItem.tsx
LogItem의 코드를 보면 timeOffset 이라는 변수를 사용하는 걸 볼 수 있는데,
보통 활동 로그를 보면 몇 초 전, 몇 분 전, 이렇게 시간 계산을 해주는 걸 볼 수 있다. 그걸 위한 변수라고 생각하면 된다.
console.log를 찍어놨기 때문에 간단히 보면서 설명하겠다.
첫 번째 log의 분, 초를 보면 된다.
두 번째 log는 timeOffset에서 나온 값의 분만 나타나게 만들었다.
그래서 0분의 0 을 나타내고 있고, 세 번째 log는 timeOffset의 초만 나타나게 하였다.
그래서 22초의 22를 나타내고 있다.
이걸 사용해서 showOffsetTime 변수를 만들었다.
즉, 분은 m을 붙여 나타내게 하고, 초는 s ago를 붙여 나타내게 했다.
하지만, s는 0초일 경우 0s가 아닌 지금! 이라는 뜻을 가진 just now 라는 글자가 나타나게 만들었다.
이렇게 0초를 나타내는 just now와 2초 전인 2s ago가 나타는 걸 볼 수 있다.
💥 게시판 삭제 기능 생성하기
게시판 삭제하기 버튼을 누르면, Active한 게시판을 삭제할 수 있게 할 것이다.
단, 게시판이 1개일 경우에 삭제버튼을 누르면 최소 게시판 개수는 한 개입니다. 라는 알림창이 뜨게 만들려고 한다.
deleteBoard: (state, {payload}: PayloadAction<TDeleteBoardAction>) => {
state.boardArray = state.boardArray.filter(
board => board.boardId !== payload.boardId
)
}
- boardsSlice.tsx
먼저, boardsSlice 파일에 deleteBoardAction을 만들어준다.
const handleDeleteBoard = () => {
if(boards.length > 1) {
dispatch(
deleteBoard({boardId: getActiveBoard.boardId})
)
dispatch(
addLog({
logId: v4(),
logMessage: `게시판 지우기: ${getActiveBoard.boardName}`,
logAuthor: "User",
logTimestamp: String(Date.now())
})
)
const newIndexToSet = () => {
const indexToBeDelete = boards.findIndex(
board => board.boardId === activeBoardId
)
return indexToBeDelete === 0
? indexToBeDelete + 1
: indexToBeDelete - 1
}
setActiveBoardId(boards[newIndexToSet()].boardId)
} else {
alert('최소 게시판 개수는 한 개입니다.')
}
}
- App.tsx
그 다음, App.tsx 파일에 "이 게시판 삭제하기" 버튼을 눌렀을 때 일어날 이벤트를 만들어준다.
변수이름은 handleDeleteBoard 라고 만들어주었다.
게시판이 1개일 땐, 삭제가 되지 않고 알림창을 띄워주어야 한다.
그래서 boards의 length가 1보다 클 때만 삭제할 수 있게 유효성 체크 부분을 넣어주었다.
그럼 이렇게 게시판이 1개일 땐, "최소 게시판 개수는 한 개입니다." 라는 알림창이 뜨게 되고,
게시판이 2개 이상일 땐, 성공적으로 지울 수 있게 되고, dispatch를 통해 log를 남기게 만들어놨으니,
log도 정상적으로 "게시판 지우기" 라고 뜨는 걸 볼 수 있다.
'웹 개발 공부하기' 카테고리의 다른 글
[01.24] Book Store 프로젝트 프론트 준비! (1) | 2025.01.29 |
---|---|
[01.23] 리액트를 이용한 Task 생성 앱 만들기 4 (1) | 2025.01.29 |
[01.21] 리액트를 이용한 Task 생성 앱 만들기 2 (0) | 2025.01.27 |
[01.20] 리액트를 이용한 Task 생성 앱 만들기 (0) | 2025.01.21 |
[01.16] todolist 마무리하기😆 (0) | 2025.01.17 |