Skip to content

feat : QA 지도 하위 카테고리 수정#34

Merged
kangdy25 merged 3 commits intomainfrom
feature/QA-map-category
Feb 8, 2026
Merged

feat : QA 지도 하위 카테고리 수정#34
kangdy25 merged 3 commits intomainfrom
feature/QA-map-category

Conversation

@kim3360
Copy link
Contributor

@kim3360 kim3360 commented Feb 8, 2026

🚀 QA 지도 하위 카테고리 수정

📝 변경사항

1. 상위 카테고리 기반 하위 카테고리 동적 표시

  • 모임 생성 시 선택한 상위 카테고리("회의" 또는 "친목")에 따라 하위 카테고리를 동적으로 필터링하여 표시
    • 회의: 스터디카페, 장소 대여
    • 친목: 식당, 술집, 카페, 놀거리

2. 모임 참여자 카테고리 정보 접근 개선

  • 기존: 모임 생성자만 localStorage에 저장된 카테고리 정보로 추천 장소 확인 가능
  • 개선: 모임 참여자도 API를 통해 purposes 정보를 가져와 추천 장소 확인 가능
  • useCheckMeeting 훅을 통해 모임 정보 API에서 purposes 배열을 가져와 상위/하위 카테고리 추출

3. 카테고리 클릭 시 장소 리스트 자동 요청

  • 지도에서 카테고리 버튼 클릭 시 해당 카테고리의 장소 리스트를 자동으로 API 요청
  • React Query의 queryKeycategory를 포함하여 카테고리 변경 시 자동 refetch 구현

4. 카테고리 정보 캐싱

  • API에서 가져온 카테고리 정보를 localStorage에 저장하여 다음 접근 시 빠르게 사용

  • 모임 생성 시 상위 카테고리(meetingType)도 localStorage에 저장

  • 여기에 변경된 내용을 적어주세요.

✅ 체크리스트

  • 코드 리뷰를 받았습니다
  • 테스트를 완료했습니다
  • 린터 에러가 없습니다
  • 타입 에러가 없습니다
  • 브라우저에서 테스트를 완료했습니다
  • 모바일에서 테스트를 완료했습니다 (해당되는 경우)

📸 스크린샷

UI 변경 사항이 있다면 이미지를 드래그해서 넣어주세요!

💬 리뷰어 전달사항

  • 리뷰어가 특별히 확인해야 할 사항이 있다면 적어주세요.

Summary by CodeRabbit

릴리스 노트

  • New Features
    • 모임 유형(회의/친목)에 따른 카테고리 동적 필터링 추가
    • 새로운 카테고리 옵션(술집, 장소 대여) 추가
    • 사용자 카테고리 선택이 자동으로 저장됨
    • 모임 정보 기반 추천 기능 개선

@vercel
Copy link

vercel bot commented Feb 8, 2026

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

Project Deployment Actions Updated (UTC)
mingling-frontend Ready Ready Preview, Comment Feb 8, 2026 1:41pm

@coderabbitai
Copy link

coderabbitai bot commented Feb 8, 2026

Walkthrough

미팅 생성 후 meetingType을 localStorage에 저장하고, 추천 페이지에서 API 기반 미팅 데이터를 통해 meetingType과 카테고리를 파생시킨 후 필터링된 카테고리 목록을 지도 컴포넌트로 전달합니다. API 응답에 purposes 필드가 추가되었습니다.

Changes

Cohort / File(s) Summary
API 확장
types/api.ts
MeetingStatusData 인터페이스에 purposes 필드 추가로 미팅 API 응답 확장
생성 후 상태 보존
app/create/page.tsx
카테고리 저장 후 meetingType을 meeting 기반 localStorage 키로 저장
미팅 컨텍스트 및 카테고리 관리
app/recommend/page.tsx, components/map/kakaoMapRecommend.tsx
useCheckMeeting()으로 API 미팅 데이터 조회, purposes에서 defaultCategory 파생, 사용자 선택 카테고리와 병합, meetingType 기반 카테고리 필터링 로직 구현, KakaoMapRecommend에 new props 전달

Sequence Diagram

