-
Notifications
You must be signed in to change notification settings - Fork 1
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: 공통 컴포넌트 개발 및 톡픽 수정, 삭제, 신고, 요약, 댓글 api 연결 #180
Conversation
if (isTempLoaded) { | ||
setImgUrls((prevUrls) => prevUrls.filter((_, i) => i !== index)); | ||
setStoredNames((prevNames) => prevNames.filter((_, i) => i !== index)); | ||
const isObjectUrl: boolean = imageList[index].startsWith('blob:'); |
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.
수정된 handleDelete
를 통해 로컬에서 생성된 blob: URL과 서버에 저장된 파일을 구분하여 처리하는 로직에 대해 새롭게 알게 되었네용👍
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.
사용자가 업로드를 할 경우 blob: 이라는 스키마로 시작하는 군요! 저도 하나 배워갑니다.
+) 추가로 ImageUploader 도 스토리북에 구현이 안되어있는거 같아요 이 부분도 확인 부탁드립니다!
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.
참고로 blob으로 시작하는 string 값은 서버에 이미지 업로드 요청을 보내기 전의 이미지입니다!! 현재 로직을 설명드리면
사용자가 이미지 파일을 선택 -> URL.createObjectURL(file)
을 통해 사용자가 선택한 이미지를 임시적으로 보여줌 -> 게시글 작성 (수정) 버튼 클릭 시 해당 이미지 파일을 서버에 (이미지) 업로드 요청하여 그에 대한 반환 값으로 storedNames
배열을 얻음 -> 게시글 데이터와 함께 storedNames
배열을 보냄 -> 게시글 상세 조회 데이터에 존재하는 imgUrls
배열을 통해 사용자에게 업로드된 이미지를 보여줌
위와 같습니다!! 참고 부탁드립니다 🙇♀️🙇♀️
+) ImageUploader 컴포넌트 스토리북에 추가하였습니다 !!
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.
친절한 설명 감사합니다 : ) 이미지 예시로 가로로 나열되는 이미지들이 URL.createObjectURL(file)
을 통해 생성된 임시 이미지라고 생각하면 될까요?
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.
게시글을 새로 작성하는 경우는 URL.createObjectURL(file)
로 생성된 임시 이미지이고, 기존에 이미지가 있던 게시글을 수정하는 경우는 imgUrls
가 보여집니다! 기존에 이미지가 있던 게시글에 이미지를 추가하는 경우엔 기존에 있던 이미지는 imgUrls
, 새로 추가한 이미지는 URL.createObjectURL(file)
로 보여집니다 기존 이미지와 추가한 이미지를 합쳐 보여주는 배열이 imageList
입니다🙌
const imageList: string[] = [
...imgUrls,
...imageFiles.map((file) => URL.createObjectURL(file)),
];
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 PostInputForm = ( | ||
{ onSubmit, onSave }: PostInputFormProps, | ||
{ onSubmit, onEditSubmit, onSave, existingTalkPick }: PostInputFormProps, |
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.
existingTalkPick
을 받아오는 이유는 임시 저장 이후 또는 수정 시 데이터를 불러오기 위함인지 궁금합니다!
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.
existingTalkPick
은 톡픽 상세 페이지에서 수정 버튼을 눌렀을 때 state를 이용해 작성 페이지로 넘겨준 톡픽 상세 데이터입니다! 임시 저장된 톡픽 데이터는 유빈님께서 작성하셨던 handleLoadDraft
함수로 불러와집니다 😊
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 구현 및 수정 그리고 UI 구현까지 넘 수고많으셨어요!!👏 수정된 ImageUploader, PostInputForm 처리 로직도 감사합니닷...🙇♀️ 코드 보면서 제가 생각하지 못했던 로직까지 보면서 또 배우고 갑니당ㅎㅎ👍
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.
게시글 수정, 삭제 관련 변경 사항이 많았는데, 전반적인 흐름을 매끄럽게 수정해주신 부분 대단히 감사합니다! 정말 고생많으셨어요 🚀
ImageUpload 관련해서 구현할 때의 방향성을 더 잡고 가게 되네요!!
추가로 코멘트에도 남겼지만, ImageUploader에 대한 스토리북 코드가 없는거 같아요 이 부분 확인 부탁드립니다! 다시 한번 고생 많으셨습니다 👍
@@ -16,7 +16,7 @@ export const putComment = async ( | |||
) => { | |||
const { data } = await axiosInstance.put<ServerResponse>( | |||
END_POINT.EDIT_COMMENT(talkPickId, commentId), | |||
{ ...comment }, | |||
{ content: comment }, |
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 response = await axiosInstance.post( | ||
END_POINT.REPORT_COMMENT(talkPickId, commentId), | ||
{ | ||
reportType: 'COMMENT', |
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.
swagger에서도 request body
에는 reportType: 'COMMENT'
로 고정되는 구조인데 reportType 는 항상 COMMENT인지 궁금합니다 :)
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.
저도 스웨거에서 'COMMENT'로 고정된 것을 보고 저렇게 작성해두었어요!!
추후에 답글 신고나 톡픽 게시글 신고의 경우엔 다른 값을 사용하지 않을까 싶습니다 😶
if (!withText) { | ||
return css({}); | ||
} |
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.
withText로 1차 분기 처리를 하고, true 일 경우 option을 통해 스타일을 설정을 하는 방식이 정말 깔끔한거 같습니다!
@@ -6,12 +6,12 @@ import { | |||
} from './CommentProfile.style'; | |||
|
|||
export interface CommentProfileProps { | |||
stance: 'pros' | 'cons'; | |||
option: 'A' | 'B'; |
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 { mutate: deleteComment } = useDeleteCommentMutation( | ||
comment.talkPickId, | ||
'comments', | ||
); | ||
|
||
const { | ||
mutate: reportComment, | ||
reportCommentSuccess, | ||
setReportCommentSuccess, | ||
} = useReportCommentMutation(comment.talkPickId, comment.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.
최근에 컴포넌트 단계에 따라서(atoms, molecules, ....pages) 관심사 분리
를 어디까지 해야할까 하는 고민이 있는데, pages의 하위단계에서 데이터 패칭이 일어나는 것이 옳은 방법인가에 대해 고민이 되더라구요!
저도 하위 단계에서 커스텀 훅을 이용한 api 요청을 처리한 부분들이 많아서 아름님은 어떻게 생각하시는지 궁금합니다!
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.
저는 데이터를 받아와서 하위 컴포넌트에 뿌려주는 방식은 pages 컴포넌트 내에서 구현하는게 좋다고 생각해요!! 그런데 댓글 삭제나 신고와 같은 훅은 톡픽의 id, 댓글의 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.
그렇네요! 개별 댓글
의 기능은 각 댓글 창에서만 일어나는 동작이라는 생각에 동의합니다 ㅎㅎ 답변 감사합니다!!
onClose?: () => void; | ||
} | ||
|
||
const ReportModal = ({ isOpen, onConfirm, onClose }: ReportModalProps) => { | ||
const [reportReason, setReportReason] = useState<string>(''); | ||
const [otherReason, setOtherReason] = useState<string>(''); | ||
const finalReportReason: string = | ||
reportReason === '기타' ? otherReason : reportReason; |
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.
저 같은 경우에 === 한글
이렇게 사용하면 lint 에러가 나서 enum으로 처리했는데 혹시 이런 오류가 발생하지 않았는지 궁금합니다.
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.
저도 처음엔 신고 옵션에 대한 value를 영어로 작성해두었는데 스웨거를 보니 서버로 보내지는 신고 사유가 한글로 처리되어있어서 해당 값들을 수정해두었어요,,! 오류가 발생하진 않았습니다 🥹
}, | ||
decorators: [ | ||
(Story) => ( | ||
<Provider store={store}> |
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 요청에서 header 부분과 연관이 있는지 궁금합니다. 유사한 코드로 스토리북 테스트를 진행했을 때, 토큰이 없어서 요청 자체가 거부되더라구요!
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.
redux 스토어에 접근하기 위한 코드입니다!! useNewSelector
함수로 redux에 접근하기 위해 사용한 부분입니다
저는 Provider 코드로 감싸준 것 외에는 따로 적용한 게 없어서 요청 거부에 대한 이유는 좀 더 찾아봐야 할 것 같아요,, 🥲
export const useCreateLikeCommentMutation = ( | ||
talkPickId: Id, | ||
commentId: Id, | ||
selectedPageNumber: Pick<Pageable, 'page'>, |
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.
페이지 네이션 관련된 사항을 별도로 처리하신 부분이 좋습니다!
{ value: '욕설', label: '욕설' }, | ||
{ value: '도배_및_스팸', label: '도배 및 스팸' }, | ||
{ value: '불건전_및_불법_정보', label: '불건전 및 불법 정보' }, | ||
{ value: '차별적_발언', label: '차별적 발언' }, | ||
{ value: '홍보_목적', label: '홍보 목적' }, | ||
{ value: '개인정보_노출_및_침해', label: '개인정보노출 및 침해' }, | ||
{ value: '기타', label: '기타' }, |
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.
이 부분도 value 값으로 한글 값이 들어가면 lint 에러가 발생하지 않는지 궁금합니다 !!
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.
저는 에러가 발생하지 않아서 위와 같이 작성해두었습니다 ,,!!
onSubmit: (data: NewTalkPick) => void; | ||
onEditSubmit: (data: NewTalkPick) => void; | ||
onSave: (data: NewTalkPick) => void; |
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.
해당 동작들에 대한 정의만 PostInputForm에서 처리하고, 상위 컴포넌트로 해당 동작을 넘겨준 건가욥?!!
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.
CreatePostPage
에서 톡픽 생성, 수정, 임시저장과 같이 게시글 작성 페이지에서 사용되는 훅을 선언해주고 PostInputForm
에 props로 넘겨주어 사용했습니다!!👍기존 게시글 작성 코드에 맞춰 연결해둔 부분입니당
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.
앗 그렇군요! CreatePostPage
에서 훅이 선언되어있고, PostInputForm
에서 해당 return 에 대한 props들이 선언되어 있네요 ㅎㅎ 답변 감사합니다!
const location = useLocation(); | ||
const state = location.state as State; | ||
const talkPickData = state?.todayTalkPick; |
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.
useLocation을 사용하신 의도가 궁금합니다!
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.
오늘의 톡픽 페이지에서 게시글 수정을 눌렀을 때 톡픽 상세 조회 데이터를 state
를 사용하여 CreatePostPage
로 넘겨주었고, 이를 받아오기 위해 사용했습니다 !! talkPickData
를 PostInputForm
에 existingTalkPick
으로 넘겨주었습니다😊
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.
저는 이전 페이지에서 전달된 todayTalkPick
데이터를 현재 페이지에서 활용하기 위해서라고 생각했는데, 맞나욥?!!!
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.
맞습니다!!! 현재는 오늘의 톡픽 페이지에 대한 데이터 수정을 위해 state 속성 명을 todayTalkPick이라고 지정해두었는데 생각해보니 이후 기본 톡픽에 대한 수정 시에도 사용될 것을 고려하면 속성 명을 수정해야겠네요!!😯 해당 부분 언급 주셔서 감사합니다!
onSubmit: (data: NewTalkPick) => void; | ||
onEditSubmit: (data: NewTalkPick) => void; | ||
onSave: (data: NewTalkPick) => void; |
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.
앗 그렇군요! CreatePostPage
에서 훅이 선언되어있고, PostInputForm
에서 해당 return 에 대한 props들이 선언되어 있네요 ㅎㅎ 답변 감사합니다!
💡 작업 내용
💡 자세한 설명
✅ CommentItem, CommentsSection
✅ ImageUploader, PostInputForm
storedNames
배열 값을 사용해 이미지 삭제 api를 호출하도록 구현했습니다.이미지가 존재하는 게시글을 수정 -> 이미지 추가
의 로직일 경우 작성 페이지에 보여지는 이미지를imgUrls
와imageFile
을 배열로 묶어 한번에 보여질 수 있도록 구현했습니다! (삭제도 이와 같은 로직입니다!)✅ GameStageBar
number
값 하나만 받도록 구현하였고, index 값에 맞추는 것이 좋을 것 같다고 생각하여 0을 넘겨줄 경우 1단계, 4를 넘겨줄 경우 5단계와 같이 표시됩니다!📗 참고 자료 (선택)
📢 리뷰 요구 사항 (선택)
🚩 후속 작업 (선택)
✅ 셀프 체크리스트
closes #179