Skip to content

✨ Feat: course result 페이지 및 지도 페이지 구현#64

Merged
skyblue1232 merged 10 commits intodevelopfrom
feat/#61/course-result
Nov 3, 2025
Merged

✨ Feat: course result 페이지 및 지도 페이지 구현#64
skyblue1232 merged 10 commits intodevelopfrom
feat/#61/course-result

Conversation

@skyblue1232
Copy link
Copy Markdown
Contributor

@skyblue1232 skyblue1232 commented Oct 26, 2025

🔥 작업 내용

  • 코스 추천 결과 페이지 (/map/result) 신규 구현

    • CourseResultPage 생성 및 리스트 / 지도 뷰 전환 기능 추가
    • ResultList, ResultMap, FullMap, TagGroup 등 기능별 컴포넌트로 분리하여 구조화
    • localStorage 기반 팝업 노출 (seenCoursePopup) 로직 추가
    • BottomNav, ControlBar 등 공통 컴포넌트 연동 완료
  • 카카오 지도 기능 통합

    • useKakaoMap 커스텀 훅 생성 → loadKakaoSdk 유틸 함수로 SDK 로딩 분리
    • kakao.d.ts 타입 선언 추가로 전역 타입 안정성 확보
    • 마커, InfoWindow, 클릭 이벤트 처리 로직 추가
    • MAP_LOCATIONS 상수 분리로 mock 데이터 기반 위치 표시
  • UI 및 접근성 개선

    • 스크롤바 제거(no-scrollbar), 모바일 뷰 기준 레이아웃 정리
    • TagGroup에서 뷰 전환 버튼(지도로 보기 / 리스트로 보기) UX 개선
    • 코드 전반에 Tailwind 기반 스타일 통일 (rounded-[2rem], overflow-hidden 등)

🤔 추후 작업 사항

  • 장소 데이터 API 연동 (mock → 서버 데이터 교체)
  • 리스트 아이템 클릭 시 지도 마커 하이라이트 기능 추가
  • 지도 뷰 확대/축소 및 사용자 위치 기반 탐색 기능 확장
  • 공동 카카오 디벨로퍼 계정으로 맵 허용 설정해주시면 알려주신다고 하셔서, 완료되면 맵 연결되는지 추가로 테스트할 예정입니다

🔗 이슈

PR Point (To Reviewer)

  • useKakaoMap 내부에서 window.kakao 접근 시점loadKakaoSdk 로딩 순서가 안정적인지 확인 부탁드립니다.
  • 리스트 ↔ 지도 전환 시 상태(viewMode) 흐름 및 UI 자연스러움 검토 요청드립니다.
  • 전체 구조 분리(hooks/constants/components)가 적절한지 피드백 부탁드립니다.

💡 UX 관점 리팩토링 포인트

  • 지도 내 마커 클릭 시 뜨는 Card 추가
  • 리스트 내 특정 아이템 선택 시 지도 뷰로 자동 이동 UX 고려
  • SDK 초기화 후 지도 상태(중심, 확대레벨 등)를 Context로 관리하는 구조로 확장 여지 있음

📸 피그마 스크린샷 or 기능 GIF

(작업 내역 스크린샷)

-.Clipchamp.1.mp4

Summary by CodeRabbit

  • 새로운 기능

    • 코스 추천 페이지 추가 — 리스트/지도 전환, 전체화면 지도 보기, 하단 내비게이션 및 일회성 공지 팝업 포함
    • 카카오 지도 통합 — 복수 위치 마커·정보창 표출 및 전체/부분 지도 뷰 지원
    • 장소 카드 리스트, 해시태그 기반 필터와 보기 토글, 아이콘 세트 업데이트
  • 접근성/사용성

    • ARIA 레이블·역할 추가, 리스트 항목 및 지도에 접근성 속성 적용
  • 스타일

    • 스크롤바 관련 스타일 정리 및 레이아웃 보완

@skyblue1232 skyblue1232 self-assigned this Oct 26, 2025
@skyblue1232 skyblue1232 added the feat 새로운 기능 추가 / 퍼블리싱 label Oct 26, 2025
@skyblue1232 skyblue1232 linked an issue Oct 26, 2025 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 26, 2025

Walkthrough

코스 결과 페이지와 관련 컴포넌트(풀스크린 맵, 결과 리스트/맵, 태그), 카카오 맵 SDK 로더·훅, 정적 장소 데이터 및 아이콘/타입 선언을 추가합니다.

Changes

