Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
""" Walkthrough이번 변경 사항에서는 피드 게시글 상세보기 페이지와 댓글(대댓글 포함) UI 컴포넌트가 새롭게 구현되었습니다. 댓글 및 대댓글 데이터 타입이 추가되고, 목업 데이터가 정의되었으며, 상세 페이지 라우트가 생성되었습니다. 일부 컴포넌트의 import 경로와 props가 수정되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant FeedDetailPage
participant FeedPost
participant ReplyList
participant MessageInput
User->>FeedDetailPage: 상세 페이지 접근
FeedDetailPage->>FeedPost: 피드 게시글 렌더링(목업 데이터)
FeedDetailPage->>ReplyList: 댓글 리스트 렌더링(목업 데이터)
User->>MessageInput: 댓글 입력 및 전송
MessageInput->>FeedDetailPage: onSend 콜백 호출
FeedDetailPage->>ReplyList: 댓글 리스트 갱신(예정)
Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (3)
src/components/common/Post/Reply.tsx (3)
39-41: 접근성 개선이 필요합니다.SubReply 컴포넌트와 동일한 접근성 문제가 있습니다. 좋아요 버튼에 적절한 접근성 속성이 필요합니다.
SubReply 컴포넌트에서 제안한 것과 동일한 접근성 개선사항을 적용해주세요.
37-37: "답글작성" 기능 구현이 누락되었습니다.클릭 가능한 스타일이 적용되어 있지만 실제 기능이 없는 상태입니다.
SubReply 컴포넌트와 동일한 문제로, 답글 작성 기능 구현이 필요합니다.
89-89: 하드코딩된 폰트 크기를 수정하세요.SubReply 컴포넌트와 동일한 문제로,
10px이 하드코딩되어 있습니다.- font-size: 10px; + font-size: ${typography.fontSize.xs};
🧹 Nitpick comments (12)
src/components/today-words/MessageInput.tsx (3)
47-47: 빈 메시지 전송 방지 로직이 적절히 추가되었습니다.
trim()사용으로 공백만 있는 메시지도 적절히 차단됩니다. 하지만 코드 중복을 줄이기 위해 검증 로직을 별도 함수로 분리하는 것을 고려해보세요.+ const isValidMessage = () => value.trim() !== ''; + const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => { if (e.key === 'Enter' && !e.shiftKey) { if (isComposing) { return; } - if (value.trim() === '') return; + if (!isValidMessage()) return; e.preventDefault(); onSend(); resetInputHeight(); } }; const handleSendClick = () => { - if (value.trim() === '') return; + if (!isValidMessage()) return; onSend(); resetInputHeight(); };Also applies to: 58-58
50-53: 전송 후 높이 초기화 기능이 추가되었지만 코드 중복이 있습니다.기능은 적절하지만 중복된 로직을 별도 함수로 분리하면 유지보수성이 향상됩니다.
+ const resetInputHeight = () => { + if (inputRef.current) { + inputRef.current.style.height = 'auto'; + } + }; const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => { // ... 기존 로직 onSend(); - if (inputRef.current) { - inputRef.current.style.height = 'auto'; - } + resetInputHeight(); }; const handleSendClick = () => { // ... 기존 로직 onSend(); - if (inputRef.current) { - inputRef.current.style.height = 'auto'; - } + resetInputHeight(); };Also applies to: 60-63
47-47: 한국어 주석의 오타를 수정해주세요."공백 메세지 전송 방지" → "공백 메시지 전송 방지"로 수정해야 합니다.
- if (value.trim() === '') return; // 공백 메세지 전송 방지 + if (value.trim() === '') return; // 공백 메시지 전송 방지Also applies to: 58-58
src/pages/feed/FeedDetailPage.tsx (2)
18-18: 더보기 버튼 기능이 구현되지 않았습니다.현재
handleMoreClick함수가 비어있습니다. 향후 기능 구현이 필요하거나 TODO 주석을 추가하는 것을 고려해보세요.더보기 기능 구현이 필요하시면 도움을 드릴 수 있습니다. 새로운 이슈를 생성하시겠습니까?
47-58: 스타일링에서 일관성 개선이 필요합니다.하드코딩된 배경색(
#121212) 대신 전역 색상 상수를 사용하는 것이 좋겠습니다. 다른 컴포넌트들에서colors.black.main을 사용하고 있습니다.- background-color: #121212; + background-color: ${colors.black.main};그리고
colorsimport를 추가해야 합니다:import styled from '@emotion/styled'; +import { colors } from '@/styles/global/global';src/components/common/Post/ReplyList.tsx (2)
35-36: 반응형 디자인을 위한 최소 너비 검토가 필요합니다.
min-width: 360px가 설정되어 있는데, 이는 작은 모바일 기기에서 가로 스크롤을 유발할 수 있습니다. 320px 또는 더 작은 값으로 조정하는 것을 고려해보세요.- min-width: 360px; + min-width: 320px;
55-56: EmptyState에서도 동일한 최소 너비 이슈가 있습니다.Container와 마찬가지로
min-width: 360px를 더 작은 값으로 조정하는 것이 좋겠습니다.- min-width: 360px; + min-width: 320px;src/data/postData.ts (2)
14-14: 반복되는 텍스트 패턴을 개선해보세요.현재 같은 문장이 13번 반복되어 있습니다. 실제 사용 시나리오를 더 잘 반영하는 다양한 내용으로 구성하거나, 적절한 길이의 자연스러운 텍스트로 대체하는 것이 좋겠습니다.
- '정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.정말 인상 깊게 읽은 책이에요.', + '정말 인상 깊게 읽은 책이에요. 한강 작가의 섬세한 심리 묘사와 독특한 서사 구조가 인상적이었습니다. 특히 주인공의 내적 갈등과 변화 과정이 매우 사실적으로 그려져 있어서 몰입도가 높았어요. 현대 사회의 억압적인 구조와 개인의 자유 의지에 대한 깊이 있는 성찰을 담고 있는 작품이라고 생각합니다.',
23-69: 주석된 댓글 데이터를 활성화하는 것을 고려해보세요.현재 빈 배열로 되어 있어 EmptyState만 표시됩니다. 개발 및 테스트 목적으로 주석된 데이터를 활성화하는 것이 좋겠습니다.
주석을 해제하여 댓글 UI를 테스트할 수 있도록 하시겠습니까?
src/types/post.ts (1)
31-31: ID 타입 일관성을 검토해보세요.
commentId는number타입이고replyCommentId도number타입인데, 다른 곳에서postId는string타입을 사용하고 있습니다. ID 타입을 통일하는 것을 고려해보세요.프로젝트 전체에서 ID 타입 일관성을 위해 모두
string또는number로 통일하는 것이 좋겠습니다.Also applies to: 36-36
src/components/common/Post/SubReply.tsx (2)
37-42: "답글작성" 기능이 아직 구현되지 않았습니다.클릭 가능한 스타일이 적용되어 있지만 실제 기능이 없어 사용자에게 혼란을 줄 수 있습니다.
답글 작성 기능을 구현하거나 임시로 비활성화 상태로 표시하는 것을 권장합니다. 구현이 필요하시면 도움을 드릴 수 있습니다.
109-109: 하드코딩된 폰트 크기를 글로벌 스타일로 통일하세요.
10px이 하드코딩되어 있어 디자인 시스템의 일관성을 해칩니다.- font-size: 10px; + font-size: ${typography.fontSize.xs};또는 더 작은 폰트 크기가 필요하다면 글로벌 스타일에
xxs크기를 추가하는 것을 고려해보세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
src/assets/feed/activeLike.svgis excluded by!**/*.svgsrc/assets/feed/like.svgis excluded by!**/*.svgsrc/assets/feed/replyIcon.svgis excluded by!**/*.svg
📒 Files selected for processing (13)
src/components/common/Post/PostBody.tsx(1 hunks)src/components/common/Post/PostFooter.tsx(1 hunks)src/components/common/Post/Reply.tsx(1 hunks)src/components/common/Post/ReplyList.tsx(1 hunks)src/components/common/Post/SubReply.tsx(1 hunks)src/components/common/TitleHeader.tsx(3 hunks)src/components/feed/FeedPost.tsx(2 hunks)src/components/feed/TotalBar.tsx(0 hunks)src/components/today-words/MessageInput.tsx(2 hunks)src/data/postData.ts(1 hunks)src/pages/feed/FeedDetailPage.tsx(1 hunks)src/pages/index.tsx(2 hunks)src/types/post.ts(1 hunks)
💤 Files with no reviewable changes (1)
- src/components/feed/TotalBar.tsx
🧰 Additional context used
🧬 Code Graph Analysis (6)
src/components/common/Post/ReplyList.tsx (2)
src/types/post.ts (1)
ReplyListProps(55-57)src/styles/global/global.ts (2)
colors(4-53)typography(56-76)
src/pages/feed/FeedDetailPage.tsx (3)
src/components/common/Wrapper.tsx (1)
Wrapper(3-14)src/data/postData.ts (2)
mockFeedPost(5-20)mockCommentList(23-69)src/components/today-words/MessageInput.styled.ts (1)
MessageInput(27-53)
src/data/postData.ts (1)
src/types/post.ts (2)
FeedPostProps(24-27)ReplyDataProps(42-52)
src/components/common/Post/SubReply.tsx (2)
src/types/post.ts (1)
SubReplyDataProps(30-39)src/styles/global/global.ts (2)
colors(4-53)typography(56-76)
src/components/common/Post/Reply.tsx (2)
src/types/post.ts (1)
ReplyDataProps(42-52)src/styles/global/global.ts (2)
colors(4-53)typography(56-76)
src/components/today-words/MessageInput.tsx (1)
src/components/today-words/MessageInput.styled.ts (3)
MessageInput(27-53)InputContainer(4-15)MessageInputWrapper(17-25)
🔇 Additional comments (21)
src/components/common/Post/PostFooter.tsx (1)
4-9: Import 경로 변경이 올바르게 적용되었습니다.컴포넌트가
common/Post/디렉토리로 이동됨에 따라 asset import 경로가 적절히 업데이트되었습니다.src/components/common/Post/PostBody.tsx (1)
3-3: BookInfoCard import 경로가 적절히 업데이트되었습니다.컴포넌트 구조 변경에 따라 BookInfoCard를 feed 디렉토리에서 가져오도록 경로가 올바르게 수정되었습니다.
src/pages/index.tsx (3)
19-19: 새로운 FeedDetailPage 컴포넌트 import가 추가되었습니다.피드 상세보기 페이지 구현을 위한 필수 import입니다.
35-35: 피드 상세보기를 위한 새로운 라우트가 추가되었습니다.
feed/:feedId라우트는 RESTful 패턴을 따르며 피드 상세보기 기능을 위해 적절합니다.
37-37: 팔로워 목록 라우트 경로가 개선되었습니다.
feed/:type에서follow/:type으로 변경하여 라우트 의미가 더 명확해지고 새로운 피드 상세 라우트와의 충돌을 방지합니다.src/components/feed/FeedPost.tsx (2)
2-4: Post 컴포넌트들의 import 경로가 공통 디렉토리로 적절히 변경되었습니다.컴포넌트를
common/Post/디렉토리로 이동시킨 리팩토링이 올바르게 반영되었습니다.
31-31: isMyFeed prop의 boolean 강제 변환이 추가되었습니다.
!!isMyFeed를 사용하여 optional 속성을 명시적으로 boolean으로 변환하는 것은 타입 안전성을 향상시킵니다.src/components/today-words/MessageInput.tsx (1)
14-14: placeholder prop 추가로 재사용성이 향상되었습니다.동적 placeholder 텍스트 지원으로 컴포넌트의 유연성이 개선되었습니다.
src/pages/feed/FeedDetailPage.tsx (2)
1-11: Import 구문들이 잘 구성되었습니다.필요한 모듈들이 적절히 import되어 있고, 경로 별칭(@)을 일관성 있게 사용하고 있습니다.
20-25: 댓글 전송 로직이 잘 구현되었습니다.빈 문자열 전송 방지 로직(
message.trim()체크)과 전송 후 입력 필드 초기화가 적절히 구현되어 있습니다.src/components/common/Post/ReplyList.tsx (1)
7-29: 컴포넌트 로직이 잘 구현되었습니다.조건부 렌더링과 중첩된 댓글 구조가 적절히 처리되어 있고, key prop도 올바르게 설정되어 있습니다.
src/data/postData.ts (1)
5-20: 모킹 데이터가 적절히 구성되었습니다.타입 안전성이 보장되고 있고, 한국어 콘텐츠로 현지화가 잘 되어 있습니다.
src/components/common/TitleHeader.tsx (2)
53-53: rightIcon 타입 정의가 적절합니다.React.ReactNode 타입을 사용하여 유연성을 제공하고 있습니다.
75-85: 조건부 렌더링 로직이 잘 구현되었습니다.rightIcon이 rightButton보다 우선순위를 갖도록 설계되어 있고, 각각의 클릭 핸들러와 스타일링이 적절히 적용되어 있습니다.
src/types/post.ts (3)
21-21: isMyFeed 속성의 optional 변경이 적절합니다.기존 코드와의 호환성을 유지하면서 더 유연한 사용을 가능하게 합니다.
Also applies to: 26-26
30-39: SubReplyDataProps 인터페이스가 잘 설계되었습니다.대댓글에 필요한 모든 필드가 포함되어 있고, 타입이 명확히 정의되어 있습니다.
42-52: ReplyDataProps 인터페이스가 중첩 구조를 잘 지원합니다.댓글과 대댓글의 관계가 명확히 정의되어 있고, 재귀적 구조를 적절히 표현하고 있습니다.
src/components/common/Post/SubReply.tsx (3)
1-8: 임포트 구조가 잘 정의되어 있습니다.React hooks, 스타일링, 타입, 그리고 에셋들이 명확하게 구분되어 임포트되어 있어 좋습니다. 상대 경로 사용도 일관성 있게 적용되었습니다.
10-24: 좋아요 기능의 상태 관리가 올바르게 구현되었습니다.useState를 사용한 로컬 상태 관리와 토글 로직이 정확합니다. 좋아요 상태에 따른 카운트 증감 로직도 적절합니다.
54-114: 스타일링이 일관성 있게 잘 구현되었습니다.글로벌 스타일 시스템을 활용한 색상과 타이포그래피 사용이 적절하며, 플렉스 레이아웃도 올바르게 구성되어 있습니다.
src/components/common/Post/Reply.tsx (1)
1-7: 임포트 구조가 적절합니다.필요한 모든 의존성이 명확하게 임포트되어 있으며, 타입 임포트도 올바르게 분리되어 있습니다.
| return ( | ||
| <Container> | ||
| <ReplyIcon> | ||
| <img src={replyIcon} alt="대댓글" /> | ||
| </ReplyIcon> | ||
| <Content> | ||
| <PostHeader | ||
| profileImgUrl={profileImgUrl} | ||
| userName={userName} | ||
| userTitle={userTitle} | ||
| titleColor={titleColor} | ||
| createdAt={createdAt} | ||
| /> | ||
| <ReplySection> | ||
| <div className="left"> | ||
| <div className="reply">{subreplyContent}</div> | ||
| <div className="sub-reply">답글작성</div> | ||
| </div> | ||
| <div className="right"> | ||
| <img src={liked ? activeLike : like} onClick={handleLike} /> | ||
| <div className="count">{likeCount}</div> | ||
| </div> | ||
| </ReplySection> | ||
| </Content> | ||
| </Container> | ||
| ); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
접근성 개선이 필요합니다.
좋아요 버튼에 접근성 속성이 누락되어 있습니다. 스크린 리더 사용자를 위해 개선이 필요합니다.
다음과 같이 수정하여 접근성을 개선하세요:
- <img src={liked ? activeLike : like} onClick={handleLike} />
+ <img
+ src={liked ? activeLike : like}
+ onClick={handleLike}
+ alt={liked ? "좋아요 취소" : "좋아요"}
+ role="button"
+ tabIndex={0}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ handleLike();
+ }
+ }}
+ />📝 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.
| return ( | |
| <Container> | |
| <ReplyIcon> | |
| <img src={replyIcon} alt="대댓글" /> | |
| </ReplyIcon> | |
| <Content> | |
| <PostHeader | |
| profileImgUrl={profileImgUrl} | |
| userName={userName} | |
| userTitle={userTitle} | |
| titleColor={titleColor} | |
| createdAt={createdAt} | |
| /> | |
| <ReplySection> | |
| <div className="left"> | |
| <div className="reply">{subreplyContent}</div> | |
| <div className="sub-reply">답글작성</div> | |
| </div> | |
| <div className="right"> | |
| <img src={liked ? activeLike : like} onClick={handleLike} /> | |
| <div className="count">{likeCount}</div> | |
| </div> | |
| </ReplySection> | |
| </Content> | |
| </Container> | |
| ); | |
| return ( | |
| <Container> | |
| <ReplyIcon> | |
| <img src={replyIcon} alt="대댓글" /> | |
| </ReplyIcon> | |
| <Content> | |
| <PostHeader | |
| profileImgUrl={profileImgUrl} | |
| userName={userName} | |
| userTitle={userTitle} | |
| titleColor={titleColor} | |
| createdAt={createdAt} | |
| /> | |
| <ReplySection> | |
| <div className="left"> | |
| <div className="reply">{subreplyContent}</div> | |
| <div className="sub-reply">답글작성</div> | |
| </div> | |
| <div className="right"> | |
| <img | |
| src={liked ? activeLike : like} | |
| onClick={handleLike} | |
| alt={liked ? "좋아요 취소" : "좋아요"} | |
| role="button" | |
| tabIndex={0} | |
| onKeyDown={(e) => { | |
| if (e.key === 'Enter' || e.key === ' ') { | |
| e.preventDefault(); | |
| handleLike(); | |
| } | |
| }} | |
| /> | |
| <div className="count">{likeCount}</div> | |
| </div> | |
| </ReplySection> | |
| </Content> | |
| </Container> | |
| ); |
🤖 Prompt for AI Agents
In src/components/common/Post/SubReply.tsx between lines 26 and 51, the like
button image lacks accessibility attributes. To fix this, replace the img
element used as a button with a semantic button element or add role="button" and
tabIndex="0" to make it keyboard accessible. Also, include an aria-label
describing the button's action, such as "좋아요 버튼" or "Like button," and ensure
the onClick handler is preserved for interaction.
| const Container = styled.div` | ||
| display: flex; | ||
| flex-direction: column; | ||
| width: 100%; | ||
| gap: 12px; | ||
| `; | ||
|
|
||
| const ReplySection = styled.div` | ||
| display: flex; | ||
| flex-direction: row; | ||
| justify-content: space-between; | ||
| gap: 20px; | ||
|
|
||
| .left { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 12px; | ||
|
|
||
| .reply { | ||
| color: ${colors.grey[100]}; | ||
| font-size: ${typography.fontSize.sm}; | ||
| font-weight: ${typography.fontWeight.regular}; | ||
| line-height: 20px; | ||
| } | ||
| .sub-reply { | ||
| color: ${colors.grey[300]}; | ||
| font-size: ${typography.fontSize.xs}; | ||
| font-weight: ${typography.fontWeight.semibold}; | ||
| line-height: normal; | ||
| cursor: pointer; | ||
| } | ||
| } | ||
|
|
||
| .right { | ||
| display: flex; | ||
| flex-direction: column; | ||
| cursor: pointer; | ||
|
|
||
| .count { | ||
| text-align: center; | ||
| color: ${colors.grey[100]}; | ||
| font-size: 10px; | ||
| font-weight: ${typography.fontWeight.medium}; | ||
| line-height: normal; | ||
| } | ||
| } | ||
| `; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
스타일 코드가 SubReply와 거의 동일합니다.
두 컴포넌트의 스타일링이 중복되어 유지보수성이 떨어집니다.
공통 스타일을 별도 파일로 분리하거나, 더 나은 방법으로는 하나의 기본 컴포넌트를 만들고 props로 차이점을 처리하는 것을 권장합니다:
// BaseReply.tsx
interface BaseReplyProps {
showReplyIcon?: boolean;
// ... other props
}
const BaseReply = ({ showReplyIcon = false, ...props }: BaseReplyProps) => {
// 공통 로직
return (
<Container>
{showReplyIcon && <ReplyIcon>...</ReplyIcon>}
{/* 공통 렌더링 로직 */}
</Container>
);
};🤖 Prompt for AI Agents
In src/components/common/Post/Reply.tsx between lines 48 and 94, the styling
code for Reply and SubReply components is almost identical, causing duplication
and reducing maintainability. Refactor by extracting the shared styles into a
single base styled component or a separate file, then create one base Reply
component that accepts props to handle the differences in styling or behavior.
This approach centralizes common styles and logic, improving code reuse and ease
of updates.
| const Reply = ({ | ||
| profileImgUrl, | ||
| userName, | ||
| userTitle, | ||
| titleColor, | ||
| createdAt, | ||
| initialLikeCount, | ||
| replyContent, | ||
| }: ReplyDataProps) => { | ||
| const [liked, setLiked] = useState(false); | ||
| const [likeCount, setLikeCount] = useState<number>(initialLikeCount); | ||
| const handleLike = () => { | ||
| setLiked(!liked); | ||
| setLikeCount(prev => (liked ? prev - 1 : prev + 1)); | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Reply와 SubReply 컴포넌트 간 코드 중복이 발생하고 있습니다.
두 컴포넌트가 동일한 상태 관리 로직과 이벤트 핸들러를 가지고 있어 중복 코드가 많습니다.
공통 로직을 커스텀 훅으로 분리하는 것을 권장합니다:
// hooks/useLike.ts
export const useLike = (initialCount: number) => {
const [liked, setLiked] = useState(false);
const [likeCount, setLikeCount] = useState<number>(initialCount);
const handleLike = () => {
setLiked(!liked);
setLikeCount(prev => (liked ? prev - 1 : prev + 1));
};
return { liked, likeCount, handleLike };
};🤖 Prompt for AI Agents
In src/components/common/Post/Reply.tsx around lines 9 to 23, the like state
management and handler logic is duplicated between Reply and SubReply
components. To fix this, extract the like-related state and handleLike function
into a custom hook named useLike that accepts the initial like count and returns
liked, likeCount, and handleLike. Then replace the duplicated state and handler
in both components by using this custom hook to reduce code duplication and
improve maintainability.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/components/feed/BookInfoCard.tsx (1)
52-52: ISBN 타입을 검토해 보세요.ISBN은 일반적으로 문자열 형태(하이픈 포함)로 사용되는 경우가 많습니다. number 타입보다는 string 타입이 더 적절할 수 있습니다.
- isbn: number; + isbn: string;그리고 src/types/post.ts의 PostData 인터페이스도 동일하게 수정해야 합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
src/components/common/Post/PostBody.tsx(3 hunks)src/components/common/Post/PostHeader.tsx(3 hunks)src/components/common/Post/Reply.tsx(1 hunks)src/components/common/Post/SubReply.tsx(1 hunks)src/components/feed/BookInfoCard.tsx(2 hunks)src/components/feed/Profile.tsx(4 hunks)src/data/postData.ts(1 hunks)src/pages/feed/Feed.tsx(1 hunks)src/pages/feed/OtherFeedPage.tsx(1 hunks)src/types/post.ts(2 hunks)
✅ Files skipped from review due to trivial changes (2)
- src/pages/feed/OtherFeedPage.tsx
- src/pages/feed/Feed.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
- src/components/common/Post/PostBody.tsx
- src/components/common/Post/SubReply.tsx
- src/components/common/Post/Reply.tsx
- src/data/postData.ts
- src/components/common/Post/PostHeader.tsx
🔇 Additional comments (7)
src/types/post.ts (3)
4-4: PostData 인터페이스 확장이 적절합니다.userId와 isbn 속성 추가로 사용자 식별과 도서 네비게이션 기능을 지원할 수 있게 되었습니다.
Also applies to: 9-9
23-23: isMyFeed 속성을 optional로 변경한 것이 적절합니다.컴포넌트의 재사용성을 높이고 다양한 컨텍스트에서 유연하게 사용할 수 있게 되었습니다.
Also applies to: 28-29
31-34: PostBodyProps 타입 정의가 효율적입니다.Pick 유틸리티 타입을 사용하여 필요한 속성만 선택적으로 추출한 것이 좋은 설계입니다. 컴포넌트의 관심사를 명확히 분리했습니다.
src/components/feed/BookInfoCard.tsx (1)
1-1: 네비게이션 기능 구현이 잘 되었습니다.useNavigate 훅을 사용한 라우팅 구현이 적절하고, ISBN을 통한 도서 상세 페이지 네비게이션이 직관적입니다.
Also applies to: 55-61, 63-63
src/components/feed/Profile.tsx (3)
1-1: 상태 관리 추가가 적절합니다.내부 상태로 팔로우 여부를 관리하는 것이 컴포넌트의 독립성을 높입니다.
Also applies to: 19-19
44-46: 동적 텍스트 표시가 잘 구현되었습니다.상태에 따른 버튼 텍스트 변경이 직관적이고 사용자 경험을 개선합니다.
115-115: 커서 스타일 추가가 적절합니다.클릭 가능한 요소임을 명확히 표시하여 사용자 경험을 개선했습니다.
| const toggleFollow = () => { | ||
| if (followed) { | ||
| // await axios.delete(`/api/unfollow/${userName}`); | ||
| } else { | ||
| // await axios.post(`/api/follow/${userName}`); | ||
| } | ||
| setFollowed(prev => !prev); | ||
| console.log(`${userName} - ${followed ? '띱 취소' : '띱 요청'}`); | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
toggleFollow 함수의 비동기 처리를 개선해 보세요.
현재 주석 처리된 API 호출 부분에서 몇 가지 개선점이 있습니다:
- 에러 처리 부족: API 호출 실패 시 상태 롤백이 필요합니다.
- 로딩 상태 관리: 요청 중 중복 클릭을 방지해야 합니다.
- 상태 업데이트 순서: API 응답 후 상태를 업데이트하는 것이 안전합니다.
const toggleFollow = async () => {
+ const prevFollowed = followed;
+ setFollowed(prev => !prev); // 낙관적 업데이트
+
try {
if (followed) {
- // await axios.delete(`/api/unfollow/${userName}`);
+ await axios.delete(`/api/unfollow/${userName}`);
} else {
- // await axios.post(`/api/follow/${userName}`);
+ await axios.post(`/api/follow/${userName}`);
}
- setFollowed(prev => !prev);
console.log(`${userName} - ${followed ? '띱 취소' : '띱 요청'}`);
+ } catch (error) {
+ // 실패 시 상태 롤백
+ setFollowed(prevFollowed);
+ console.error('팔로우 상태 변경 실패:', error);
+ }
};📝 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.
| const toggleFollow = () => { | |
| if (followed) { | |
| // await axios.delete(`/api/unfollow/${userName}`); | |
| } else { | |
| // await axios.post(`/api/follow/${userName}`); | |
| } | |
| setFollowed(prev => !prev); | |
| console.log(`${userName} - ${followed ? '띱 취소' : '띱 요청'}`); | |
| }; | |
| const toggleFollow = async () => { | |
| const prevFollowed = followed; | |
| setFollowed(prev => !prev); // 낙관적 업데이트 | |
| try { | |
| if (followed) { | |
| await axios.delete(`/api/unfollow/${userName}`); | |
| } else { | |
| await axios.post(`/api/follow/${userName}`); | |
| } | |
| console.log(`${userName} - ${followed ? '띱 취소' : '띱 요청'}`); | |
| } catch (error) { | |
| // 실패 시 상태 롤백 | |
| setFollowed(prevFollowed); | |
| console.error('팔로우 상태 변경 실패:', error); | |
| } | |
| }; |
🤖 Prompt for AI Agents
In src/components/feed/Profile.tsx lines 21 to 29, the toggleFollow function
lacks proper async handling for the API calls. To fix this, make toggleFollow an
async function, add try-catch blocks to handle errors and rollback the followed
state if the API call fails, introduce a loading state to prevent multiple
clicks during the request, and update the followed state only after a successful
API response.
| // 대댓글(SubReply) | ||
| export interface SubReplyDataProps { | ||
| replyCommentId: number; | ||
| profileImgUrl: string; | ||
| userName: string; | ||
| userId: number; | ||
| userTitle: string; | ||
| titleColor: string; | ||
| createdAt: string; | ||
| subreplyContent: string; | ||
| initialLikeCount: number; | ||
| } | ||
|
|
||
| // 댓글(Reply) | ||
| export interface ReplyDataProps { | ||
| commentId: number; | ||
| profileImgUrl: string; | ||
| userName: string; | ||
| userId: number; | ||
| userTitle: string; | ||
| titleColor: string; | ||
| createdAt: string; | ||
| replyContent: string; | ||
| initialLikeCount: number; | ||
| replyCommentList: SubReplyDataProps[]; | ||
| } | ||
|
|
||
| // ReplyList Props | ||
| export interface ReplyListProps { | ||
| commentList: ReplyDataProps[]; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
댓글/대댓글 구조 설계를 개선해 보세요.
현재 구조에서 몇 가지 개선점이 있습니다:
- 일관성 부족: SubReplyDataProps와 ReplyDataProps에서 공통 속성들(profileImgUrl, userName, userId 등)이 중복됩니다.
- 네이밍 불일치:
subreplyContent와replyContent의 명명 규칙이 일관되지 않습니다. - 확장성 부족: 대댓글의 대댓글은 지원하지 않는 구조입니다.
다음과 같이 개선해 보세요:
+// 공통 사용자 정보 인터페이스
+export interface UserInfo {
+ profileImgUrl: string;
+ userName: string;
+ userId: number;
+ userTitle: string;
+ titleColor: string;
+}
+
+// 공통 댓글 속성
+export interface BaseComment {
+ id: number;
+ content: string;
+ createdAt: string;
+ initialLikeCount: number;
+ user: UserInfo;
+}
+
+// 대댓글
+export interface SubReplyDataProps extends BaseComment {
+ parentCommentId: number;
+}
+
+// 댓글
+export interface ReplyDataProps extends BaseComment {
+ replies: SubReplyDataProps[];
+}
-// 대댓글(SubReply)
-export interface SubReplyDataProps {
- replyCommentId: number;
- profileImgUrl: string;
- userName: string;
- userId: number;
- userTitle: string;
- titleColor: string;
- createdAt: string;
- subreplyContent: string;
- initialLikeCount: number;
-}
-
-// 댓글(Reply)
-export interface ReplyDataProps {
- commentId: number;
- profileImgUrl: string;
- userName: string;
- userId: number;
- userTitle: string;
- titleColor: string;
- createdAt: string;
- replyContent: string;
- initialLikeCount: number;
- replyCommentList: SubReplyDataProps[];
-}📝 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.
| // 대댓글(SubReply) | |
| export interface SubReplyDataProps { | |
| replyCommentId: number; | |
| profileImgUrl: string; | |
| userName: string; | |
| userId: number; | |
| userTitle: string; | |
| titleColor: string; | |
| createdAt: string; | |
| subreplyContent: string; | |
| initialLikeCount: number; | |
| } | |
| // 댓글(Reply) | |
| export interface ReplyDataProps { | |
| commentId: number; | |
| profileImgUrl: string; | |
| userName: string; | |
| userId: number; | |
| userTitle: string; | |
| titleColor: string; | |
| createdAt: string; | |
| replyContent: string; | |
| initialLikeCount: number; | |
| replyCommentList: SubReplyDataProps[]; | |
| } | |
| // ReplyList Props | |
| export interface ReplyListProps { | |
| commentList: ReplyDataProps[]; | |
| } | |
| // 공통 사용자 정보 인터페이스 | |
| export interface UserInfo { | |
| profileImgUrl: string; | |
| userName: string; | |
| userId: number; | |
| userTitle: string; | |
| titleColor: string; | |
| } | |
| // 공통 댓글 속성 | |
| export interface BaseComment { | |
| id: number; | |
| content: string; | |
| createdAt: string; | |
| initialLikeCount: number; | |
| user: UserInfo; | |
| } | |
| // 대댓글 | |
| export interface SubReplyDataProps extends BaseComment { | |
| parentCommentId: number; | |
| } | |
| // 댓글 | |
| export interface ReplyDataProps extends BaseComment { | |
| replies: SubReplyDataProps[]; | |
| } | |
| // ReplyList Props | |
| export interface ReplyListProps { | |
| commentList: ReplyDataProps[]; | |
| } |
🤖 Prompt for AI Agents
In src/types/post.ts between lines 36 and 66, the current ReplyDataProps and
SubReplyDataProps interfaces have duplicated common fields, inconsistent naming
for content properties, and do not support nested replies beyond one level.
Refactor by creating a base interface for shared properties, unify the content
property name across all reply levels, and modify the structure to allow
recursive nesting of replies to support replies of replies. This will improve
consistency, reduce duplication, and enhance extensibility.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/components/common/ScrollToTop.tsx (1)
3-13: 주석 처리된 코드 정리 및 사용자 경험 개선을 고려해보세요.컴포넌트의 핵심 기능은 올바르게 구현되었습니다. 다음 개선사항을 제안합니다:
- 주석 처리된 코드를 제거하거나 실제로 사용할지 결정해주세요.
- 부드러운 스크롤 효과를 위해
behavior: 'smooth'옵션을 고려해보세요.다음과 같이 개선할 수 있습니다:
useEffect(() => { window.scrollTo({ top: 0, - // left: 0, - // behavior: 'smooth', + behavior: 'smooth', }); }, []);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/common/ScrollToTop.tsx(1 hunks)src/pages/index.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/pages/index.tsx
🔇 Additional comments (2)
src/components/common/ScrollToTop.tsx (2)
1-2: Import문이 정확합니다.React의 useEffect 훅을 올바르게 import하고 있습니다.
15-15: Export 구문이 적절합니다.표준적인 React 컴포넌트 default export 패턴을 따르고 있습니다.
#️⃣연관된 이슈
close #33 [UI] 피드 글 상세보기 페이지
📝작업 내용
2. postHeader.tsx type 추가(피드 글 헤더에 올 때의 사이즈와 댓글에 올 때의 사이즈가 달라서 type으로 조건부 스타일링이 가능하게 함)
3. 댓글(Reply.tsx) 및 답글(SubReply.tsx) 컴포넌트 추가
5. 피드 글 상세보기 페이지(FeedDetailPage.tsx) 추가
6. MessageInput.tsx 로직 추가 - 빈 문자열 전송 제한 - 메세지 전송 후 textarea 높이 초기화 - placeholder props로 변경 (동적으로 사용)
7. 페이지 이동할 때 스크롤 위치 0으로 초기화 추가
💬리뷰 요구사항
스크롤 바 숨김처리는 전역으로 두는 것보다 필요한 부분에서만 속성쓰는게 나을거같다는 생각도 드는데 어떻게 생각하시나요?
전역으로 했더니 전체 브라우저 body의 스크롤바도 사라져서 좀 곤란하네요...
스크롤 바를 없애는 공통 styled 컴포넌트만 따로 뺄까도 생각해봤는데 그게 괜찮으려나요?
Summary by CodeRabbit
Summary by CodeRabbit
신규 기능
개선 사항
버그 수정
데이터
타입
라우팅