-
Notifications
You must be signed in to change notification settings - Fork 1
Feat/#74 카테고리 별 맛집 페이지에서 스와이프로 카테고리 전환 #76
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
Conversation
- 카테고리 별 맛집 페이지에서 스와이프로 카테고리 전환
- prevMapCenter.ts에서 lastMapCenter.ts로 이름 변경
Walkthrough맵 센터 위치 추적 기능을 추가하고 카테고리 선택 시 스와이프 제스처를 구현했습니다. 기존 Changes
Sequence Diagram(s)sequenceDiagram
participant User as 사용자
participant Campus as CampusSelector
participant Store as lastMapCenterStore
participant Map as MapComponent
User->>Campus: 캠퍼스 선택
activate Campus
Campus->>Store: setLastMapCenter(위치)
activate Store
Store->>Map: 상태 업데이트
deactivate Store
Map->>Map: 맵 센터 이동
deactivate Campus
Note over Campus,Map: 사용자가 캠퍼스를 변경하면<br/>해당 위치가 저장되어<br/>맵 페이지에서 복원 가능
sequenceDiagram
participant User as 사용자
participant Place as Places Component
participant Handler as onDragEnd Handler
participant Callback as setIdFunc
User->>Place: 드래그/스와이프
activate Place
Place->>Handler: onDragEnd 호출<br/>(offset, velocity)
activate Handler
Handler->>Handler: 스와이프 파워 계산<br/>threshold 확인
alt 스와이프 감지
Handler->>Callback: 새로운 ID로 호출<br/>(범위: 1-15)
end
deactivate Handler
deactivate Place
Note over Place,Callback: 수평 드래그 제스처로<br/>카테고리 전환 구현
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 추가 검토 필요 영역:
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/app/categories/[id]/CategoryDetailPage.tsx (1)
17-24:window.history.replaceState에null을 전달하면 Next Router 상태가 손상됩니다검증 결과, 현재 코드의 근본 문제는 다음과 같습니다:
window.history.replaceState(null, '', `/categories/${id}`)Next.js App Router는
window.history.state에 내부 라우터 상태를 저장하는데,null을 전달하면 이 상태가 덮어씌워집니다. 그 결과:
usePathname()이 제대로 업데이트되지 않을 수 있음- 브라우저 뒤로가기/앞으로가기 동작이 깨질 수 있음
- 라우터 상태 불일치로 인한 예기치 않은 렌더링 문제 발생
해결 방안 (권장):
useRouter().replace()를 사용하거나,window.history.state를 보존해서 호출합니다:-import { usePathname } from 'next/navigation' +import { usePathname, useRouter } from 'next/navigation' export const CategoryDetailPage = () => { + const router = useRouter() const { data: categories } = useSuspenseQuery(useCategoryQueries.list()) const activeCategoryId = usePathname().split('/')[2] || '0' const setIdFunc = (id: string) => { - window.history.replaceState(null, '', `/categories/${id}`) + router.replace(`/categories/${id}`, { scroll: false }) }이렇게 하면 Next Router 상태와
usePathname()이 동기화되어, 스와이프 시 Places와 RowCategories 모두 올바른 카테고리로 재렌더링됩니다.lines 17-24, 45-52
🧹 Nitpick comments (2)
apps/web/app/categories/[id]/_components/Places/Places.tsx (2)
17-47: 스와이프 ID 증감 로직의 하드코딩된 범위(1~15)와 숫자 변환은 향후 변경에 취약할 수 있습니다
currentCategoryId를Number(id)로 파싱하고, 범위를1~15로 고정해 두어서 카테고리 개수나 ID 스키마가 바뀌면 이 파일만 따로 수정해야 합니다.- 또한 id가 숫자가 아닌 문자열(슬러그 등)로 변경되면
Number(id)가NaN이 되어 비교가 전부 실패하고, 스와이프가 묵살되는 문제가 생길 수 있습니다.카테고리 범위와 타입이 고정이라면 지금도 동작은 맞지만, 유지보수성을 위해서:
- 카테고리 최소/최대 ID를 상수로 선언해 import 하거나, 상위에서 prop으로 전달받는 형태로 magic number(1, 15)를 제거하는 것,
- 혹은
id타입을type CategoryId = '1' | '2' | ...처럼 좁혀 두거나,Number(id)결과가NaN일 때는 조기 return 하는 방어 로직을 고려해 보면 좋겠습니다.
2-3: 스와이프 임계값 미만 드래그 후 리스트가 옆으로 살짝 밀린 채 남지 않는지 확인이 필요합니다
motion.div에drag='x'만 걸려 있고 별도의 제약이나 복귀 애니메이션이 없어서,SWIPE_CONFIDENCE_THRESHOLD(50)를 넘지 못한 짧은 드래그 이후에도 콘텐츠가 약간 좌우로 이동된 상태로 남을 수 있습니다. 그렇게 되면 스와이프에 실패했는데도 리스트가 한쪽으로 치우쳐 보이는 어색한 UX가 나올 수 있습니다.실제 기기에서 한번 확인해 보시고, 문제가 있다면 예를 들어:
dragConstraints로 이동 가능한 범위를 제한하거나,onDragEnd안에서 항상x: 0으로 되돌리는 애니메이션을 트리거하는 방식으로 드래그 실패 시에는 원위치로 자연스럽게 복귀시키는 걸 검토해 보시면 좋겠습니다.
Also applies to: 65-75
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
apps/web/app/_components/CampusSelector/CampusSelector.tsx(1 hunks)apps/web/app/_components/eventBanners/FoodSlotMachineBanner.tsx(1 hunks)apps/web/app/_components/eventBanners/LuckyDrawBanner.tsx(1 hunks)apps/web/app/_store/lastMapCenter.ts(1 hunks)apps/web/app/_store/prevMapCenter.ts(0 hunks)apps/web/app/categories/[id]/CategoryDetailPage.tsx(1 hunks)apps/web/app/categories/[id]/_components/Places/EmptyPlaces.tsx(1 hunks)apps/web/app/categories/[id]/_components/Places/Places.tsx(1 hunks)apps/web/app/categories/template.tsx(0 hunks)apps/web/app/map/MapComponent.tsx(1 hunks)
💤 Files with no reviewable changes (2)
- apps/web/app/categories/template.tsx
- apps/web/app/_store/prevMapCenter.ts
🧰 Additional context used
🧬 Code graph analysis (3)
apps/web/app/categories/[id]/CategoryDetailPage.tsx (1)
apps/web/app/categories/[id]/_components/Places/Places.tsx (1)
Places(17-77)
apps/web/app/_components/CampusSelector/CampusSelector.tsx (3)
apps/web/app/_store/campus.ts (1)
useCampusStore(9-12)apps/web/app/_store/lastMapCenter.ts (1)
useLastMapCenterStore(20-23)apps/web/app/_constants/campus.ts (1)
CAMPUS_LOCATION(9-13)
apps/web/app/categories/[id]/_components/Places/Places.tsx (5)
apps/web/app/_store/campus.ts (1)
useCampusStore(9-12)apps/web/app/_apis/queries/place.ts (1)
usePlaceQueries(27-69)apps/web/app/categories/[id]/_components/Places/EmptyPlaces.tsx (1)
EmptyPlaces(9-103)packages/ui/src/components/Layout/VerticalScrollArea/VerticalScrollArea.tsx (1)
VerticalScrollArea(4-20)apps/web/app/_components/PlaceListItem/PlaceListItem.tsx (1)
PlaceListItem(15-55)
🔇 Additional comments (6)
apps/web/app/_components/eventBanners/LuckyDrawBanner.tsx (1)
23-27: 배너 본문 타이포그래피 조정 일관성 좋습니다.기존 구조는 그대로 두고 폰트 사이즈만 조정하면서 sm 이상에서만 크게 보이도록 처리해, 다른 배너들과의 시각적 일관성이 잘 맞습니다.
apps/web/app/_components/eventBanners/FoodSlotMachineBanner.tsx (1)
22-26: 슬롯머신 배너 텍스트도 LuckyDraw와 일관되게 정리됨폰트 크기/굵기와 반응형 클래스 구성이 LuckyDrawBanner와 동일 패턴이라, 두 이벤트 배너 간 UI 톤이 잘 맞습니다.
apps/web/app/categories/[id]/_components/Places/EmptyPlaces.tsx (1)
80-80: Empty 상태를 화면 전체 기준으로 중앙 정렬하도록 바뀐 점 좋습니다상위가 h-full을 갖는 컨테이너라는 전제에서, auto margin 대신 전체 높이 + justify-center를 쓰는 편이 뷰포트 높이 변화에도 더 안정적으로 동작할 것 같습니다.
apps/web/app/_components/CampusSelector/CampusSelector.tsx (1)
13-31: 캠퍼스 변경 시 맵 센터를 즉시 동기화하는 로직이 요구사항에 잘 맞습니다
isCampusType으로 키를 안전하게 좁힌 뒤setLastMapCenter(CAMPUS_LOCATION[newKey])를 호출해서, 이후 맵 진입 시 선택한 캠퍼스 중심으로 바로 초기화될 수 있게 잘 연결돼 있습니다.setTimeout으로 캠퍼스 상태를 지연 설정하는 기존 패턴과도 충돌 없이 동작할 것으로 보입니다.apps/web/app/map/MapComponent.tsx (1)
7-35: lastMapCenter 스토어 경로 변경으로 구현이 새 스토어와 잘 정합됩니다
useLastMapCenterStore를 새 파일(@/_store/lastMapCenter)에서 불러오되,lastMapCenter || CAMPUS_LOCATION[campus]기본 센터 계산과 언마운트 시setLastMapCenter호출 로직은 그대로라 기존 동작을 그대로 유지하면서 스토어만 교체했습니다.apps/web/app/_store/lastMapCenter.ts (1)
1-23: 지도의 마지막 중심 좌표를 위한 최소한의 Zustand 스토어 설계가 명확합니다
Coord | null을 허용하는 단일 상태와 setter만 노출해서 MapComponent/CampusSelector에서 읽고 쓰기 쉬운 구조입니다. 주석에 주요 사용 시나리오(이탈/복귀, 캠퍼스 변경 시 처리)가 잘 설명돼 있어 다른 개발자가 용도를 이해하기도 좋겠습니다.
#️⃣연관된 이슈
📝작업 내용
1. 카테고리 별 맛집 리스트 스와이프 전환 구현
목적:
모바일 배달 앱(예: 배민)과 유사한 네이티브 사용자 경험을 웹에서도 제공
구현 내용:
motion/react을 사용하여 좌우 드래그 제스처를 감지하고 적용했습니다.2. 캠퍼스 변경 시 지도 중심 좌표 로직 개선
변경 내용:
메인 화면에서 캠퍼스(천안/공주/예산)를 변경할 때, 해당 캠퍼스에 맞는 초기 위치로 지도가 설정되도록 useLastMapCenterStore의 상태 업데이트 로직을 수정했습니다.
효과:
캠퍼스를 변경하고 지도로 진입했을 때, 엉뚱한 위치(이전 마지막 좌표)가 아닌 선택한 캠퍼스의 중심을 바로 보여줍니다.
스크린샷 (선택)
2025-11-24.3.55.03.mov
💬리뷰 요구사항(선택)
Summary by CodeRabbit
릴리스 노트
새로운 기능
스타일
✏️ Tip: You can customize this high-level summary in your review settings.