Cohort / File(s) Summary
페이지 컴포넌트
src/pages/map/result/index.tsx, src/pages/map/result/Map.tsx
코스 결과 메인 페이지와 풀스크린 맵 페이지 추가. 뷰 토글, 팝업 로직 및 라우터 쿼리 기반 초기 뷰 설정 포함.
결과 컴포넌트
src/pages/map/result/components/FullMap.tsx, src/pages/map/result/components/ResultList.tsx, src/pages/map/result/components/ResultMap.tsx, src/pages/map/result/components/TagGroup.tsx
FullMap: 풀스크린 맵 컨테이너. ResultList: listData 기반 2열 카드 리스트(스크롤 숨김). ResultMap: 미니맵 + 전체화면 보기 버튼(라우팅). TagGroup: 해시태그 및 뷰 토글 컨트롤.
카카오 맵 통합
src/shared/hooks/kakao/useKakaoMap.ts, src/shared/utils/loadKakaoSdk.ts, src/shared/types/kakao.d.ts
Kakao SDK 동적 로드 유틸과 useKakaoMap 훅 추가, 전역 Window.kakao 타입 선언 추가.
데이터 상수
src/shared/constants/map/result/listData.ts, src/shared/constants/map/result/mapLocations.ts
정적 장소 데이터 listData(9개 항목) 및 마커용 MAP_LOCATIONS 추가.
아이콘 변경
src/shared/icons/iconNames.ts, src/shared/icons/index.ts
ListButton 아이콘 이름 추가 및 ListButton.svg 임포트 추가.
글로벌 스타일(사소)
src/styles/globals.css
.no-scrollbar 규칙 순서 재배치(동작 변화 없음).
기타
src/pages/map/index.tsx
use client 디렉티브 제거(서버 컴포넌트로 변경).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Page as CourseResultPage
    participant TagGroup
    participant ResultList
    participant ResultMap
    participant FullMap
    participant Kakao as KakaoSDK

    User->>Page: 페이지 진입
    Page->>TagGroup: 렌더(viewMode, onToggleView)
    alt viewMode == list
        Page->>ResultList: 렌더(listData)
    else viewMode == map
        Page->>ResultMap: 렌더(MAP_LOCATIONS)
        ResultMap->>Kakao: loadKakaoSdk → useKakaoMap(mapRef, MAP_LOCATIONS)
        Kakao-->>ResultMap: 마커·인포윈도우 초기화
    end
    User->>TagGroup: 뷰 토글 클릭
    TagGroup->>Page: onToggleView()
    Page->>ResultMap: 뷰 전환
    User->>ResultMap: "전체화면 보기" 클릭
    ResultMap->>Page: router.push('/map/result/Map?from=map')
    Page->>FullMap: FullMap 렌더 → useKakaoMap(mapRef, MAP_LOCATIONS)
    Kakao-->>FullMap: 맵 초기화 완료
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • 추가로 주의할 파일/영역:
    • src/shared/hooks/kakao/useKakaoMap.ts — SDK 로드 시점, 의존성 배열, 마커/이벤트 정리 여부
    • src/shared/utils/loadKakaoSdk.ts — 스크립트 중복 방지 및 env 키 사용
    • src/pages/map/result/index.tsx — localStorage 기반 팝업 로직과 router.query 처리
    • 접근성(role/aria-*) 및 스크롤/레이아웃 전환 동작 확인

Possibly related PRs

Suggested labels

api

Suggested reviewers

  • KongMezu
  • jjangminii

Poem

🐰 껑충 토끼가 말하네,
지도에 핀들이 반짝이고,
태그로 탭하면 뷰가 살짝 바뀌네,
전체화면엔 길이 쭉 펼쳐져,
함께 떠나요, 발자국 따라 ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed PR 제목 "✨ Feat: course result 페이지 및 지도 페이지 구현"은 변경사항의 주요 목표를 명확하게 요약하고 있습니다. 코스 추천 결과 페이지와 지도 페이지 구현이라는 핵심 변경사항을 정확히 반영하고 있으며, 간결하고 구체적인 표현으로 개발자가 이 PR의 목적을 쉽게 파악할 수 있습니다.
Out of Scope Changes Check ✅ Passed 대부분의 변경사항은 이슈 #61의 범위 내에 있습니다. src/pages/map/result 디렉토리 하위의 모든 새로운 파일과 컴포넌트들은 코스 결과 페이지 구현에 직접 관련되며, 공유 유틸리티와 상수들도 맵 기능 통합을 위해 필요한 변경사항입니다. 다만 src/pages/map/index.tsx에서 "use client" 지시문을 제거한 변경사항은 기존 파일 수정에 해당하며, 새로운 페이지 구조와의 호환성을 위한 필요한 조정으로 보입니다.
Description Check ✅ Passed PR 설명은 저장소의 템플릿 구조를 완전히 따르고 있습니다. 필수 섹션인 🔥 작업 내용, 🤔 추후 작업 사항, 🔗 이슈, PR Point (To Reviewer)가 모두 포함되어 있으며, 각 섹션이 상세하고 명확하게 작성되었습니다. 추가로 💡 UX 관점 리팩토링 포인트와 📸 피그마 GIF 링크까지 제공되어 리뷰어가 변경사항을 충분히 이해할 수 있도록 구성되었습니다.
✨ 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/#61/course-result

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the comment 필요한 주석 추가 및 변경 label Oct 26, 2025
@github-actions
Copy link
Copy Markdown

🏷️ Labeler has automatically applied labels based on your PR title, branch name, or commit message.
Please verify that they are correct before merging.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (6)
src/styles/globals.css (1)

222-222: 커스텀 border-pink-300 유틸의 의미 충돌 가능성

현재 클래스가 두 역할(두께+스타일+색상)을 동시에 수행합니다. Tailwind 관례(색상 전용: border-pink-300, 두께 전용: border)와 다르게 동작해 혼선이 생길 수 있습니다.
권장: 기본 조합(border border-pink-300)을 사용하거나, 동일 스케일 전반(border-pink-50~900)을 일관되게 제공하는 border-color 전용 유틸을 정의하세요.

src/pages/map/result/Map.tsx (1)

7-17: 전역 객체 Map과의 섀도잉 회피 권장

컴포넌트명을 Map으로 두면 JS 전역 Map과 섀도잉됩니다. CourseResultMapPage 또는 MapPage로 변경을 권장합니다.
예시:

