[feature] 메인 배너 클릭, 페이지네이션 추가 및 Swiper 마이그레이션#788
Conversation
원인: setIsReady(false) 호출 직후에도 isReady는 여전히 true 결과: 복구 로직(if (!isReady)) 실행 안 됨 → 배너 멈춤 해결: 리사이즈는 단순히 레이아웃 변경이므로 상태 리셋 불필요
- 커스텀 슬라이더 로직을 Swiper로 교체 - 복잡한 상태 관리 및 애니메이션 로직 제거 - 기존 기능(무한 루프, 자동재생, 네비게이션) 동일하게 유지
- useDevice 커스텀 훅을 적용하여 Banner 컴포넌트 내의 화면 크기 감지 로직 제거
- 내부 경로는 React Router navigate로 라우팅 - 외부 HTTPS 링크는 새 탭에서 안전하게 열기 (noopener, noreferrer)
배너 이미지 리스트에 linkTo 속성을 추가하여 클릭 시 이동할 경로 지정
- useNavigator 훅 import 및 적용 - handleBannerClick 함수 구현 (linkTo 기반 페이지 이동) - BannerItem에 onClick 이벤트 및 isClickable prop 추가 - linkTo 존재 여부에 따른 조건부 클릭 처리
- 데스크탑: dot 형태 페이지네이션 - 모바일: 숫자형 페이지네이션 (1/5)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Change summary |
|---|---|
배너 데이터: 링크 필드 추가frontend/src/constants/banners.ts |
데스크톱/모바일 배너 아이템에 linkTo: '/introduce' 필드 추가. |
네비게이션 훅 도입frontend/src/hooks/useNavigator.ts |
useNavigator 훅 추가. handleLink로 공백 제거·빈 값 무시, https:// 외부 URL은 window.open, 그 외는 useNavigate로 내부 라우팅. (default export) |
배너 컴포넌트 — Swiper 전환 및 클릭 처리frontend/src/pages/MainPage/components/Banner/Banner.tsx, frontend/src/pages/MainPage/components/Banner/Banner.styles.ts |
커스텀 슬라이드 로직 제거 후 Swiper(Autoplay, Navigation) 사용으로 전환. BannerProps에 선택적 linkTo 추가, 배너 클릭 시 useNavigator 사용. 모바일은 숫자 페이지네이션, 데스크톱은 도트 페이지네이션으로 렌더. 스타일은 media 유틸 적용, BannerItem에 isClickable prop 추가, NumericPagination, DotPagination, Dot 컴포넌트 추가 및 SlideButton/버튼 포인터 이벤트 조정. |
Sequence Diagram(s)
sequenceDiagram
autonumber
actor U as 사용자
participant B as Banner (SwiperSlide)
participant H as useNavigator.handleLink
participant R as React Router (navigate)
participant W as window.open
U->>B: 배너 클릭
B->>H: handleLink(linkTo)
alt 외부 URL (https://...)
H->>W: window.open(url, "_blank")
else 내부 경로
H->>R: navigate(url)
end
sequenceDiagram
autonumber
actor U as 사용자
participant BtnP as Prev 버튼
participant BtnN as Next 버튼
participant S as Swiper 인스턴스
U->>BtnP: 클릭
BtnP->>S: slidePrev()
U->>BtnN: 클릭
BtnN->>S: slideNext()
S-->>S: onSlideChange -> currentIndex 갱신
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
- 주의할 파일/영역:
Banner.tsx— Swiper 이벤트(onSwiper, onSlideChange) 및 swiperInstance 관리useNavigator.ts— 외부/내부 링크 판별 로직Banner.styles.ts— media 유틸 적용, 포인터 이벤트/페이지네이션 새 컴포넌트 확인
Possibly related PRs
- [fix] 모바일 환경에서 배너 슬라이드 초기 렌더링 문제 해결 #381 — 기존 수동 배너 슬라이드 로직을 Swiper로 대체하는 PR과 중복/직접 관련.
- [feature]상세페이지에 동아리 추천 추가 #665 — Swiper 의존성 및 CSS를 도입하는 PR로 Swiper 사용을 가능하게 하는 변경과 연관.
- [feature] 소개페이지 임시 이미지로 대체 및 메뉴바 구현 #366 —
/introduce라우트 및 네비게이션 처리 추가 PR로 배너linkTo: '/introduce'와 밀접하게 연동됨.
Suggested reviewers
- lepitaaar
- seongje973
- seongwon030
Pre-merge checks and finishing touches
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | PR 제목은 주요 변경사항을 명확하게 요약하고 있습니다: 배너 클릭 기능 추가, 페이지네이션 추가, Swiper 마이그레이션이라는 핵심 내용을 간결하게 표현했습니다. |
| Linked Issues check | ✅ Passed | 변경사항이 MOA-287 요구사항을 완전히 충족합니다: 배너 클릭 기능이 구현되었고, useNavigator 훅으로 내부/외부 링크를 자동 판별하여 처리하며, banners.ts에 linkTo 필드를 추가하여 배너별 링크 설정이 가능합니다. |
| Out of Scope Changes check | ✅ Passed | 모든 변경사항이 MOA-287의 배너 클릭 기능 구현 범위 내에 있습니다. Swiper 마이그레이션, 페이지네이션, useNavigator 훅 등은 모두 배너 기능 개선을 위한 필수 지원 작업입니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
✨ Finishing touches
- 📝 Generate docstrings
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
feat/#782-mainpage-banner-click-MOA-287
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 @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (5)
frontend/src/constants/banners.ts (1)
31-31: 이름 혼동 가능:SlideButton(상수) vsStyled.SlideButton(컴포넌트).가독성/오해 방지를 위해 상수명을 변경하는 것을 권장합니다.
-export const SlideButton = [PrevButton, NextButton]; +export const SlideButtonIcons = [PrevButton, NextButton];Banner.tsx의 import도 함께 변경 필요:
-import { SlideButton } from '@/constants/banners'; +import { SlideButtonIcons as SlideButton } from '@/constants/banners';frontend/src/hooks/useNavigator.ts (1)
2-2: React Router v7 가이드에 맞춘 import 정리(선택).v7에서는
react-router로의 직접 import를 권장합니다. 현재는 re-export라 동작하나, 점진적 이전을 고려해보세요.Based on learnings
frontend/src/pages/MainPage/components/Banner/Banner.tsx (3)
59-64: 매직 넘버 상수화.autoplay delay(3000), speed(500)을 명명 상수로 추출하세요.
As per coding guidelines
- autoplay={{ - delay: 3000, - disableOnInteraction: false, - }} - speed={500} + autoplay={{ + delay: AUTOPLAY_DELAY_MS, + disableOnInteraction: false, + }} + speed={SLIDE_SPEED_MS}파일 상단(컴포넌트 위) 등에 추가:
const AUTOPLAY_DELAY_MS = 3000; const SLIDE_SPEED_MS = 500;
3-3: 불필요한 Swiper 모듈 제거(선택).기본 네비게이션 UI는 사용하지 않고 인스턴스 메서드로 제어하므로 Navigation 모듈이 불필요해 보입니다. 번들 최적화를 위해 제거를 고려하세요.
-import { Navigation, Autoplay } from 'swiper/modules'; +import { Autoplay } from 'swiper/modules';- modules={[Navigation, Autoplay]} + modules={[Autoplay]}Also applies to: 55-55
71-71: 배너 이미지 대체 텍스트 구체화(선택).
banner-{index}는 정보가 부족합니다. 배너 목적(예: "서비스 소개 페이지 이동")에 맞게 alt를 구체화하거나 장식적 이미지면 빈 문자열로 처리하세요.
📜 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)
frontend/src/assets/images/icons/next_button_icon.svgis excluded by!**/*.svgfrontend/src/assets/images/icons/prev_button_icon.svgis excluded by!**/*.svg
📒 Files selected for processing (4)
frontend/src/constants/banners.ts(1 hunks)frontend/src/hooks/useNavigator.ts(1 hunks)frontend/src/pages/MainPage/components/Banner/Banner.styles.ts(5 hunks)frontend/src/pages/MainPage/components/Banner/Banner.tsx(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx}: Replace magic numbers with named constants for clarity.
Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Assign complex boolean conditions to named variables.
Use consistent return types for similar functions and hooks.
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Define constants near related logic or ensure names link them clearly.
Files:
frontend/src/hooks/useNavigator.tsfrontend/src/pages/MainPage/components/Banner/Banner.styles.tsfrontend/src/constants/banners.tsfrontend/src/pages/MainPage/components/Banner/Banner.tsx
frontend/**/*.tsx
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.tsx: Abstract complex logic/interactions into dedicated components or higher-order components (HOCs).
Separate significantly different conditional UI/logic into distinct components.
Colocate simple, localized logic or use inline definitions to reduce context switching.
Choose field-level or form-level cohesion based on form requirements.
Break down broad state management into smaller, focused hooks or contexts.
Use component composition instead of props drilling.
Files:
frontend/src/pages/MainPage/components/Banner/Banner.tsx
🧬 Code graph analysis (2)
frontend/src/pages/MainPage/components/Banner/Banner.styles.ts (1)
frontend/src/styles/mediaQuery.ts (1)
media(8-14)
frontend/src/pages/MainPage/components/Banner/Banner.tsx (2)
frontend/src/pages/MainPage/components/Banner/Banner.styles.ts (1)
SlideButton(63-85)frontend/src/constants/banners.ts (1)
SlideButton(31-31)
🔇 Additional comments (1)
frontend/src/pages/MainPage/components/Banner/Banner.tsx (1)
2-4: Swiper CSS import 확인 필요.전역 또는 이 컴포넌트에서
import 'swiper/css'가 누락되면 기본 스타일이 적용되지 않습니다. 프로젝트 내 어디엔가 포함되어 있는지 확인 부탁드립니다.
seongwon030
left a comment
There was a problem hiding this comment.
와 확실히 라이브러리를 사용하니까 코드양이 많이 줄어드네요. 라이브러리를 사용했을때의 성능 최적화는 어떤 방식으로 할 수 있을지 생각해봐도 좋을 것 같습니다.
초반 캐러셀 구현할 때 직접 구현해보고 싶은 마음에 코드가 길어져도 감수했던 것 같습니다.
지금 저희는 비즈니스적인 문제도 고려할 필요가 있는 것 같아요. 스프린트를 정하고 그 안에 수행해야 하는 일이 있는데 개인적인 기술적 성장보단 팀 자체의 능률이 중요해진 것 같네요. 역량이 부족하다면 작업단위를 줄이는 방향이 더 맞는 것 같습니다..!
suhyun113
left a comment
There was a problem hiding this comment.
헉 배너 도트 추가되면 좋겠다고 생각하고 있었는데! 좋아요!
너무 수고하셨습니다ㅏ
저는 Swiper를 사용한거 좋다고 생각해요. 준서님께서 충분히 고민해보고 코드 복잡도를 해결하기 위해 도입하신거 같아서 좋은 것 같습니다ㅏ 안그래도 배너에서 자잘한 오류들이 있었는데, 클릭 이벤트까지 추가해야하니 적절한 선택인 것 같습니다!
라이브러리 도입 기준이 있다면 좋을 것 같네요! 저는 음... 준서님처럼 타당한 이유를 이야기하고 사용한다면 좋을 것 같아요! PR을 읽으면서 이해도 되고, 좋은 것 같아요.
아 단지, 팀 차원의 기준을 정하기로 한다면 라이브러리 도입 전에 같이 이야기해봐도 좋을 것 같아요!
Discussions을 활용한다면 라이브러리 도입 기준 관련된 곳에서 토의하는 것은 어떨까요?
수현님 |
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
frontend/src/pages/MainPage/components/Banner/Banner.styles.ts (2)
2-2: 순환 의존성 여전히 존재.이전 리뷰에서 지적된 순환 의존성 문제가 해결되지 않았습니다.
BannerProps를 런타임 임포트하면Banner.tsx와 순환 참조가 발생합니다.해결 방법:
-import { BannerProps } from './Banner'; +import type { BannerProps } from './Banner';또는 Line 21의
BannerWrapper에서 실제로 props를 사용하지 않으므로 제네릭 제거:-export const BannerWrapper = styled.div<BannerProps>` +export const BannerWrapper = styled.div`
96-96: 잘못된 CSS 값:font-weight: medium.이전 리뷰에서 지적된 이슈가 수정되지 않았습니다.
font-weight: medium은 유효하지 않은 CSS 값입니다.- font-size: 11px; - font-weight: medium; + font-size: 11px; + font-weight: 500;
🧹 Nitpick comments (1)
frontend/src/pages/MainPage/components/Banner/Banner.styles.ts (1)
86-116: 매직 넘버를 상수로 추출하는 것을 고려해보세요.페이지네이션 컴포넌트들에 여러 매직 넘버가 사용되고 있습니다(예:
bottom: 17px,right: -10px,gap: 6px,width: 8px등). 코딩 가이드라인에 따라 이러한 값들을 명명된 상수로 추출하면 유지보수성이 향상됩니다.예시:
const PAGINATION_SPACING = { NUMERIC_BOTTOM: 17, NUMERIC_RIGHT: -10, DOT_BOTTOM: 20, DOT_GAP: 6, DOT_SIZE: 8, } as const;적용:
export const NumericPagination = styled.div` bottom: ${PAGINATION_SPACING.NUMERIC_BOTTOM}px; right: ${PAGINATION_SPACING.NUMERIC_RIGHT}px; // ... `;
📜 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 selected for processing (1)
frontend/src/pages/MainPage/components/Banner/Banner.styles.ts(5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx}: Replace magic numbers with named constants for clarity.
Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Assign complex boolean conditions to named variables.
Use consistent return types for similar functions and hooks.
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Define constants near related logic or ensure names link them clearly.
Files:
frontend/src/pages/MainPage/components/Banner/Banner.styles.ts
🧠 Learnings (1)
📚 Learning: 2025-07-19T05:09:10.702Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.{ts,tsx} : Replace magic numbers with named constants for clarity.
Applied to files:
frontend/src/pages/MainPage/components/Banner/Banner.styles.ts
🧬 Code graph analysis (1)
frontend/src/pages/MainPage/components/Banner/Banner.styles.ts (1)
frontend/src/styles/mediaQuery.ts (1)
media(8-14)
🔇 Additional comments (4)
frontend/src/pages/MainPage/components/Banner/Banner.styles.ts (4)
3-3: 미디어 쿼리 유틸리티 도입 잘 했습니다.중앙화된
mediaQuery유틸리티를 사용하여 하드코딩된 브레이크포인트를 제거한 점이 좋습니다. 유지보수성이 향상되고 일관성 있는 반응형 디자인을 보장합니다.Also applies to: 15-18, 31-35, 77-83
38-48: 클릭 가능 상태 표시가 올바르게 구현되었습니다.
isClickableprop을 통해 커서 스타일을 조건부로 적용하여 사용자에게 명확한 인터랙션 피드백을 제공합니다.
58-59: 포인터 이벤트 처리가 적절합니다.컨테이너에서
pointer-events: none을 설정하고 버튼에서pointer-events: auto를 활성화하여 중첩된 인터랙티브 요소의 이벤트 전파를 올바르게 제어했습니다. 반응형 스타일 조정도 적절합니다.Also applies to: 62-84
100-116: 페이지네이션 컴포넌트 구현이 깔끔합니다.데스크톱용 도트 페이지네이션과 모바일용 숫자 페이지네이션을 명확하게 분리하여 구현했습니다. 활성 상태 전환 애니메이션도 부드럽게 적용되어 좋은 사용자 경험을 제공합니다.
#️⃣연관된 이슈
📝작업 내용
👉 Preview 배포 확인하기
1️⃣ Swiper 라이브러리로 배너 마이그레이션 cfd9018
해결 방법
추가 개선
2️⃣ useNavigator 커스텀 훅 추가 bbaa725
도입 배경
해결 방법
장점
react-router-dom의navigate직접 사용 불필요💡💡 앞으로 내외부 링크 처리가 필요한 경우 이 훅을 사용해주세요!💡💡
3️⃣ 이전 / 다음 버튼 아이콘을 변경 0c02310
4️⃣ 배너 클릭 기능 추가 3e1c7d7
외부 링크or내부 링크로 페이지 이동5️⃣ 페이지네이션 추가 ed50294
모바일
데스크톱
중점적으로 리뷰받고 싶은 부분(선택)
피드백, 궁금증, 칭찬 환영합니다~
논의하고 싶은 부분(선택)
라이브러리 도입 기준에 대해
처음에는 직접 구현했는데 요구사항(무한 루프, 자동 재생, 모바일 스와이프, 페이지네이션 등)이 추가되면서 코드가 너어무 복잡해졌습니다. 물론 극한의 추상화를 진행하면 어느정도 해결할 수 있을 것 같긴해요
Swiper는 loop={true} 한 줄로 무한 루프가 해결되는 걸 보고... 지금까지 작업한 게 아깝기도 했지만 도입했습니다.
선택 이유
다른 분들의 의견이 듣고 싶습니다.
생각나는 게 있으면 가볍게 남겨주세요~ 안 남겨도 괜찮습니다! 👍
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선 사항