Skip to content
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

Merged
merged 28 commits into from
Sep 10, 2024

Conversation

areumH
Copy link
Contributor

@areumH areumH commented Sep 8, 2024

💡 작업 내용

  • 선택지 작성 버튼 컴포넌트 구현 (atom)
  • 밸런스 게임 단계 확인바 컴포넌트 구현 (atom)
  • 밸런스 게임 추천 썸네일 컴포넌트 구현 (atom, molecule)
  • 톡픽 게시글 수정/삭제/요약 기능 api 연결
  • 톡픽 댓글 작성/삭제/신고 기능 api 연결
  • 톡픽 댓글 좋아요/좋아요 취소 기능 api 연결
  • 톡픽 투표 이후 댓글 확인 가능하도록 로직 구현
  • 본인이 작성한 댓글일 경우 배경색 추가
  • 톡픽 신고 모달 제시 로직 구현

💡 자세한 설명

✅ CommentItem, CommentsSection

  • 해당 컴포넌트들이 받는 데이터의 타입을 types 폴더에 재정리 후 연결시켜두었습니다.
  • Comment 타입명과 컴포넌트명의 구별을 위해 해당 컴포넌트명을 CommentItem으로 수정했습니다.
  • 댓글 작성 / 삭제 / 신고 / 좋아요 / 좋아요 취소 기능 화면 녹화본 첨부합니다! ▼

제목-없는-동영상-Clipchamp로-제작

✅ ImageUploader, PostInputForm

  • 이미지 없이 게시글 작성이 가능하도록 수정했습니다.
  • 기존에 구현되어있던 게시글 작성 코드에 맞춰 수정 기능을 추가하였습니다.
  • 수정 버튼을 누르면 해당 게시글에 대한 내용이 담긴 작성 페이지로 이동되어야 하기 때문에 state로 해당 데이터들을 넘겨주었습니다!
  • 기존에 존재하던 이미지를 삭제할 때에 storedNames 배열 값을 사용해 이미지 삭제 api를 호출하도록 구현했습니다.
  • 이미지가 존재하는 게시글을 수정 -> 이미지 추가의 로직일 경우 작성 페이지에 보여지는 이미지를 imgUrlsimageFile을 배열로 묶어 한번에 보여질 수 있도록 구현했습니다! (삭제도 이와 같은 로직입니다!)
  • 게시글 이미지 수정 기능 화면 녹화본 첨부합니다! ▼

제목-없는-동영상-Clipchamp로-제작-4

✅ GameStageBar

  • props로 number 값 하나만 받도록 구현하였고, index 값에 맞추는 것이 좋을 것 같다고 생각하여 0을 넘겨줄 경우 1단계, 4를 넘겨줄 경우 5단계와 같이 표시됩니다!

📗 참고 자료 (선택)

📢 리뷰 요구 사항 (선택)

🚩 후속 작업 (선택)

  • 댓글 수정 및 답글과 관련된 기능은 아직 ui가 확실히 나오지 않아 ui가 확정된 이후 기능 구현해도 괜찮다고 PM님께 전달받았습니다!! 추후 역할 분담 후 구현하면 좋을 것 같습니당
  • 톡픽 요약 요청을 보낼 때 talkPickId 값이 필요한데 톡픽 작성 후 응답으로 오는 데이터가 없어 작성 즉시 요약 요청을 보내지 못하고 있습니다. 현재는 톡픽 조회와 동시에 요청을 보내는 로직으로 작성되어 있어 톡픽을 조회할 때마다 톡픽 요약 문장이 다르게 보여지는 문제가 있습니다. 회의 때 톡픽 작성 성공 응답으로 해당 톡픽의 id 값을 받을 수 있을지 질문드린 후 가능하다면 코드 수정할 예정이니 참고 부탁드립니다!!

✅ 셀프 체크리스트

  • PR 제목을 형식에 맞게 작성했나요?
  • 브랜치 전략에 맞는 브랜치에 PR을 올리고 있나요? (master/main이 아닙니다.)
  • 이슈는 close 했나요?
  • Reviewers, Labels, Projects를 등록했나요?
  • 작업 도중 문서 수정이 필요한 경우 잘 수정했나요?
  • 테스트는 잘 통과했나요?
  • 불필요한 코드는 제거했나요?