-const Map = () => {
+const MapPage = () => {
 ...
-export default Map;
+export default MapPage;
src/shared/constants/map/result/mapLocations.ts (1)

1-7: 데이터 타입 명시로 안전성 강화

위치 데이터에 타입을 부여해 오타/필드 누락을 컴파일 타임에 검출하세요.

-export const MAP_LOCATIONS = [
+type Location = { name: string; lat: number; lng: number };
+export const MAP_LOCATIONS: Location[] = [
   { name: '한국만화박물관', lat: 37.505652, lng: 126.776922 },
   ...
-];
+];

또는 TS 4.9+ satisfies:

export const MAP_LOCATIONS = [
  ...
] satisfies readonly { name: string; lat: number; lng: number }[];
src/pages/map/result/components/TagGroup.tsx (1)

12-12: 향후 태그 데이터를 props로 받는 것을 고려하세요.

현재 태그가 하드코딩되어 있습니다. 이슈 #61의 체크리스트에 "태그와 카드 연결"이 남아있는 만큼, 향후 API 연동 시 tags를 props로 전달받도록 리팩토링하면 재사용성이 향상됩니다.

src/pages/map/result/index.tsx (1)

35-40: ControlBar의 하드코딩된 props를 동적으로 처리하세요.

isLoggedIn={false}와 빈 onLogin 핸들러가 하드코딩되어 있습니다. 실제 인증 로직과 연동하거나, 추후 작업이 필요하다면 TODO 코멘트를 추가하는 것을 권장합니다.

src/shared/hooks/kakao/useKakaoMap.ts (1)

33-35: InfoWindow 컨텐츠에 인라인 스타일 대신 CSS 클래스 사용을 고려하세요.

인라인 스타일을 문자열로 주입하고 있습니다. 향후 스타일 일관성과 유지보수를 위해 CSS 클래스나 Tailwind 유틸리티를 사용하는 것을 권장합니다.

예시:

          const infoWindow = new window.kakao.maps.InfoWindow({
-           content: `<div style="padding:5px 10px; font-size:12px;">${p.name}</div>`,
+           content: `<div class="kakao-info-window">${p.name}</div>`,
          });

그리고 전역 CSS 또는 globals.css에 스타일 정의:

.kakao-info-window {
  padding: 0.5rem 1rem;
  font-size: 1.2rem;
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 07d6602 and 13a1658.

⛔ Files ignored due to path filters (4)
  • public/assets/bannerMap.svg is excluded by !**/*.svg
  • public/assets/sample1.jpg is excluded by !**/*.jpg
  • src/shared/icons/source/ListButton.svg is excluded by !**/*.svg
  • src/shared/icons/source/Stamp.svg is excluded by !**/*.svg
📒 Files selected for processing (14)
  • src/pages/map/result/Map.tsx (1 hunks)
  • src/pages/map/result/components/FullMap.tsx (1 hunks)
  • src/pages/map/result/components/ResultList.tsx (1 hunks)
  • src/pages/map/result/components/ResultMap.tsx (1 hunks)
  • src/pages/map/result/components/TagGroup.tsx (1 hunks)
  • src/pages/map/result/index.tsx (1 hunks)
  • src/shared/constants/map/result/listData.ts (1 hunks)
  • src/shared/constants/map/result/mapLocations.ts (1 hunks)
  • src/shared/hooks/kakao/useKakaoMap.ts (1 hunks)
  • src/shared/icons/iconNames.ts (1 hunks)
  • src/shared/icons/index.ts (1 hunks)
  • src/shared/types/kakao.d.ts (1 hunks)
  • src/shared/utils/loadKakaoSdk.ts (1 hunks)
  • src/styles/globals.css (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
src/pages/map/result/index.tsx (6)
src/pages/map/result/components/TagGroup.tsx (1)
  • TagGroup (11-34)
src/shared/lib/utils.ts (1)
  • cn (71-73)
src/pages/map/result/components/ResultList.tsx (1)
  • ResultList (7-46)
src/pages/map/result/components/ResultMap.tsx (1)
  • ResultMap (7-38)
src/shared/components/tab/BottomNav.tsx (1)
  • BottomNav (21-54)
src/shared/components/container/Popup.tsx (1)
  • Popup (9-32)
src/pages/map/result/components/ResultMap.tsx (2)
src/shared/hooks/kakao/useKakaoMap.ts (1)
  • useKakaoMap (11-46)
src/shared/constants/map/result/mapLocations.ts (1)
  • MAP_LOCATIONS (1-7)
src/pages/map/result/components/ResultList.tsx (2)
src/shared/lib/utils.ts (1)
  • cn (71-73)
src/shared/constants/map/result/listData.ts (1)
  • listData (1-65)
src/shared/hooks/kakao/useKakaoMap.ts (1)
src/shared/utils/loadKakaoSdk.ts (1)
  • loadKakaoSdk (1-16)
src/pages/map/result/components/TagGroup.tsx (1)
src/shared/lib/utils.ts (1)
  • cn (71-73)
src/pages/map/result/components/FullMap.tsx (2)
src/shared/hooks/kakao/useKakaoMap.ts (1)
  • useKakaoMap (11-46)
src/shared/constants/map/result/mapLocations.ts (1)
  • MAP_LOCATIONS (1-7)
src/pages/map/result/Map.tsx (1)
src/pages/map/result/components/FullMap.tsx (1)
  • FullMap (7-19)
🪛 Biome (2.1.2)
src/pages/map/result/Map.tsx

[error] 7-7: Do not shadow the global "Map" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-deploy
🔇 Additional comments (7)
src/shared/icons/index.ts (1)

14-14: 아이콘 추가 반영 확인됨

ListButton.svg 임포트가 아이콘 목록과 일치합니다. 문제 없습니다.

src/shared/icons/iconNames.ts (1)

14-14: 아이콘 네임 추가 LGTM

"ListButton" 추가가 인덱스 임포트와 일치합니다. 사용처(예: TagGroup)에서도 동일 문자열인지 한 번만 확인해 주세요.

src/pages/map/result/components/FullMap.tsx (1)

7-19: LGTM!

접근성 속성(role, aria-label)이 적절히 설정되어 있고, 컴포넌트 구조가 명확합니다.

src/pages/map/result/index.tsx (2)

4-4: Next.js App Router 사용 시 next/navigation으로 마이그레이션하세요.

next/router를 사용하고 있는데, 'use client' 컴포넌트에서 App Router를 사용한다면 next/navigationuseRouteruseSearchParams를 사용해야 합니다.

프로젝트가 App Router를 사용하는지 확인하고, 사용한다면 다음과 같이 수정하세요:

-import { useRouter } from 'next/router';
+import { useRouter, useSearchParams } from 'next/navigation';

 export default function CourseResultPage() {
   const router = useRouter();
+  const searchParams = useSearchParams();
   const [showPopup, setShowPopup] = useState(false);
   const [viewMode, setViewMode] = useState<'list' | 'map'>('list');

   useEffect(() => {
     // ... localStorage logic
     
-    if (router.query.from === 'map') {
+    if (searchParams.get('from') === 'map') {
       setViewMode('map');
     }
-  }, [router.query.from]);
+  }, [searchParams]);

Pages Router를 사용 중이라면 이 코멘트는 무시하셔도 됩니다.

Also applies to: 26-28


65-74: 뷰 전환 시 상태 관리가 적절합니다.

viewMode 상태를 기반으로 한 조건부 렌더링과 스타일링이 명확하고, 리스트/지도 뷰 간 전환이 자연스럽게 처리되고 있습니다.

src/shared/hooks/kakao/useKakaoMap.ts (1)

11-46: 전체적인 훅 구조와 카카오 지도 통합이 잘 설계되었습니다.

useKakaoMap 훅이 지도 초기화, 마커 생성, 이벤트 리스너 등록을 명확하게 처리하고 있으며, React의 생명주기와 잘 통합되어 있습니다. 의존성 배열도 적절히 설정되어 있습니다.

src/shared/constants/map/result/listData.ts (1)

1-65: 이미지 파일이 존재하므로 추가 조치가 필요하지 않습니다.

검증 결과 public/assets/sample1.jpg 파일이 실제로 존재하며, 코드에서 참조하는 경로(/assets/sample1.jpg)가 올바르게 구성되어 있습니다. 해당 이미지 파일에 대한 우려사항은 해결되었습니다.

Comment on lines +31 to +43
<style jsx global>{`
/* Chrome, Safari, Opera */
::-webkit-scrollbar {
width: 0 !important;
height: 0 !important;
}

/* Firefox */
* {
scrollbar-width: none !important;
-ms-overflow-style: none !important;
}
`}</style>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

전역 스크롤바 숨김은 접근성 저해—컨테이너 단위로 한정하세요

<style jsx global>로 전역 ::-webkit-scrollbar/* { scrollbar-width: none }를 막아 앱 전반 스크롤바가 사라집니다. 스크린리더/키보드 사용자에게 치명적입니다. 래퍼에 한정된 클래스 적용으로 범위를 축소하세요.

-      <style jsx global>{`
-        /* Chrome, Safari, Opera */
-        ::-webkit-scrollbar {
-          width: 0 !important;
-          height: 0 !important;
-        }
-
-        /* Firefox */
-        * {
-          scrollbar-width: none !important;
-          -ms-overflow-style: none !important;
-        }
-      `}</style>
+      <style jsx>{`
+        .no-scrollbar::-webkit-scrollbar {
+          width: 0;
+          height: 0;
+        }
+        .no-scrollbar {
+          scrollbar-width: none;
+          -ms-overflow-style: none;
+        }
+      `}</style>

그리고 래퍼에 클래스 추가:

-      className={cn(
+      className={cn(
         'grid grid-cols-2 gap-[1.2rem] w-full',
         'justify-items-center pb-[15rem]',
-        'overflow-y-scroll' 
+        'overflow-y-scroll no-scrollbar'
       )}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/pages/map/result/components/ResultList.tsx around lines 31 to 43, the
current <style jsx global> hides scrollbars globally which breaks accessibility;
instead scope the scrollbar rules to the component wrapper (e.g. add a className
like "resultListWrapper" to the outermost wrapper element) and move the CSS out
of global so selectors target .resultListWrapper ::-webkit-scrollbar and
.resultListWrapper { scrollbar-width: none; -ms-overflow-style: none; } (remove
the global * and avoid unnecessary !important), ensuring only this container
hides its scrollbars.

@@ -0,0 +1,38 @@
'use client';
import { useRef } from 'react';
import { useRouter } from 'next/router';
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Oct 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Next.js App Router에서는 next/navigation을 사용하세요.

'use client' 컴포넌트에서 next/router를 import하고 있습니다. Next.js 13+ App Router를 사용하는 경우 next/navigationuseRouter를 사용해야 합니다.

다음과 같이 수정하세요:

-import { useRouter } from 'next/router';
+import { useRouter } from 'next/navigation';
📝 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.

Suggested change
import { useRouter } from 'next/router';
import { useRouter } from 'next/navigation';
🤖 Prompt for AI Agents
In src/pages/map/result/components/ResultMap.tsx around line 3, the component
currently imports useRouter from 'next/router' which is incorrect for App Router
client components; replace that import to use useRouter from 'next/navigation'
(ensure the file has 'use client' at the top if it’s a client component), update
any router method calls that differ between the two hooks to their
next/navigation equivalents, and remove the old 'next/router' import.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저희는 page Router이라 next/router가 맞을거같아요 하지만 'use client';는 수정해야할 것 같네요

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jjangminii 네, 맞습니다! Pages Router를 사용하시는 거였군요. 정정해주셔서 감사합니다.

Pages Router에서는:

  • next/router 사용이 맞습니다
  • 'use client' 지시문은 App Router 전용이므로 제거해야 합니다

Pages Router에서는 pages/ 디렉토리 하위의 모든 컴포넌트가 자동으로 클라이언트 측 라우팅을 지원하므로 'use client' 지시문이 필요하지 않습니다. 이 지시문은 Next.js 13+ App Router의 Server Components와 Client Components를 구분하기 위한 것입니다.

해당 파일(src/pages/map/result/components/ResultMap.tsx)에서 첫 줄의 'use client';를 제거하시면 됩니다.


✏️ Learnings added
Learnt from: jjangminii
Repo: geulDa/FE PR: 64
File: src/pages/map/result/components/ResultMap.tsx:3-3
Timestamp: 2025-10-31T17:34:04.305Z
Learning: The geulDa/FE project uses Next.js Pages Router (not App Router), so components should import useRouter from 'next/router' and should not use the 'use client' directive.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +1 to +6
declare global {
interface Window {
kakao: typeof kakao;
}
}
export {};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

TS 전역 타입 오류 위험: typeof kakao는 외부 선언 없으면 실패

현재 typeof kakao는 Kakao SDK가 타입을 제공하지 않으면 컴파일 에러를 유발합니다. 최소 안전 타입으로 교체하세요.

-declare global {
-  interface Window {
-    kakao: typeof kakao;
-  }
-}
-export {};
+declare global {
+  interface Window {
+    kakao?: {
+      maps?: unknown; // 필요 시 세부 타입 확장
+    };
+  }
+}
+export {};

추후 필요 범위에 맞춰 maps.Map, LatLng, Marker, InfoWindow, event.addListener 등만 정밀 선언하면 DX가 개선됩니다.

📝 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.

Suggested change
declare global {
interface Window {
kakao: typeof kakao;
}
}
export {};
declare global {
interface Window {
kakao?: {
maps?: unknown; // 필요 시 세부 타입 확장
};
}
}
export {};
🤖 Prompt for AI Agents
In src/shared/types/kakao.d.ts lines 1-6, the Window.kakao property is typed as
"typeof kakao" which fails if there is no external kakao declaration; replace
that with a safe minimal type (e.g., any or an explicit minimal interface) to
avoid TS compile errors, then optionally add more specific declarations later
for maps.Map, LatLng, Marker, InfoWindow, and event.addListener as needed.

Comment on lines +5 to +8
if (existing) {
callback();
return;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

스크립트 로딩 완료 여부를 확인해야 합니다.

스크립트 태그가 이미 존재하는 경우 즉시 callback을 호출하지만, 이 시점에 SDK 로딩이 완료되지 않았을 수 있습니다. 이로 인해 useKakaoMap 훅에서 window.kakao에 접근할 때 경쟁 상태(race condition)가 발생할 수 있습니다.

다음과 같이 수정하여 SDK 로딩 상태를 확인하세요:

  if (existing) {
-   callback();
+   if (window.kakao && window.kakao.maps) {
+     callback();
+   } else {
+     existing.addEventListener('load', callback);
+   }
    return;
  }
📝 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.

Suggested change
if (existing) {
callback();
return;
}
if (existing) {
if (window.kakao && window.kakao.maps) {
callback();
} else {
existing.addEventListener('load', callback);
}
return;
}
🤖 Prompt for AI Agents
In src/shared/utils/loadKakaoSdk.ts around lines 5 to 8, the current code calls
callback immediately when a script tag already exists, but that may be before
the SDK has finished loading and causes a race when accessing window.kakao;
update the logic so that if the script tag already exists you check whether
window.kakao is present and ready and call callback immediately only if it is,
otherwise attach an onload (and onerror) handler to that existing script to
invoke the callback once the SDK finishes loading (and handle/report load
failure); similarly when creating a new script, ensure you set onload/onerror
handlers and only call callback after successful load.

Copy link
Copy Markdown
Contributor

@KongMezu KongMezu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다..! 전체적으로 기존 만들어둔 유틸과 컴포넌트 사용에 대한 리뷰 남겨놨습니다! 확인해보시고 수정해보심 좋을 거 같습니다!

Comment on lines +80 to +81
{showPopup && (
<div className="fixed inset-0 bg-black/40 z-50 flex items-center justify-center">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분 shared/shared/set/PopupSet.tsx 에
오버레이랑 같이 뜨도록 해놓은거 있어서

이거 이용하심 될 거 같습니다!
팝업 PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다!!

Comment on lines +38 to +43
/* Firefox */
* {
scrollbar-width: none !important;
-ms-overflow-style: none !important;
}
`}</style>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스크롤바 숨김 경우 제가 최근에 올린 PR에서
global.css 로 빼놔서 확인해보시고, 머지되면 리팩토링 해보시면 될 거 같습니다!

role="region"
aria-labelledby="map-title"
>
<h2 id="map-title" className="sr-only">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기 피그마에서 정해진 폰트 있지 않나요??
유틸 클래스 명시 없이 h2태그로만 묶어도 괜찮나요?

@utility max-w-mobile { max-width: var(--max-w-mobile); }
@utility min-w-100 { min-width: var(--min-w-100); }

@utility border-pink-300 { border: 1px solid var(--color-pink-300); }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분
전역 유틸리티로 등록하지 않아도 될 것 같습니다..!
필요한 클래스나 컴포넌트 내부에서 선언해도 충분히 동작할 것 같습니다!


const Map = () => {
return (
<div className="w-full h-[100vh] bg-[#46d1cd] overflow-hidden">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분 bg-mint-300 으로 유틸 설정해놔서 이거 쓰심 될 거 같습니다!

Comment on lines +19 to +29
useEffect(() => {
const hasSeenPopup = localStorage.getItem('seenCoursePopup');
if (!hasSeenPopup) {
setShowPopup(true);
localStorage.setItem('seenCoursePopup', 'true');
}

if (router.query.from === 'map') {
setViewMode('map');
}
}, [router.query.from]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

query 체크랑 localstorage 체크 이렇게 2개 useeffect로 분리하는게 의존성 문제에서도 더 좋을 거 같습니다!

@vercel
Copy link
Copy Markdown

vercel bot commented Oct 29, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
af-fe Ready Ready Preview Comment Nov 3, 2025 4:54pm

Copy link
Copy Markdown
Contributor

@jjangminii jjangminii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다-! 코멘트 한번 체크해주시고 코드래빗의 'use client' 부분 한번 더 확인해주시면 좋을 것 같아요

'use client';

import { cn } from '@/shared/lib';
import LocationCard from '@/shared/components/container/LocationCard';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 임포트 경로 @/shared/components 만 써도 됩니다

Comment on lines +31 to +36
<style jsx global>{`
/* Chrome, Safari, Opera */
::-webkit-scrollbar {
width: 0 !important;
height: 0 !important;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 수민님이 따로 global.css에서 작업항걸로 아는데 한번 확인해주세요

@@ -0,0 +1,38 @@
'use client';
import { useRef } from 'react';
import { useRouter } from 'next/router';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저희는 page Router이라 next/router가 맞을거같아요 하지만 'use client';는 수정해야할 것 같네요

@@ -0,0 +1,34 @@
'use client';

import Tag from '@/shared/components/tag/Tag';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 경로 수정해 주세요

Comment on lines +8 to +9
import { BottomNav } from '@/shared/components/tab/BottomNav';
import Popup from '@/shared/components/container/Popup';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 경로 수정해주세요

Comment on lines +33 to +35
const infoWindow = new window.kakao.maps.InfoWindow({
content: `<div style="padding:5px 10px; font-size:12px;">${p.name}</div>`,
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이부분은 어떤 역할인가요? 왜 px로 되어잇는지 궁금합니다

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a 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

🧹 Nitpick comments (1)
src/styles/globals.css (1)

221-221: 이전 리뷰 의견 재검토: 지역 범위 사용 가능성 확인

이전 리뷰에서 지적된 바와 같이 border-pink-300을 전역 유틸리티로 정의할 필요가 있는지 확인해주세요.

해당 유틸리티가:

  • 여러 컴포넌트(ResultList, ResultMap, TagGroup 등)에서 사용되는 경우 → 전역 유틸리티 유지 ✓
  • 1~2개 컴포넌트에만 사용되는 경우 → 해당 컴포넌트 파일 내 로컬 스타일로 이동 권장

필요하다면 사용 위치를 확인하고 일관된 스타일 관리 전략을 고려해주세요.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b1228a and 9dfcfc3.

📒 Files selected for processing (3)
  • src/shared/icons/iconNames.ts (1 hunks)
  • src/shared/icons/index.ts (1 hunks)
  • src/styles/globals.css (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/shared/icons/iconNames.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/shared/icons/index.ts (2)
src/shared/icons/scripts/generate-icon-list.ts (2)
  • file (24-24)
  • file (16-16)
src/shared/icons/components/icon.tsx (2)
  • IconProps (42-53)
  • rest (55-110)
🔇 Additional comments (2)
src/styles/globals.css (1)

223-224: no-scrollbar 규칙 적용 승인

스크롤바 숨김 규칙이 브라우저 호환성을 잘 처리합니다(webkit, MS, 표준). 지도 결과 페이지의 ResultList 컴포넌트 등에서 스크롤바를 숨기는 PR 목표에 부합합니다.

src/shared/icons/index.ts (1)

13-13: ListButton 아이콘 통합 상태 확인됨 - 생성 방식 수동 검증 권장

기능적 통합은 모두 정상적으로 이루어졌습니다:

  • src/shared/icons/source/ListButton.svg 파일 존재
  • iconNames.ts에 'ListButton' 타입 포함됨
  • TagGroup.tsx에서 정상 사용 중
  • ✓ import 형식 및 알파벳 순서 정확함

다만 파일 헤더에 "자동 생성 파일"로 명시되어 있으므로, 개발 환경에서 다음을 수동으로 확인해 주시기 바랍니다:

  • src/shared/icons/scripts/generate-icon-list.ts 스크립트 실행 시 index.ts에 ListButton import가 자동으로 생성되는지 확인
  • 향후 유지보수 시 수동 편집을 피하고 스크립트를 통한 재생성으로 덮어쓰기 문제를 방지할 수 있습니다

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a 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

♻️ Duplicate comments (2)
src/pages/map/result/Map.tsx (2)

2-2: useRouter 훅 사용으로 변경 필요 (미해결 이슈)

이전 리뷰에서 지적된 사항이 아직 반영되지 않았습니다. Pages Router 환경에서는 useRouter 훅을 사용하는 것이 권장됩니다.

다음과 같이 수정해 주세요:

-import router from 'next/router';
+import { useRouter } from 'next/router';

 const Map = () => {
+  const router = useRouter();
   return (

Based on learnings

Also applies to: 10-10


7-7: 유틸리티 클래스 사용 권장

팀원(KongMezu)이 제안한 대로 하드코딩된 색상값 대신 bg-mint-300 유틸리티 클래스를 사용하는 것이 좋습니다. 이는 디자인 시스템의 일관성을 유지하고 유지보수성을 향상시킵니다.

-    <div className="w-full h-[100vh] bg-[#46d1cd] overflow-hidden">
+    <div className="w-full h-[100vh] bg-mint-300 overflow-hidden">
🧹 Nitpick comments (2)
src/styles/globals.css (1)

222-223: .no-scrollbar 크로스 브라우저 호환성 개선.

WebKit 브라우저(Chrome, Safari) 외에도 Firefox(scrollbar-width)와 IE/Edge(-ms-overflow-style) 스크롤바 숨김을 완성했습니다. 새로운 map/result UI 컴포넌트에서 일관된 scrollbar 처리가 필요한 경우 적절한 변경입니다.

단, 이전 리뷰에서 지적된 대로 이 클래스가 전역 유틸리티로 등록되어야 하는지는 재고할 가치가 있습니다. 현재 PR에서 실제로 여러 컴포넌트(ResultList, FullMap 등)가 .no-scrollbar를 재사용한다면, 전역 CSS 등록이 DRY 원칙을 따르므로 현재 구조는 합리적입니다. 만약 특정 컴포넌트에서만 사용되거나 미래에 확장성이 제한적이면, 컴포넌트별 scoped style이나 Tailwind 커스텀 유틸리티(@layer utilities)를 고려해 보세요.

혹시 이 PR의 새로운 컴포넌트 중에서 .no-scrollbar를 사용하는 파일이 있다면 확인해 주세요. 여러 곳에서 재사용된다면 현재 전역 등록 접근이 최적입니다.

src/pages/map/result/Map.tsx (1)

5-5: 컴포넌트명 명확성 개선 고려

Map이라는 이름이 JavaScript의 전역 Map 객체와 충돌할 수 있습니다. 더 명확한 이름(예: MapPage, CourseMapPage)을 사용하면 코드의 가독성과 명확성이 향상됩니다.

-const Map = () => {
+const MapPage = () => {
   return (
     // ...
   );
 };

-export default Map;
+export default MapPage;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9dfcfc3 and 35424ae.

📒 Files selected for processing (7)
  • src/pages/map/index.tsx (0 hunks)
  • src/pages/map/result/Map.tsx (1 hunks)
  • src/pages/map/result/components/ResultList.tsx (1 hunks)
  • src/pages/map/result/components/ResultMap.tsx (1 hunks)
  • src/pages/map/result/index.tsx (1 hunks)
  • src/shared/hooks/kakao/useKakaoMap.ts (1 hunks)
  • src/styles/globals.css (1 hunks)
💤 Files with no reviewable changes (1)
  • src/pages/map/index.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/pages/map/result/components/ResultList.tsx
  • src/pages/map/result/index.tsx
  • src/shared/hooks/kakao/useKakaoMap.ts
  • src/pages/map/result/components/ResultMap.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-31T17:34:04.305Z
Learnt from: jjangminii
Repo: geulDa/FE PR: 64
File: src/pages/map/result/components/ResultMap.tsx:3-3
Timestamp: 2025-10-31T17:34:04.305Z
Learning: The geulDa/FE project uses Next.js Pages Router (not App Router), so components should import useRouter from 'next/router' and should not use the 'use client' directive.

Applied to files:

  • src/pages/map/result/Map.tsx
🧬 Code graph analysis (1)
src/pages/map/result/Map.tsx (1)
src/pages/map/result/components/FullMap.tsx (1)
  • FullMap (7-19)
🪛 Biome (2.1.2)
src/pages/map/result/Map.tsx

[error] 5-5: Do not shadow the global "Map" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-deploy

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/pages/map/result/index.tsx (1)

17-23: SSR 환경에서 localStorage 접근 시 안전성 검사가 여전히 필요합니다.

useEffect 내에서 localStorage에 직접 접근하고 있어 SSR 중 hydration 오류가 발생할 수 있습니다. 이전 리뷰에서 지적된 사항이 아직 해결되지 않았습니다.

다음과 같이 수정하세요:

  useEffect(() => {
+   if (typeof window === 'undefined') return;
+   
    const hasSeenPopup = localStorage.getItem('seenCoursePopup');
    if (!hasSeenPopup) {
      setShowPopup(true);
      localStorage.setItem('seenCoursePopup', 'true');
    }
  }, []);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35424ae and 2cef263.

📒 Files selected for processing (3)
  • src/pages/map/result/components/ResultList.tsx (1 hunks)
  • src/pages/map/result/components/TagGroup.tsx (1 hunks)
  • src/pages/map/result/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/pages/map/result/components/TagGroup.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-31T17:34:04.305Z
Learnt from: jjangminii
Repo: geulDa/FE PR: 64
File: src/pages/map/result/components/ResultMap.tsx:3-3
Timestamp: 2025-10-31T17:34:04.305Z
Learning: The geulDa/FE project uses Next.js Pages Router (not App Router), so components should import useRouter from 'next/router' and should not use the 'use client' directive.

Applied to files:

  • src/pages/map/result/index.tsx
🧬 Code graph analysis (2)
src/pages/map/result/components/ResultList.tsx (2)
src/shared/lib/utils.ts (1)
  • cn (71-73)
src/shared/constants/map/result/listData.ts (1)
  • listData (1-65)
src/pages/map/result/index.tsx (5)
src/pages/map/result/components/TagGroup.tsx (1)
  • TagGroup (11-34)
src/shared/lib/utils.ts (1)
  • cn (71-73)
src/pages/map/result/components/ResultList.tsx (1)
  • ResultList (7-31)
src/pages/map/result/components/ResultMap.tsx (1)
  • ResultMap (6-33)
src/shared/components/set/PopupSet.tsx (1)
  • PopupSet (11-35)
🔇 Additional comments (4)
src/pages/map/result/components/ResultList.tsx (1)

7-31: 컴포넌트 구조와 접근성 구현이 잘 되어 있습니다.

  • role="list"aria-label을 통한 적절한 접근성 마크업
  • no-scrollbar 클래스를 사용하여 이전 리뷰에서 지적된 전역 스크롤바 숨김 문제 해결
  • 각 아이템에 role="listitem" 적용으로 의미론적 구조 유지
  • 반응형 그리드 레이아웃과 명확한 데이터 매핑
src/pages/map/result/index.tsx (3)

35-40: ControlBar의 하드코딩된 props를 확인해주세요.

현재 isLoggedIn={false}, 빈 onLogin 핸들러, 하드코딩된 userName="글다"로 설정되어 있습니다.

이것이 의도된 것인지 확인이 필요합니다:

  • 추후 실제 인증 로직과 연동 예정인가요?
  • 현재 단계에서는 mock/placeholder로 사용하는 것이 맞나요?

실제 사용자 인증 상태를 반영하도록 개선이 필요하다면 알려주시면 구현을 도와드릴 수 있습니다.


25-29: 라우터 쿼리 기반 뷰 모드 전환 로직이 잘 구현되었습니다.

전체화면 지도에서 돌아올 때 from=map 쿼리 파라미터를 통해 지도 뷰를 유지하는 로직이 적절하게 분리되어 있습니다. 이전 리뷰에서 제안된 대로 localStorage 체크와 별도의 useEffect로 분리된 점도 좋습니다.


54-70: 리스트/지도 뷰 전환 구조가 명확하고 깔끔합니다.

TagGroup을 통한 뷰 모드 토글과 조건부 렌더링이 잘 구현되어 있습니다:

  • 뷰 모드에 따른 적절한 높이 및 오버플로우 처리
  • ResultList와 ResultMap의 명확한 분리
  • 상태 관리 로직의 간결함

@@ -0,0 +1,31 @@
'use client';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Pages Router에서는 'use client' 지시어가 불필요합니다.

이 프로젝트는 Next.js App Router가 아닌 Pages Router를 사용하고 있습니다. Pages Router에서는 모든 컴포넌트가 기본적으로 클라이언트 컴포넌트로 동작하므로 'use client' 지시어를 제거해야 합니다.

다음과 같이 수정하세요:

-'use client';
-
 import { cn } from '@/shared/lib';

Based on learnings

📝 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.

Suggested change
'use client';
import { cn } from '@/shared/lib';
🤖 Prompt for AI Agents
In src/pages/map/result/components/ResultList.tsx around line 1, remove the
top-level 'use client' directive because this project uses the Next.js Pages
Router where components are already client-side; simply delete that line and
ensure no other code depends on the directive so the file compiles correctly.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a 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

🧹 Nitpick comments (1)
src/pages/map/result/index.tsx (1)

17-25: SSR 안전성 체크가 올바르게 추가되었습니다.

이전 리뷰의 SSR localStorage 접근 문제가 해결되었습니다. 다만 코드 스타일 개선을 위해 작은 수정을 제안합니다.

다음과 같이 spacing을 개선하세요:

  useEffect(() => {
-   if(typeof window === 'undefined') return;
+   if (typeof window === 'undefined') return;
    
    const hasSeenPopup = localStorage.getItem('seenCoursePopup');
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2cef263 and 6a7e7f1.

📒 Files selected for processing (2)
  • src/pages/map/result/Map.tsx (1 hunks)
  • src/pages/map/result/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/pages/map/result/Map.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-31T17:34:04.305Z
Learnt from: jjangminii
Repo: geulDa/FE PR: 64
File: src/pages/map/result/components/ResultMap.tsx:3-3
Timestamp: 2025-10-31T17:34:04.305Z
Learning: The geulDa/FE project uses Next.js Pages Router (not App Router), so components should import useRouter from 'next/router' and should not use the 'use client' directive.

Applied to files:

  • src/pages/map/result/index.tsx
🧬 Code graph analysis (1)
src/pages/map/result/index.tsx (5)
src/pages/map/result/components/TagGroup.tsx (1)
  • TagGroup (11-34)
src/shared/lib/utils.ts (1)
  • cn (71-73)
src/pages/map/result/components/ResultList.tsx (1)
  • ResultList (7-31)
src/pages/map/result/components/ResultMap.tsx (1)
  • ResultMap (6-33)
src/shared/components/set/PopupSet.tsx (1)
  • PopupSet (11-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-deploy
🔇 Additional comments (6)
src/pages/map/result/index.tsx (6)

1-10: 임포트 구조가 깔끔합니다.

필요한 의존성을 적절히 임포트하고 있으며, Next.js Pages Router 방식을 올바르게 따르고 있습니다.


27-31: useEffect 분리가 적절하게 적용되었습니다.

이전 리뷰 피드백대로 query 체크와 localStorage 체크를 별도의 useEffect로 분리하여 의존성 관리가 명확해졌습니다. 쿼리 파라미터 기반 view mode 전환 로직도 정확합니다.


37-42: 인증 관련 props가 하드코딩되어 있습니다.

isLoggedIn={false}와 빈 onLogin 핸들러가 하드코딩되어 있습니다. 본 PR의 범위가 UI 구현에 집중되어 있다면 문제없지만, 추후 실제 인증 로직 통합이 필요한지 확인해주세요.


56-72: 뷰 전환 로직과 조건부 렌더링이 깔끔합니다.

TagGroup을 통한 리스트/지도 전환 UI와 viewMode 기반 조건부 렌더링이 명확하게 구현되어 있습니다. overflow 처리도 각 뷰 모드에 맞게 적절히 설정되었습니다.


78-83: PopupSet 통합이 올바르게 완료되었습니다.

이전 리뷰에서 제안된 대로 shared/components/set/PopupSet.tsx를 활용하여 팝업을 구현했습니다. 오버레이와 함께 중앙에 표시되는 구조로 UX가 개선되었습니다.


46-54: 배너 이미지 경로 확인 완료

/assets/bannerMap.svg 파일이 public/assets/bannerMap.svg에 정상적으로 존재합니다. 문제없습니다.

Copy link
Copy Markdown
Contributor

@KongMezu KongMezu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

복잡한 구조였는데 수고하셨습니다..!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comment 필요한 주석 추가 및 변경 feat 새로운 기능 추가 / 퍼블리싱

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] Course Result UI 구현

3 participants