Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Walkthrough피드 상세 데이터 인터페이스에 bookImageUrl, isWriter 필드가 추가되었고, MoreMenu와 Reply/SubReply/FeedDetailPage에서 작성자 여부와 타입(post/reply)에 따라 편집/삭제/신고 액션을 분기하도록 변경되었습니다. 팝업 스토어의 MoreMenuProps에 isWriter와 type이 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant PDP as FeedDetailPage
participant MM as MoreMenu
participant PS as PopupStore/Snackbar
U->>PDP: 더보기 클릭
PDP->>MM: openMoreMenu({ type: 'post', isWriter, onEdit/onDelete/onReport })
alt isWriter == true
U->>MM: 삭제 선택
MM-->>PDP: onDelete()
PDP->>PS: 삭제 처리 후 스낵바/네비게이션
else isWriter == false
U->>MM: 신고 선택
MM-->>PDP: onReport()
PDP->>PS: 신고 접수 스낵바
end
sequenceDiagram
participant U as User
participant R as Reply/SubReply
participant MM as MoreMenu
participant PS as PopupStore/Snackbar
U->>R: 더보기 클릭
R->>MM: openMoreMenu({ type: 'reply', isWriter, onDelete or onReport })
alt isWriter == true
U->>MM: 삭제 선택
MM-->>R: onDelete()
R->>PS: 삭제 성공/실패 스낵바
else isWriter == false
U->>MM: 신고 선택
MM-->>R: onReport()
R->>PS: 신고 접수 스낵바
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (12)
src/api/feeds/getFeedDetail.ts (1)
13-14: 신규 필드 도입 영향 범위 확인 필요:bookImageUrl,isWriter
bookImageUrl: string과isWriter: boolean추가는 UI 분기(수정/삭제/신고)에 핵심입니다. 서버 응답에서 두 필드가 항상 제공되는지 확인해 주세요. 특히bookImageUrl이 비어있는 케이스에 대한 UI fallback(placeholder 이미지 등)이 준비되어야 합니다.isWriter가 누락되거나false로 오는 경우, 타 사용자 브랜치로 처리됩니다. 의도대로라면 OK지만, 구버전 API나 특정 조건에서 필드가 빠질 수 있으면 방어 로직이 필요합니다.필드 존재 여부를 서버/문서로 확인해 주세요. 불확실하다면
bookImageUrl만이라도 UI에서 안전하게 fallback 처리하는 것을 권장합니다.필요하시면
bookImageUrl미제공 시 placeholder를 적용하는 패치도 제안드릴게요.Also applies to: 24-25
src/components/common/Post/SubReply.tsx (2)
59-75: 주석 처리된 이전 모달 코드 정리 권장과거 구현을 주석으로 남겨두면 유지보수 시 혼란을 줄 수 있습니다. git history로 충분히 추적 가능하니 삭제를 권장합니다.
- // 이전 더보기 모달 - // const handleMoreClick = () => { - // if (containerRef.current) { - // const rect = containerRef.current.getBoundingClientRect(); - // openReplyModal({ - // isOpen: true, - // userId: creatorId, - // commentId: commentId, - // position: { - // x: rect.right, - // y: rect.bottom, - // }, - // onClose: closePopup, - // }); - // } - // };
114-137: 작성자/비작성자 분기 로직 명확. 신고 액션 공통화로 중복 제거 가능현재 로직은 기능적으로 타당합니다. 다만 Reply.tsx와 동일한 신고 스낵바 로직이 복제되어 있어, 한 줄 함수로 공통화하면 가독성과 재사용성이 좋아집니다.
예시:
const handleMoreClick = () => { + const reportAction = () => { + closePopup(); + openSnackbar({ + message: '신고가 접수되었어요.', + variant: 'top', + onClose: closePopup, + }); + }; if (isWriter) { // 작성자인 경우: 삭제하기만 표시 openMoreMenu({ onDelete: handleDelete, type: 'reply', isWriter: true, onClose: closePopup, }); } else { // 작성자가 아닌 경우: 신고하기만 표시 openMoreMenu({ - onReport: () => { - closePopup(); - openSnackbar({ - message: '신고가 접수되었어요.', - variant: 'top', - onClose: closePopup, - }); - }, + onReport: reportAction, type: 'reply', isWriter: false, onClose: closePopup, }); } };또한, 삭제 실행 시 UX 응답성을 높이려면 API 호출 전에 즉시 팝업을 닫는 것도 고려해볼 수 있습니다(선택).
src/components/common/Modal/MoreMenu.tsx (4)
5-5: MoreMenu 기본값 지정으로 방어적 렌더링
type이 누락되면 reply 브랜치로 떨어지는 문제를 예방하기 위해 기본값을 제안합니다. 또한onClose/isWriter에도 기본값을 지정하면 안정적입니다.-const MoreMenu = ({ onEdit, onDelete, onClose, onReport, isWriter, type }: MoreMenuProps) => { +const MoreMenu = ({ + onEdit, + onDelete, + onClose = () => {}, + onReport, + isWriter = false, + type = 'post', +}: MoreMenuProps) => {
8-47: 분기 UI 자체는 적절. 다만type누락 시 reply로 폴백되는 점 주의위에서 제안한 기본값을 적용하면 안전합니다. 추가로,
isWriter가 true인데onEdit/onDelete가 누락된 경우 무반응이 되니, 개발 단계에서는 콘솔 경고 정도를 남기는 것도 디버깅에 유용합니다(선택).
87-104: Container/ReportContainer 스타일 중복 최소화 제안두 컴포넌트가 거의 동일하며 height만 다릅니다.
BottomSheet컴포넌트 하나에size나heightprop으로 통합하면 유지보수성이 올라갑니다.예시:
-const Container = styled.div` +const BottomSheet = styled.div<{ height: number }>` position: fixed; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; min-width: 320px; max-width: 767px; width: 100%; - height: 141px; + height: ${({ height }) => `${height}px`}; padding: 20px; border-radius: 12px 12px 0px 0px; background-color: ${colors.darkgrey.main}; z-index: 1201; `;사용처:
{isWriter ? ( <BottomSheet height={141} onClick={e => e.stopPropagation()}> ... </BottomSheet> ) : ( <BottomSheet height={90} onClick={e => e.stopPropagation()}> ... </BottomSheet> )}
105-139: 접근성: 클릭 가능한 요소는 button 사용 권장현재
Button이div라 키보드 접근성과 스크린리더 호환성이 떨어집니다.styled.button으로 전환하고 기본 스타일을 제거하는 방식이 안전합니다.-const Button = styled.div<{ variant: 'edit' | 'delete' | 'report' }>` +const Button = styled.button<{ variant: 'edit' | 'delete' | 'report' }>` display: flex; height: 50px; align-items: center; + width: 100%; + text-align: left; + background: transparent; + border: none; + padding: 0; + outline: none; color: ${({ variant }) => { if (variant === 'edit') return colors.white; if (variant === 'delete') return colors.red; if (variant === 'report') return colors.red; return colors.white; }}; font-size: ${typography.fontSize.base}; font-weight: ${typography.fontWeight.semibold}; line-height: 24px; border-bottom: 1px solid ${colors.grey[400]}; cursor: pointer; + &:focus-visible { + box-shadow: 0 0 0 2px ${colors.grey[400]}; + border-radius: 8px; + }
variant === 'report'일 때의 패딩 처리 로직은 그대로 유지하되, 상단의 기본padding: 0;이 있으므로 충돌 없도록 순서만 유의하면 됩니다.src/components/common/Post/Reply.tsx (1)
96-119: 작성자/비작성자 분기 로직 SubReply와 중복 — 공통화 제안동일한 신고 스낵바 처리 로직이 SubReply.tsx와 중복되어 있습니다. 콜백을 공통 함수로 뽑아 중복을 줄이면 유지보수성이 좋아집니다. SubReply에 제안한
reportAction패턴과 동일합니다.또한, 삭제 실행 시에는 API 응답까지 기다리지 않고 메뉴를 먼저 닫는 방식(낙관적 UI)도 고려해볼 수 있습니다(선택).
src/pages/feed/FeedDetailPage.tsx (4)
92-96: onEdit 핸들러가 실질 동작이 없습니다 (navigate 주석 처리).사용자 입장에선 아무 일도 일어나지 않습니다. 라우팅을 아직 못 묶는 상황이라면 최소 토스트라도 노출해 주세요.
아래처럼 임시 스낵바를 노출하거나, 실제 수정 페이지 라우팅이 확정되면 주석을 해제해 주세요.
- onEdit: () => { - closePopup(); - // navigate(`/post/update/${feedId}`); - }, + onEdit: () => { + closePopup(); + // TODO: 피드 수정 페이지 라우트 확정 시 아래 navigate 주석 해제 + // navigate(`/post/update/${feedId}`); + openSnackbar({ + message: '피드 수정은 준비 중이에요.', + variant: 'top', + onClose: closePopup, + }); + },
99-104: 확인 모달을 띄우기 전에 MoreMenu를 닫아 중첩 오버레이를 방지하세요.현재는 MoreMenu가 열린 상태에서 Confirm이 열릴 가능성이 있습니다.
아래처럼 모달을 열기 전에 먼저 closePopup()을 호출하는 걸 권장합니다.
- onDelete: () => { - openConfirm({ + onDelete: () => { + // MoreMenu를 닫고 확인 모달을 띄워 중첩 오버레이 방지 + closePopup(); + openConfirm({
105-108: feedId 누락 시 조용히 return 됩니다 — 사용자 피드백을 추가하세요.에지 케이스지만, 조용히 종료되면 UX에 안 좋습니다. 간단히 스낵바를 노출해 주세요.
- try { - if (!feedId) return; + try { + if (!feedId) { + openSnackbar({ + message: '잘못된 피드 ID입니다.', + variant: 'top', + onClose: closePopup, + }); + return; + } const resp = await deleteFeedPost(Number(feedId));
115-116: 삭제 성공 후 뒤로가기로 삭제된 상세로 되돌아가는 문제를 예방하세요.navigate에 replace: true를 주면 히스토리 상 이전 페이지로 돌아갈 때 삭제된 상세로 복귀하는 일을 줄일 수 있습니다. 또, 스낵바가 페이지 전환 후에도 유지되는지 확인해 주세요(글로벌 레벨 스낵바가 아니라면 onClose에서 navigate하도록 순서를 바꿔야 합니다).
- navigate('/feed', { state: { initialTab: '내 피드' } }); + navigate('/feed', { replace: true, state: { initialTab: '내 피드' } });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
src/api/feeds/getFeedDetail.ts(2 hunks)src/components/common/Modal/MoreMenu.tsx(2 hunks)src/components/common/Post/Reply.tsx(2 hunks)src/components/common/Post/SubReply.tsx(3 hunks)src/pages/feed/FeedDetailPage.tsx(1 hunks)src/stores/usePopupStore.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/components/common/Post/SubReply.tsx (1)
src/hooks/usePopupActions.ts (1)
usePopupActions(9-35)
src/components/common/Post/Reply.tsx (1)
src/hooks/usePopupActions.ts (1)
usePopupActions(9-35)
src/pages/feed/FeedDetailPage.tsx (1)
src/api/feeds/deleteFeedPost.ts (1)
deleteFeedPost(10-13)
src/components/common/Modal/MoreMenu.tsx (2)
src/stores/usePopupStore.ts (1)
MoreMenuProps(14-21)src/styles/global/global.ts (2)
colors(4-53)typography(56-77)
🔇 Additional comments (5)
src/components/common/Post/SubReply.tsx (1)
40-40:openConfirm제거 및 단일 메뉴 플로우로 단순화, 방향성 좋습니다댓글 삭제를 작성자 전용 단일 액션으로 노출하고, 비작성자는 신고만 노출하는 구조가 명확합니다.
usePopupActions사용도 일관적입니다.src/components/common/Post/Reply.tsx (1)
38-38: 팝업 액션 정리 OK
openConfirm의존 제거 및{ openMoreMenu, closePopup, openSnackbar }만 사용하도록 정리한 방향 좋습니다.src/pages/feed/FeedDetailPage.tsx (3)
137-152: 비작성자 신고 플로우 분기와 사용자 피드백 처리 좋습니다.MoreMenu 닫기 → 스낵바 노출의 흐름이 깔끔합니다. API 연동이 추후 예정이라면 이 상태로도 합리적입니다.
101-103: 해결: ‘disc’는 ConfirmModalProps에 정의된 올바른 키입니다.
src/stores/usePopupStore.ts의 ConfirmModalProps에서 설명 텍스트를 위한 프로퍼티 키로disc: string을 사용하도록 정의되어 있으며, 모든openConfirm호출에서도 일관되게disc를 사용하고 있습니다. 따라서 별도의 수정이 필요 없습니다.
107-109: DeleteFeedPostResponse의 isSuccess 보장됨
- 확인 결과,
src/api/feeds/deleteFeedPost.ts의DeleteFeedPostResponse인터페이스에isSuccess: boolean이 명시되어 있어 항상 반환됩니다.- 따라서
resp.isSuccess를 사용하는 현재 로직은 안전하며 추가 검증이 필요 없습니다.
| isWriter?: boolean; | ||
| type?: 'post' | 'reply'; | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
type가 전달되지 않으면 잘못된 UI 브랜치로 렌더링될 수 있음
MoreMenu에서 type === 'post' ? ... : ...로 분기하고 있어 type이 undefined면 자동으로 reply 브랜치로 떨어집니다. 의도치 않은 사용을 막기 위해 아래 중 하나를 권장합니다.
- MoreMenu 컴포넌트 쪽에서
type과isWriter기본값을 지정 - 혹은
MoreMenuProps에서type을 필수로 승격
아래처럼 기본값을 주는 쪽이 안전하고, 기존 호출부에도 영향이 없습니다.
- export interface MoreMenuProps {
+ export interface MoreMenuProps {
onEdit?: () => void;
onDelete?: () => void;
onClose?: () => void;
onReport?: () => void;
- isWriter?: boolean;
- type?: 'post' | 'reply';
+ isWriter?: boolean; // 기본값 false 권장
+ type?: 'post' | 'reply'; // 기본값 'post' 권장
}추가로, 모든 openMoreMenu(...) 호출부에 type/isWriter가 빠진 사용이 없는지 아래 스크립트로 점검해 주세요.
🏁 Script executed:
#!/bin/bash
# openMoreMenu 호출 중 type 누락된 케이스 탐지
rg -nPU '(?s)openMoreMenu\s*\(\s*\{(?![^}]*\btype\s*:)[^}]*\}\s*\)' -C2
# openMoreMenu 호출 중 isWriter 누락된 케이스(의도적으로 false 기본값을 쓸 계획이면 무시 가능)
rg -nPU '(?s)openMoreMenu\s*\(\s*\{(?![^}]*\bisWriter\s*:)[^}]*\}\s*\)' -C2Length of output: 5535
MoreMenuProps 기본값 지정으로 의도치 않은 UI 분기 방지
MoreMenu 컴포넌트에서 type과 isWriter를 디폴트 파라미터로 설정해주세요. 호출부에서 두 속성을 빠뜨려도 올바른 분기가 유지됩니다.
function MoreMenu({
onEdit,
onDelete,
onClose,
onReport,
- isWriter,
- type,
+ isWriter = false,
+ type = 'post',
}: MoreMenuProps) {
…
}검출된 호출부(누락 케이스):
- src/components/memory/RecordItem/RecordItem.tsx (210, 248)
- src/components/common/Post/Reply.tsx (106)
- src/components/common/Post/SubReply.tsx (124)
위 기본값 적용 후 호출부 수정 없이도 의도한 UI가 보장됩니다.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| isWriter?: boolean; | |
| type?: 'post' | 'reply'; | |
| } | |
| function MoreMenu({ | |
| onEdit, | |
| onDelete, | |
| onClose, | |
| onReport, | |
| isWriter = false, | |
| type = 'post', | |
| }: MoreMenuProps) { | |
| … | |
| } |
🤖 Prompt for AI Agents
In src/stores/usePopupStore.ts around lines 19 to 21, the MoreMenuProps
interface marks isWriter and type as optional which leads to unintended UI
branching when callers omit them; update the MoreMenu component to provide
explicit defaults (e.g., isWriter = false and type = 'post') by applying default
parameter values in the component signature or defaultProps so callers listed
(RecordItem, Reply, SubReply) need no changes and the intended UI branches are
preserved.
#️⃣연관된 이슈
없음
📝작업 내용
isWriter 여부에 따라 본인의 더보기 모달인지 다른 사용자의 더보기 모달인지를 파악합니다.
본인 글 더보기 모달인 경우 : 수정하기, 삭제하기 / 다른 사용자 더보기 모달인 경우 : 신고하기
본인 댓글 더보기 모달인 경우 : 삭제하기 / 다른 사용자 더보기 모달인 경우 : 신고하기
(댓글의 경우 y/n로 삭제여부 한번더 물어보지 않음)
💬리뷰 요구사항
없음
Summary by CodeRabbit