closes #179

@areumH areumH added ✔︎pull requests pull requests 코드 체크 요청 👩🏻‍💻 frontend 프론트엔드 작업 🎨 markup ✅feature labels Sep 8, 2024
@areumH areumH requested a review from alwubin September 8, 2024 17:27
@areumH areumH self-assigned this Sep 8, 2024
if (isTempLoaded) {
setImgUrls((prevUrls) => prevUrls.filter((_, i) => i !== index));
setStoredNames((prevNames) => prevNames.filter((_, i) => i !== index));
const isObjectUrl: boolean = imageList[index].startsWith('blob:');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정된 handleDelete를 통해 로컬에서 생성된 blob: URL과 서버에 저장된 파일을 구분하여 처리하는 로직에 대해 새롭게 알게 되었네용👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용자가 업로드를 할 경우 blob: 이라는 스키마로 시작하는 군요! 저도 하나 배워갑니다.
+) 추가로 ImageUploader 도 스토리북에 구현이 안되어있는거 같아요 이 부분도 확인 부탁드립니다!

Copy link
Contributor Author

@areumH areumH Sep 9, 2024

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 컴포넌트 스토리북에 추가하였습니다 !!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

친절한 설명 감사합니다 : ) 이미지 예시로 가로로 나열되는 이미지들이 URL.createObjectURL(file)을 통해 생성된 임시 이미지라고 생각하면 될까요?

Copy link
Contributor Author

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)),
  ];

Copy link
Contributor

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,
Copy link
Contributor

@alwubin alwubin Sep 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

existingTalkPick을 받아오는 이유는 임시 저장 이후 또는 수정 시 데이터를 불러오기 위함인지 궁금합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

existingTalkPick은 톡픽 상세 페이지에서 수정 버튼을 눌렀을 때 state를 이용해 작성 페이지로 넘겨준 톡픽 상세 데이터입니다! 임시 저장된 톡픽 데이터는 유빈님께서 작성하셨던 handleLoadDraft 함수로 불러와집니다 😊

Copy link
Contributor

@alwubin alwubin left a 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 처리 로직도 감사합니닷...🙇‍♀️ 코드 보면서 제가 생각하지 못했던 로직까지 보면서 또 배우고 갑니당ㅎㅎ👍

Copy link
Contributor

@WonJuneKim WonJuneKim left a 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 },
Copy link
Contributor

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',
Copy link
Contributor

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인지 궁금합니다 :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 스웨거에서 'COMMENT'로 고정된 것을 보고 저렇게 작성해두었어요!!
추후에 답글 신고나 톡픽 게시글 신고의 경우엔 다른 값을 사용하지 않을까 싶습니다 😶

Comment on lines +16 to +18
if (!withText) {
return css({});
}
Copy link
Contributor

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';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 제가 반영했어야 했는데 바꿔주셨군요ㅜㅜ 감사합니다아

Comment on lines +51 to +60
const { mutate: deleteComment } = useDeleteCommentMutation(
comment.talkPickId,
'comments',
);

const {
mutate: reportComment,
reportCommentSuccess,
setReportCommentSuccess,
} = useReportCommentMutation(comment.talkPickId, comment.id);
Copy link
Contributor

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 요청을 처리한 부분들이 많아서 아름님은 어떻게 생각하시는지 궁금합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 데이터를 받아와서 하위 컴포넌트에 뿌려주는 방식은 pages 컴포넌트 내에서 구현하는게 좋다고 생각해요!! 그런데 댓글 삭제나 신고와 같은 훅은 톡픽의 id, 댓글의 id를 넘겨주어야 하고, 댓글 아이템 내에서 신고 성공에 따른 토스트 모달 제시 등 훅에서 가져오는 값들을 직접적으로 사용하기 때문에 하위 컴포넌트 내에서 구현해도 나쁘지 않다고 생각합니다,!! 개별 댓글에 따른 기능이기 때문에 위와 같이 구현하였습니다!! 😊

Copy link
Contributor

@WonJuneKim WonJuneKim Sep 10, 2024

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저 같은 경우에 === 한글 이렇게 사용하면 lint 에러가 나서 enum으로 처리했는데 혹시 이런 오류가 발생하지 않았는지 궁금합니다.

Copy link
Contributor Author

