[FEAT] 인플루언서 추천 피드 - 지현#284
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📋 WalkthroughEmbla Carousel 라이브러리를 도입하고, 새로운 추천 피드 컴포넌트(RecommendedFeedCard, RecommendedFeedSection)를 추가하며, TotalFeed에 10개 게시물마다 추천 피드 섹션을 삽입하는 기능을 구현했습니다. 또한 모의 추천 피드 데이터와 스타일 조정을 추가했습니다. 📊 Changes
🔀 Sequence Diagram(s)sequenceDiagram
participant TotalFeed
participant GroupLoop as Post Grouping Loop
participant FeedPost
participant RecommendedFeedSection
participant RecommendedFeedCard
participant Embla as Embla Carousel
TotalFeed->>GroupLoop: Iterate posts (groups of 10)
loop Every post in current group
GroupLoop->>FeedPost: Render with isLast=false
FeedPost-->>GroupLoop: Rendered
end
rect rgb(230, 240, 255)
Note over GroupLoop,Embla: After every 10 posts
GroupLoop->>RecommendedFeedSection: Insert with sectionIndex
RecommendedFeedSection->>Embla: Configure carousel (center, single-slide)
loop 5 mock feeds
Embla->>RecommendedFeedCard: Render in slide
RecommendedFeedCard-->>Embla: Card rendered
end
Embla-->>RecommendedFeedSection: Carousel ready
end
RecommendedFeedSection-->>TotalFeed: Section inserted
⏱️ Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20-25 minutes 검토 시 주의사항:
🔗 Possibly related issues
🔀 Possibly related PRs
🐰 Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/components/feed/RecommendedFeedSection.tsx (1)
79-83: 슬라이스 로직 단순화 제안wrap-around 로직이 작동하지만, 더 명확하게 작성할 수 있습니다.
다음과 같이 리팩토링을 고려해보세요:
- const startIndex = (sectionIndex * 5) % allMockRecommendedFeeds.length; - const selectedFeeds = [ - ...allMockRecommendedFeeds.slice(startIndex, startIndex + 5), - ...allMockRecommendedFeeds.slice(0, Math.max(0, startIndex + 5 - allMockRecommendedFeeds.length)), - ].slice(0, 5); + const startIndex = (sectionIndex * 5) % allMockRecommendedFeeds.length; + const selectedFeeds = Array.from({ length: 5 }, (_, i) => { + const index = (startIndex + i) % allMockRecommendedFeeds.length; + return allMockRecommendedFeeds[index]; + });이 방식이 wrap-around 의도를 더 명확하게 표현합니다.
src/components/feed/RecommendedFeedCard.tsx (1)
49-58: !important 사용 최소화 고려
!important를 사용하면 스타일 우선순위 관리가 어려워지고 향후 유지보수에 문제가 될 수 있습니다. 가능하다면 더 구체적인 선택자나 styled-components의 전역 스타일 재정의를 고려해보세요.만약
PostBody컴포넌트가 props를 통해 스타일을 커스터마이징할 수 있다면, 그 방식을 사용하는 것이 더 좋습니다. 예:<PostBody {...postData} maxLines={3} lookmoreIcon={lookmoreInfluencer} />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (2)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlsrc/assets/feed/lookmore-influencer.svgis excluded by!**/*.svg
📒 Files selected for processing (6)
package.json(1 hunks)src/components/feed/FeedPost.tsx(1 hunks)src/components/feed/RecommendedFeedCard.tsx(1 hunks)src/components/feed/RecommendedFeedSection.tsx(1 hunks)src/components/feed/TotalFeed.tsx(1 hunks)src/mocks/recommendedFeeds.mock.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/components/feed/TotalFeed.tsx (1)
src/types/post.ts (1)
FeedListProps(21-27)
src/components/feed/RecommendedFeedCard.tsx (2)
src/types/post.ts (1)
PostData(1-19)src/styles/global/global.ts (1)
colors(4-53)
src/mocks/recommendedFeeds.mock.ts (2)
src/types/post.ts (1)
PostData(1-19)src/styles/global/global.ts (1)
colors(4-53)
src/components/feed/RecommendedFeedSection.tsx (2)
src/styles/global/global.ts (2)
colors(4-53)typography(56-77)src/mocks/recommendedFeeds.mock.ts (1)
allMockRecommendedFeeds(9-328)
🔇 Additional comments (6)
package.json (1)
21-22: 캐러셀 라이브러리 추가 확인 완료Embla Carousel 의존성 추가가 적절합니다. 버전 ^8.6.0이 최신 안정 버전인지 확인하시면 좋을 것 같습니다.
src/components/feed/FeedPost.tsx (1)
20-20: 하단 경계선 너비 조정 확인100%로 변경하여 일관된 UI를 제공합니다.
src/components/feed/RecommendedFeedSection.tsx (1)
70-74: Embla 옵션 설정 검토PR 설명에서 요청하신 대로 Embla 옵션을 검토했습니다:
align: 'center': 중앙 정렬로 다음 카드를 부분적으로 보여주는 의도된 UX에 적합합니다.containScroll: 'trimSnaps': 마지막 슬라이드가 중앙에 오지 않도록 스냅 포인트를 조정합니다.모바일 기기에서 터치 및 드래그 동작이 의도대로 작동하는지 테스트하시기 바랍니다.
src/mocks/recommendedFeeds.mock.ts (2)
5-7: MockPostData 인터페이스 확장 적절
PostData를 확장하여aliasColor를 추가한 방식이 타입 안전성을 유지하면서 기능을 확장하고 있습니다.
15-15: 프로덕션 환경에서 placeholder 이미지 교체 필요Mock 데이터에서
https://via.placeholder.com/36을 사용하고 있습니다. 프로덕션 배포 전에 실제 이미지 URL 또는 자체 호스팅 이미지로 교체해야 합니다.src/components/feed/RecommendedFeedCard.tsx (1)
60-62: 북 카드 클릭 비활성화 검증 필요
pointer-events: none을 첫 번째 자식에 적용하여 북 카드 클릭을 비활성화하고 있습니다. 의도한 대로 작동하는지, 그리고 다른 상호작용(예: 링크, 버튼)이 있는 경우 영향을 받지 않는지 확인하세요.
| const handleCardClick = () => { | ||
| window.open(`/feed/${postData.feedId}`, '_blank'); | ||
| }; |
There was a problem hiding this comment.
보안 취약점: window.open에 보안 속성 누락
새 탭에서 링크를 열 때 noopener와 noreferrer 속성이 없으면 tabnabbing 공격에 취약합니다. 새로 열린 페이지가 window.opener를 통해 원본 페이지를 조작할 수 있습니다.
다음과 같이 수정하세요:
const handleCardClick = () => {
- window.open(`/feed/${postData.feedId}`, '_blank');
+ window.open(`/feed/${postData.feedId}`, '_blank', 'noopener,noreferrer');
};또는 React Router의 Link 컴포넌트 사용을 고려하세요:
import { Link } from 'react-router-dom';
// In component:
<Link to={`/feed/${postData.feedId}`} target="_blank" rel="noopener noreferrer">
<CardContainer>
{/* ... */}
</CardContainer>
</Link>🤖 Prompt for AI Agents
In src/components/feed/RecommendedFeedCard.tsx around lines 14-16, the current
window.open call lacks security attributes and is vulnerable to tabnabbing;
modify the click handler to either open the URL via a proper anchor/React Router
Link with target="_blank" and rel="noopener noreferrer", or if you must use
window.open, capture the returned window object and immediately set
newWindow.opener = null and pass "noreferrer" as the third argument to
window.open to prevent the opened page from accessing window.opener and to avoid
leaking the referrer.
| {posts.map((post, index) => ( | ||
| <> | ||
| <FeedPost | ||
| key={`${post.feedId}-${index}`} | ||
| showHeader={showHeader} | ||
| isMyFeed={isTotalFeed} | ||
| isLast={false} | ||
| {...post} | ||
| /> | ||
| {/* 10개마다 추천 섹션 반복 표시 */} | ||
| {(index + 1) % 10 === 0 && ( | ||
| <RecommendedFeedSection sectionIndex={Math.floor((index + 1) / 10) - 1} /> | ||
| )} | ||
| </> | ||
| ))} |
There was a problem hiding this comment.
Fragment에 key 속성 누락
배열 내에서 Fragment를 사용할 때는 key 속성이 필요합니다. React가 각 항목을 올바르게 식별하지 못하면 콘솔 경고가 발생하고 렌더링 성능에 영향을 줄 수 있습니다.
다음과 같이 수정하세요:
- {posts.map((post, index) => (
- <>
+ {posts.map((post, index) => (
+ <React.Fragment key={`${post.feedId}-${index}`}>
<FeedPost
- key={`${post.feedId}-${index}`}
showHeader={showHeader}
isMyFeed={isTotalFeed}
isLast={false}
{...post}
/>
{/* 10개마다 추천 섹션 반복 표시 */}
{(index + 1) % 10 === 0 && (
<RecommendedFeedSection sectionIndex={Math.floor((index + 1) / 10) - 1} />
)}
- </>
+ </React.Fragment>
))}또한 FeedPost의 key는 Fragment로 이동했으므로 제거하세요.
📝 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.
| {posts.map((post, index) => ( | |
| <> | |
| <FeedPost | |
| key={`${post.feedId}-${index}`} | |
| showHeader={showHeader} | |
| isMyFeed={isTotalFeed} | |
| isLast={false} | |
| {...post} | |
| /> | |
| {/* 10개마다 추천 섹션 반복 표시 */} | |
| {(index + 1) % 10 === 0 && ( | |
| <RecommendedFeedSection sectionIndex={Math.floor((index + 1) / 10) - 1} /> | |
| )} | |
| </> | |
| ))} | |
| {posts.map((post, index) => ( | |
| <React.Fragment key={`${post.feedId}-${index}`}> | |
| <FeedPost | |
| showHeader={showHeader} | |
| isMyFeed={isTotalFeed} | |
| isLast={false} | |
| {...post} | |
| /> | |
| {/* 10개마다 추천 섹션 반복 표시 */} | |
| {(index + 1) % 10 === 0 && ( | |
| <RecommendedFeedSection sectionIndex={Math.floor((index + 1) / 10) - 1} /> | |
| )} | |
| </React.Fragment> | |
| ))} |
🤖 Prompt for AI Agents
In src/components/feed/TotalFeed.tsx around lines 16 to 30, the Fragment
wrapping each mapped item is missing a key which causes React warnings; move the
existing key from the FeedPost to the Fragment (e.g. use the same
`${post.feedId}-${index}` value) and remove the key prop from the FeedPost
component so each array child has a unique key on the Fragment instead.
Revert "Merge pull request #284 from THIP-TextHip/feat/influencer"
#️⃣ 연관된 이슈
📝 작업 내용
개요
전체 피드 화면에 "지금 뜨는 추천 글" 섹션을 추가했습니다. 피드 10개마다 인플루언서가 추천하는 게시글 5개를 캐러셀 형태로 보여줍니다.
주요 기능
추천 섹션 레이아웃
캐러셀 구현
Embla Carousel라이브러리를 사용한 수평 스크롤추천 피드 카드
PostHeader,PostBody,PostFooter컴포넌트 재사용lookmore-influencer.svg)-webkit-line-clamp: 3)pointer-events: none)데이터 구조
/src/mocks/recommendedFeeds.mock.ts로 분리구현 파일
신규 생성
src/components/feed/RecommendedFeedCard.tsx- 추천 피드 카드 컴포넌트src/components/feed/RecommendedFeedSection.tsx- 추천 섹션 컨테이너 (캐러셀 포함)src/mocks/recommendedFeeds.mock.ts- 추천 피드 목업 데이터 (15개)수정
src/components/feed/TotalFeed.tsx- 10개마다 추천 섹션 삽입 로직 추가스크린샷 (선택)
2025-10-28.9.17.01.mov
💬리뷰 요구사항(선택)
align: 'center',containScroll: 'trimSnaps')이 모바일에서 자연스러운지 확인 부탁드립니다.Summary by CodeRabbit
새로운 기능
스타일