sequenceDiagram
    participant User as 사용자
    participant RecommendPage as Recommend<br/>페이지
    participant API as API 서버
    participant Storage as localStorage
    participant KakaoMap as KakaoMap<br/>컴포넌트
    
    User->>RecommendPage: 추천 페이지 진입
    RecommendPage->>API: useCheckMeeting(meetingId)
    API-->>RecommendPage: MeetingStatusData<br/>(purposes, meetingType)
    
    RecommendPage->>RecommendPage: purposes에서<br/>defaultCategory 파생
    RecommendPage->>Storage: 카테고리 캐시
    RecommendPage->>Storage: 데이터 읽기
    Storage-->>RecommendPage: 캐시된 값
    
    RecommendPage->>RecommendPage: effectiveCategory 계산<br/>(selected > default)
    RecommendPage->>RecommendPage: meetingType 기반<br/>카테고리 필터링
    
    RecommendPage->>KakaoMap: selectedCategory,<br/>onCategoryChange,<br/>filteredCategories 전달
    
    User->>KakaoMap: 카테고리 변경
    KakaoMap->>RecommendPage: onCategoryChange
    RecommendPage->>RecommendPage: selectedCategory 업데이트
    RecommendPage->>Storage: 선택 카테고리 저장
    RecommendPage->>RecommendPage: selectedPlaceId 초기화
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항인 상위 카테고리 기반 하위 카테고리 동적 필터링을 명확하게 설명하고 있습니다.
Description check ✅ Passed PR 설명이 4가지 주요 변경사항을 구체적으로 설명하고 있으며, 필수 체크리스트 항목을 모두 완료했습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feature/QA-map-category

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.

@kangdy25 kangdy25 merged commit 5c5d627 into main Feb 8, 2026
4 of 5 checks passed
Copy link

@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: 3

🤖 Fix all issues with AI agents
In `@app/recommend/page.tsx`:
- Line 103: 현재 category 필드에 직접 할당된 category: place.categoryGroupName이 빈 문자열이나
undefined일 때 배지가 비어 보이는 문제가 있습니다; categoryGroupName이 falsy(빈 문자열 포함)인 경우
place.categoryName으로 대체되도록 수정하세요 — 예: category에 place.categoryGroupName이 유효한 값인지
확인하고(빈 문자열 체크 포함) 유효하지 않으면 place.categoryName을 할당하도록 변경하여 category:
place.categoryGroupName 대신 안전한 fallback을 사용하도록 고치세요.
- Around line 29-48: The meetingType useMemo currently has the
localStorage.setItem call commented out on the same line so the API-derived
firstPurpose never gets cached; inside the block that checks
meetingData.data.purposes and determines firstPurpose (the code dealing with
meetingData, firstPurpose, and meetingId), move the
localStorage.setItem(`meeting_${meetingId}_meetingType`, firstPurpose) out of
the comment and execute it before returning firstPurpose (ensuring typeof window
!== 'undefined' remains satisfied) so the value is persisted for future lookups
used by the cachedType logic.

In `@components/map/kakaoMapRecommend.tsx`:
- Around line 29-37: The category ID for the study-cafe is inconsistent:
ALL_CATEGORIES currently uses id '스터디카페' while the rest of the app (e.g., the
value sent from create/page and returned by the API, and the comparisons using
selectedCategory in kakaoMapRecommend.tsx) uses '스터디 카페' with a space; update
the ALL_CATEGORIES entry for the study cafe so its id is '스터디 카페' to match
selectedCategory checks and filtering logic, and verify any other places that
construct or compare this category string use the same exact value.
🧹 Nitpick comments (2)
app/recommend/page.tsx (2)

51-66: useMemo 내부에서 localStorage.setItem 부수 효과가 발생합니다.

React의 useMemo는 순수 계산을 위한 훅입니다. Strict Mode에서 두 번 실행되거나, React가 결과를 버릴 수도 있습니다. localStorage 캐싱은 별도의 useEffect로 분리하는 것이 더 안전합니다.

동일한 패턴이 meetingType useMemo(Line 36, 현재 주석 처리됨)에도 적용됩니다.

♻️ useEffect로 캐싱 로직 분리 예시
  const defaultCategory = useMemo(() => {
    if (typeof window === 'undefined') return '';
    if (meetingData?.data?.purposes && meetingData.data.purposes.length > 1) {
      const subCategory = meetingData.data.purposes[meetingData.data.purposes.length - 1];
      if (subCategory) {
-        localStorage.setItem(`meeting_${meetingId}_category`, subCategory);
        return subCategory;
      }
    }
    const cachedCategory = localStorage.getItem(`meeting_${meetingId}_category`);
    return cachedCategory || '';
  }, [meetingId, meetingData]);