@areumH areumH Sep 9, 2024

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}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 api 요청에서 header 부분과 연관이 있는지 궁금합니다. 유사한 코드로 스토리북 테스트를 진행했을 때, 토큰이 없어서 요청 자체가 거부되더라구요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redux 스토어에 접근하기 위한 코드입니다!! useNewSelector 함수로 redux에 접근하기 위해 사용한 부분입니다
저는 Provider 코드로 감싸준 것 외에는 따로 적용한 게 없어서 요청 거부에 대한 이유는 좀 더 찾아봐야 할 것 같아요,, 🥲

Comment on lines +6 to -10
export const useCreateLikeCommentMutation = (
talkPickId: Id,
commentId: Id,
selectedPageNumber: Pick<Pageable, 'page'>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

페이지 네이션 관련된 사항을 별도로 처리하신 부분이 좋습니다!

Comment on lines +2 to +8
{ value: '욕설', label: '욕설' },
{ value: '도배_및_스팸', label: '도배 및 스팸' },
{ value: '불건전_및_불법_정보', label: '불건전 및 불법 정보' },
{ value: '차별적_발언', label: '차별적 발언' },
{ value: '홍보_목적', label: '홍보 목적' },
{ value: '개인정보_노출_및_침해', label: '개인정보노출 및 침해' },
{ value: '기타', label: '기타' },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분도 value 값으로 한글 값이 들어가면 lint 에러가 발생하지 않는지 궁금합니다 !!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 에러가 발생하지 않아서 위와 같이 작성해두었습니다 ,,!!

Comment on lines 15 to 17
onSubmit: (data: NewTalkPick) => void;
onEditSubmit: (data: NewTalkPick) => void;
onSave: (data: NewTalkPick) => void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 동작들에 대한 정의만 PostInputForm에서 처리하고, 상위 컴포넌트로 해당 동작을 넘겨준 건가욥?!!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CreatePostPage에서 톡픽 생성, 수정, 임시저장과 같이 게시글 작성 페이지에서 사용되는 훅을 선언해주고 PostInputForm에 props로 넘겨주어 사용했습니다!!👍기존 게시글 작성 코드에 맞춰 연결해둔 부분입니당

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 그렇군요! CreatePostPage에서 훅이 선언되어있고, PostInputForm에서 해당 return 에 대한 props들이 선언되어 있네요 ㅎㅎ 답변 감사합니다!

Comment on lines 18 to 20
const location = useLocation();
const state = location.state as State;
const talkPickData = state?.todayTalkPick;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useLocation을 사용하신 의도가 궁금합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오늘의 톡픽 페이지에서 게시글 수정을 눌렀을 때 톡픽 상세 조회 데이터를 state를 사용하여 CreatePostPage로 넘겨주었고, 이를 받아오기 위해 사용했습니다 !! talkPickDataPostInputFormexistingTalkPick으로 넘겨주었습니다😊

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 이전 페이지에서 전달된 todayTalkPick 데이터를 현재 페이지에서 활용하기 위해서라고 생각했는데, 맞나욥?!!!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞습니다!!! 현재는 오늘의 톡픽 페이지에 대한 데이터 수정을 위해 state 속성 명을 todayTalkPick이라고 지정해두었는데 생각해보니 이후 기본 톡픽에 대한 수정 시에도 사용될 것을 고려하면 속성 명을 수정해야겠네요!!😯 해당 부분 언급 주셔서 감사합니다!

Comment on lines 15 to 17
onSubmit: (data: NewTalkPick) => void;
onEditSubmit: (data: NewTalkPick) => void;
onSave: (data: NewTalkPick) => void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 그렇군요! CreatePostPage에서 훅이 선언되어있고, PostInputForm에서 해당 return 에 대한 props들이 선언되어 있네요 ㅎㅎ 답변 감사합니다!

@areumH areumH merged commit d181701 into dev Sep 10, 2024
3 checks passed
@areumH areumH deleted the feat/179-talkpick-api branch September 26, 2024 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✅feature 👩🏻‍💻 frontend 프론트엔드 작업 🎨 markup ✔︎pull requests pull requests 코드 체크 요청
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

공통 컴포넌트 개발 및 톡픽 수정, 삭제, 요약, 댓글 기능 api 연결
3 participants