-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat: 리스트 상세 페이지 기능 구현(리스트 삭제, 존재하지 않는 리스트 처리, 유저 정보에 따른 ui 처리) 및 리팩토링 #31
Feat: 리스트 상세 페이지 기능 구현(리스트 삭제, 존재하지 않는 리스트 처리, 유저 정보에 따른 ui 처리) 및 리팩토링 #31
Conversation
@Nahyun-Kang is attempting to deploy a commit to the Eujin Ahn's projects Team on Vercel. A member of the Team first needs to authorize it. |
src/app/layout.tsx
Outdated
@@ -34,6 +34,7 @@ export default function TempLayout({ children }: { children: ReactNode }) { | |||
<QueryClientProvider client={queryClient}> | |||
<div id="modal-root" /> | |||
<div>{children}</div> | |||
<ToastContainer /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
다시 복구해놓았습니다..🥹 죄송합니다..담부턴 꼼꼼히 체크할게용
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
84개의 커밋..
제인생에 이런 숫자를 다시 볼 수 있을까요
귀하네요..✨
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나현님 정말,,, 커밋수 보고도 놀랐지만 코드 보고도 너무 놀랐어요..!
정말 엄청 많은 경우의 수와 상황이 있을 것 같은데, 너무 고생하셨고 감사합니다🙇♀️🥹💗
|
||
async function createComment({ listId, comment }: CreateCommentType) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ 화살표 함수로 바꿔야 할 것 같아요~!
|
||
//리스트 상세 페이지 리스트 조회 api | ||
async function getComments({ listId, cursorId }: GetCommentsType) { | ||
const params = new URLSearchParams({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
우와 이렇게 객체형식으로 넣어주면 쿼리 형태로 바꿔 주는가봐요!! 배워갑니다!!💗
+) 댓글 받아오는 사이즈를 5개로 정하신 이유가 (단순) 궁금합니다!!👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(저도 소현님 PR로 어깨넘어 배운건데 감사합니다 ㅎㅎ👍) 5개로 한 이유는 무한스크롤이 잘 되는지 확인하기 위해 5개로 설정한 것이었는데 IA 보고 공통 개수로 수정해두겠습니다..!! 발견 감사드려용..👍
export const disabledSheetItemWrapper = style({ | ||
':hover': { | ||
backgroundColor: '#ffffff', | ||
}, | ||
}); | ||
|
||
export const disabledSheetItem = style({ | ||
cursor: 'not-allowed', | ||
selectors: { | ||
[`${sheetItemWrapper}:hover &`]: { | ||
color: '#e9e9e9', | ||
}, | ||
}, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요기도 공용색상 사용해도 좋을 것 같아요! 🎨
var.color.white
var.color.gray5
import BottomSheet from '@/app/[userNickname]/[listId]/_components/BottomSheet/BottomSheet'; | ||
import ModalPortal from '@/components/ModalPortal'; | ||
import BottomSheet from '@/app/user/[userId]/list/[listId]/_components/BottomSheet/BottomSheet'; | ||
import ModalPortal from '@/components/modal-portal'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
modal-portal을 케밥으로 해주신 이유가 무엇인지 궁금합니다!!🙇♀️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
엇 서영님 혹시 모달포탈이 케밥으로 되어있는 부분이 어디일까용..?! 🥲
<Image | ||
src={item.profileImageUrl} | ||
className={styles.profileImage} | ||
alt="사용자 프로필 이미지" | ||
width={25} | ||
height={25} | ||
style={{ | ||
objectFit: 'cover', | ||
}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제가 아는 바로는 obejectFit 속성은 Image컴포넌트 사이작 fill일때 적용이 되는 것 같아요~! 부모div를 만들어 사이즈 지정 & position:relative 주고, Image 컴포넌트는 fill 속성으로 대체하면 어떨까요??
<Image | |
src={item.profileImageUrl} | |
className={styles.profileImage} | |
alt="사용자 프로필 이미지" | |
width={25} | |
height={25} | |
style={{ | |
objectFit: 'cover', | |
}} | |
<div className={styles.profileWrapper} > {/*프로필이미지 부모. width=25, height=25, position:relative*/} | |
<Image | |
src={item.profileImageUrl} | |
className={styles.profileImage} | |
alt="사용자 프로필 이미지" | |
fill | |
style={{ | |
objectFit: 'cover', | |
}} | |
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오매낫 사용법을 제대로 모르고 사용하고 있었군용.. 🫠 정말 감사합니다.. 당장 바꾸겠습니다!
const comments = useMemo(() => { | ||
const totalCount = commentsData ? commentsData.pages[commentsData.pages.length - 1].totalCount : 0; | ||
const commentsList = commentsData ? commentsData.pages.flatMap(({ comments }) => comments) : []; | ||
return { commentsList, totalCount }; | ||
}, [commentsData]); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useMemo를 이럴때 이렇게 쓰는거군요! 배워갑니다🥹👍👍
flatMap이라는 건 처음 보네요!
와 저에게는 엄청 어렵습니다! 이따 직접 여쭙겠습니다 🥰
(완료~! 감사합니다 🙇♀️)
setCommentId(id); | ||
}; | ||
|
||
//댓글 폼 사용(추후 리액트 훅폼으로 수정해 볼 예정) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
어서 리액트 훅 폼의 세계로...⭐️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
우왓 스켈레톤 까지!!
<button className={styles.buttonResetStyle} onClick={handleHistoryButtonClick}> | ||
<HistoryButton alt="히스토리 버튼" /> | ||
</button> | ||
{/* {리스트 관리 버튼은 리스트 오너일 때만 보이게 하기} */} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요거 너므 사소하지만 주석 "리스트 오너, 콜라보레이터"로 바꿔도 좋을 것 같아요!!
<SwiperSlide | ||
key={item.id} | ||
className={styles.swiperSlide} | ||
onClick={() => { | ||
router.push(`/user/${item.ownerId}/list/${item.id}`); | ||
}} | ||
> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍👍👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나현님, 리뷰 늦게 드려 죄송합니다..
댓글/답글 로직, 권한, UI, 인터랙션 등 디테일한 부분이 많았을텐데 구현하시느라 정말 고생많으셨습니다!! 👍🥰 덕분에 많은 부분 얻어갑니다!! 감사합니다. 🙇♀️
`/lists/${listId}/comments`, | ||
{ | ||
content: comment, | ||
}, | ||
{ | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나현님, axios 요청보낼때 content와 headers를 따로 명시하신 이유가 궁금합니다!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요청이 안 가지길래 요 문제인 줄 알고 추가해봤는데 아니었더라구요... 삭제해두겠습니다!!
interface CreateReplyType { | ||
listId: number | undefined; | ||
commentId: number | undefined | null; | ||
data: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
undefined는 옵셔널로 수정해도 좋을 것 같습니다!!
async function createReply({ listId, commentId, data }: CreateReplyType) { | ||
if (commentId === null) { | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나현님 궁금한점이 commentId가 null일 수도 있는 것인가요?? 댓글이 삭제된 경우를 의미하는 것인가용??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 저 commentId는 댓글 작성중일 때를 의미합니당..! 하나의 폼에서 댓글 / 답글 요청을 다 보내다보니 답글 작성중일 때 어떤 댓글에 대하여 답글을 작성중인지 정보가 필요해서 setState로 관리해주고 있었습니다..! 근데 변수명이 오해의 소지가 있는 것 같아서 CurrenCommentId 요런 느낌으로 고쳐봐야겠습니다!
async function deleteComment({ listId, commentId }: DeleteCommentType) { | ||
const response = await axiosInstance.delete(`/lists/${listId}/comments/${commentId}`); | ||
return response.data; | ||
} | ||
|
||
export default deleteComment; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete 후에 response로 받는 데이터가 있는 것인지 궁금합니다!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
흑흑 코드 복붙의 흔적이 여기저기(Post 요청에서 가져온 것 같습니당).. 깔끔하게 정리를 못해서 부끄럽습니다.. 감사합니다!!
//댓글 삭제 api | ||
async function deleteList(listId: string | undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나현님, undefined는 옵셔널로 처리해 주는 것이 더 좋을 것 같은데 나현님 생각은 어떠신가요..? 🤔
//댓글/답글 폼 submit 함수 | ||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault(); | ||
if (!userId) { | ||
return; | ||
} | ||
if (commentId && activeNickname) { | ||
createReplyMutation.mutate(); | ||
return; | ||
} | ||
createCommentMutation.mutate(); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나현님, 조건에 따른 댓글/답글 로직이 복잡하셨을 것 같은데 해당 컴포넌트에서 깔끔하게 정리해 주신 것 같습니다!👍👍🏄♀️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
사실 소현님 PR 보고 많이 참고했습니다..!!🥰 제 교재같은 소현님 PR..
enabled: !!params?.listId, | ||
retry: 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍👍
//리스트 생성자 제외한 사람들만 콜라보레이터들로 설정 | ||
const filteredCollaboratorsList = list?.collaborators.filter((item: UserProfileType) => item?.id !== list.ownerId); | ||
//리스트 오너가 아니고 콜라보레이터인 경우에 권한을 설정하기 위한 변수 | ||
const isCollaborator: boolean | undefined = | ||
list?.collaborators.some((item: UserProfileType) => item?.id === userId) && userId !== Number(params?.userId); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
와우! 이렇게 조건에따라 변수에 먼저 할당하는 부분 너무 좋은 것 같습니다!
+. 사소하지만 변수명 collaborators와 list가 중복된 느낌이라서 filteredCollaborators 로만 이름 지어줘도 좋을 것 같습니다.
+. some을 사용하신 점 좋네요!
|
||
if (error && error?.message.includes('404')) { | ||
return ( | ||
<Modal handleModalClose={handleSetOff}> | ||
<Modal.Title>이 리스트는 삭제 또는 비공개 처리 되었어요.</Modal.Title> | ||
<Modal.Button onCancel={handleSetOff} onClick={handleConfirmButtonClick}> | ||
확인 | ||
</Modal.Button> | ||
</Modal> | ||
); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나현님 이 부분이 리스트 없을때 커스텀 404인 것인가요? 👍
(+. 내일 자세하게 여쭤봐도 될까요?? ㅎㅎ)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵..!! 페이지로 따로 뺄까 고민하다가 로직이 이게 맞는지 확신이 들지 않아서 요렇게 썼습니당... 더 좋은 방향으로 바꿔볼 수 있는 피드백이 있다면 언제든지 말씀해주세요..!!🥹
const useInfiniteScroll = (handler: () => void) => { | ||
const ref = useRef<HTMLDivElement | null>(null); | ||
|
||
//scroll로 한 번 도전해봤는데 ref wrapper 자체가 clientHeight보다 작으면 문제가 생겨서 document로 걸어주었습니다 ㅠ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나현님 혹시 해당 hook은 어디서 사용되는 것인가용? 다른 코드에서 못본것 같아서 확인차 여쭤봅니다!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
소현님 훅 만드신 거 보자마자 버린 파일인데 삭제를 못했네요..🥲 얼른 잽싸게 지우겠습니다!!
@seoyoung-min @ParkSohyunee @Eugene-A-01 시간내주셔서 꼼꼼하게 리뷰해주셔서 감사합니다!! 소중한 의견들 모두 반영해서 다음 PR 때 올리도록 하겠습니다🙇♀️ |
개요
작업 사항
기능 구현
리팩토링 관련
참고 사항 (optional)
관련 이슈 (optional)
스크린샷
리뷰어에게