+ // API에서 가져온 카테고리를 localStorage에 캐싱
+ useEffect(() => {
+   if (meetingData?.data?.purposes && meetingData.data.purposes.length > 1) {
+     const subCategory = meetingData.data.purposes[meetingData.data.purposes.length - 1];
+     if (subCategory) {
+       localStorage.setItem(`meeting_${meetingId}_category`, subCategory);
+     }
+   }
+ }, [meetingId, meetingData]);

73-75: currentCategoryeffectiveCategory가 동일한 값입니다.

effectiveCategory = currentCategory = selectedCategory || defaultCategory로, 두 변수가 불필요하게 중복됩니다. 하나로 통합하면 가독성이 향상됩니다.

♻️ 변수 통합 제안
- const currentCategory = selectedCategory || defaultCategory;
- 
- const effectiveCategory = currentCategory;
+ const effectiveCategory = selectedCategory || defaultCategory;

Comment on lines +29 to +48
const meetingType = useMemo(() => {
if (typeof window === 'undefined') return null;

// 1. API에서 purposes 가져오기 (참여자도 접근 가능)
if (meetingData?.data?.purposes && meetingData.data.purposes.length > 0) {
const firstPurpose = meetingData.data.purposes[0];
if (firstPurpose === '회의' || firstPurpose === '친목') {
// localStorage에도 저장 (다음 접근 시 빠르게 사용) localStorage.setItem(`meeting_${meetingId}_meetingType`, firstPurpose);
return firstPurpose as '회의' | '친목';
}
}


const cachedType = localStorage.getItem(`meeting_${meetingId}_meetingType`);
if (cachedType === '회의' || cachedType === '친목') {
return cachedType as '회의' | '친목';
}

return null;
}, [meetingId, meetingData]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

localStorage.setItem 호출이 주석 안에 포함되어 실행되지 않습니다.

Line 36에서 localStorage.setItem(...) 호출이 주석(//)과 같은 줄에 있어 실행되지 않습니다. API에서 가져온 meetingType이 localStorage에 캐싱되지 않으므로, API 데이터가 없는 후속 접근 시 fallback이 작동하지 않습니다.

🐛 주석과 코드를 분리
     if (meetingData?.data?.purposes && meetingData.data.purposes.length > 0) {
       const firstPurpose = meetingData.data.purposes[0];
       if (firstPurpose === '회의' || firstPurpose === '친목') {
-        // localStorage에도 저장 (다음 접근 시 빠르게 사용)    localStorage.setItem(`meeting_${meetingId}_meetingType`, firstPurpose);
+        // localStorage에도 저장 (다음 접근 시 빠르게 사용)
+        localStorage.setItem(`meeting_${meetingId}_meetingType`, firstPurpose);
         return firstPurpose as '회의' | '친목';
       }
     }
🤖 Prompt for AI Agents
In `@app/recommend/page.tsx` around lines 29 - 48, The meetingType useMemo
currently has the localStorage.setItem call commented out on the same line so
the API-derived firstPurpose never gets cached; inside the block that checks
meetingData.data.purposes and determines firstPurpose (the code dealing with
meetingData, firstPurpose, and meetingId), move the
localStorage.setItem(`meeting_${meetingId}_meetingType`, firstPurpose) out of
the comment and execute it before returning firstPurpose (ensuring typeof window
!== 'undefined' remains satisfied) so the value is persisted for future lookups
used by the cachedType logic.

id: index + 1,
name: place.placeName,
category: place.categoryGroupName || place.categoryName,
category: place.categoryGroupName,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

categoryGroupName이 빈 값일 때의 fallback 제거.

이전에 categoryName으로의 fallback이 있었으나 제거되었습니다. categoryGroupName이 빈 문자열이나 undefined인 경우 카테고리 배지가 비어 보일 수 있습니다.

🛡️ fallback 추가 제안
-      category: place.categoryGroupName,
+      category: place.categoryGroupName || place.categoryName || '',
📝 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
category: place.categoryGroupName,
category: place.categoryGroupName || place.categoryName || '',
🤖 Prompt for AI Agents
In `@app/recommend/page.tsx` at line 103, 현재 category 필드에 직접 할당된 category:
place.categoryGroupName이 빈 문자열이나 undefined일 때 배지가 비어 보이는 문제가 있습니다;
categoryGroupName이 falsy(빈 문자열 포함)인 경우 place.categoryName으로 대체되도록 수정하세요 — 예:
category에 place.categoryGroupName이 유효한 값인지 확인하고(빈 문자열 체크 포함) 유효하지 않으면
place.categoryName을 할당하도록 변경하여 category: place.categoryGroupName 대신 안전한
fallback을 사용하도록 고치세요.

Comment on lines +29 to 37
// 전체 카테고리 목록
const ALL_CATEGORIES = [
{ id: '식당', label: '식당', icon: '/icon/place/restaurant' },
{ id: '놀거리', label: '놀거리', icon: '/icon/place/play' },
{ id: '술집', label: '술집', icon: '/icon/place/bar' },
{ id: '카페', label: '카페', icon: '/icon/place/cafe' },
{ id: '놀거리', label: '놀거리', icon: '/icon/place/play' },
{ id: '스터디카페', label: '스터디카페', icon: '/icon/place/studycafe' },
{ id: '장소 대여', label: '장소 대여', icon: '/icon/place/rent' },
];
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for both spelling variants of study cafe category
echo "=== Searching for '스터디카페' (no space) ==="
rg '스터디카페' --type=ts --type=tsx -n

echo ""
echo "=== Searching for '스터디 카페' (with space) ==="
rg '스터디 카페' --type=ts --type=tsx -n

Repository: SWYP-mingling/Frontend

Length of output: 224


🏁 Script executed:

#!/bin/bash
# Search for both spelling variants without file type restriction
echo "=== Searching for '스터디카페' (no space) ==="
rg '스터디카페' -n --glob='*.tsx' --glob='*.ts'

echo ""
echo "=== Searching for '스터디 카페' (with space) ==="
rg '스터디 카페' -n --glob='*.tsx' --glob='*.ts'

Repository: SWYP-mingling/Frontend

Length of output: 533


🏁 Script executed:

#!/bin/bash
# Check the recommend page to see how selectedCategory is used and compared
echo "=== Content of recommend/page.tsx to understand data flow ==="
rg 'selectedCategory|defaultCategory|purposes' -n --glob='*.tsx' app/ 

echo ""
echo "=== Check kakaoMapRecommend.tsx line 141 (selectedCategory comparison) ==="
sed -n '135,150p' components/map/kakaoMapRecommend.tsx

Repository: SWYP-mingling/Frontend

Length of output: 2855


'스터디카페''스터디 카페'의 불일치로 카테고리 선택이 동작하지 않습니다.

app/create/page.tsx Line 227에서 목적으로 '스터디 카페'(띄어쓰기 있음)를 전송하고, API에서도 이 값을 그대로 반환합니다. 그러나 kakaoMapRecommend.tsx에서 ALL_CATEGORIES의 ID는 '스터디카페'(띄어쓰기 없음)로 정의되어 있습니다. 결과적으로 selectedCategory === cat.id 비교(Line 141)가 실패하여 카테고리 하이라이트가 표시되지 않으며, 필터링 로직(Line 57)도 정상 작동하지 않습니다.

둘 중 하나로 통일해야 합니다.

🐛 권장 사항: ALL_CATEGORIES의 ID를 create 페이지와 일치시키기
-  { id: '스터디카페', label: '스터디카페', icon: '/icon/place/studycafe' },
+  { id: '스터디 카페', label: '스터디 카페', icon: '/icon/place/studycafe' },

또는 app/create/page.tsx Line 227의 값을 '스터디카페'로 변경하세요.

🤖 Prompt for AI Agents
In `@components/map/kakaoMapRecommend.tsx` around lines 29 - 37, The category ID
for the study-cafe is inconsistent: ALL_CATEGORIES currently uses id '스터디카페'
while the rest of the app (e.g., the value sent from create/page and returned by
the API, and the comparisons using selectedCategory in kakaoMapRecommend.tsx)
uses '스터디 카페' with a space; update the ALL_CATEGORIES entry for the study cafe
so its id is '스터디 카페' to match selectedCategory checks and filtering logic, and
verify any other places that construct or compare this category string use the
same exact value.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants