-
Notifications
You must be signed in to change notification settings - Fork 1
feat : QA 지도 하위 카테고리 수정 #34
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ import { useRouter, useSearchParams } from 'next/navigation'; | |||||
| import Image from 'next/image'; | ||||||
| import KakaoMapRecommend from '@/components/map/kakaoMapRecommend'; | ||||||
| import { useRecommend } from '@/hooks/api/query/useRecommend'; | ||||||
| import { useCheckMeeting } from '@/hooks/api/query/useCheckMeeting'; | ||||||
|
|
||||||
| function RecommendContent() { | ||||||
| const router = useRouter(); | ||||||
|
|
@@ -21,25 +22,72 @@ function RecommendContent() { | |||||
| // 현재 선택된 장소 ID (기본값: 첫 번째) | ||||||
| const [selectedPlaceId, setSelectedPlaceId] = useState<number>(1); | ||||||
|
|
||||||
| // 모임 카테고리 가져오기 (localStorage에서 캐싱된 값 사용) | ||||||
| const meetingCategory = useMemo(() => { | ||||||
| const cachedCategory = localStorage.getItem(`meeting_${meetingId}_category`); | ||||||
| if (cachedCategory) { | ||||||
| return cachedCategory; | ||||||
| // 모임 정보 조회 (purposes 정보를 가져오기 위해) | ||||||
| const { data: meetingData } = useCheckMeeting(meetingId); | ||||||
|
|
||||||
| // 상위 카테고리 추출 (API에서 가져오거나 localStorage에서) | ||||||
| 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]); | ||||||
|
|
||||||
| return ''; | ||||||
| }, [meetingId]); | ||||||
| // 하위 카테고리 추출 (API에서 가져오거나 localStorage에서) | ||||||
| const defaultCategory = useMemo(() => { | ||||||
| if (typeof window === 'undefined') return ''; | ||||||
|
|
||||||
| // 1. API에서 가져온 purposes의 마지막 값 사용 | ||||||
| if (meetingData?.data?.purposes && meetingData.data.purposes.length > 1) { | ||||||
| const subCategory = meetingData.data.purposes[meetingData.data.purposes.length - 1]; | ||||||
| if (subCategory) { | ||||||
| // localStorage에도 저장 (다음 접근 시 빠르게 사용) | ||||||
| localStorage.setItem(`meeting_${meetingId}_category`, subCategory); | ||||||
| return subCategory; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| const cachedCategory = localStorage.getItem(`meeting_${meetingId}_category`); | ||||||
| return cachedCategory || ''; | ||||||
| }, [meetingId, meetingData]); | ||||||
|
|
||||||
| const [selectedCategory, setSelectedCategory] = useState<string>(() => { | ||||||
| if (typeof window === 'undefined') return ''; | ||||||
| return localStorage.getItem(`meeting_${meetingId}_category`) || ''; | ||||||
| }); | ||||||
|
|
||||||
| const currentCategory = selectedCategory || defaultCategory; | ||||||
|
|
||||||
| const effectiveCategory = currentCategory; | ||||||
|
|
||||||
| // 카테고리 변경 핸들러 | ||||||
| const handleCategoryChange = (category: string) => { | ||||||
| setSelectedCategory(category); | ||||||
| setSelectedPlaceId(1); // 카테고리 변경 시 첫 번째 장소 선택 | ||||||
| if (typeof window !== 'undefined') { | ||||||
| localStorage.setItem(`meeting_${meetingId}_category`, category); | ||||||
| } | ||||||
| }; | ||||||
|
|
||||||
| // 장소 추천 API 호출 | ||||||
| const { | ||||||
| data: recommendData, | ||||||
| isLoading, | ||||||
| isError, | ||||||
| } = useRecommend({ | ||||||
| // 장소 추천 API 호출 (effectiveCategory 사용 - selectedCategory가 우선) | ||||||
| const { data: recommendData, isLoading, isError } = useRecommend({ | ||||||
| meetingId, | ||||||
| midPlace, | ||||||
| category: meetingCategory, | ||||||
| category: effectiveCategory, | ||||||
| page: 1, | ||||||
| size: 15, | ||||||
| }); | ||||||
|
|
@@ -52,7 +100,7 @@ function RecommendContent() { | |||||
| return recommendData.data.placeInfos.map((place, index) => ({ | ||||||
| id: index + 1, | ||||||
| name: place.placeName, | ||||||
| category: place.categoryGroupName || place.categoryName, | ||||||
| category: place.categoryGroupName, | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
이전에 🛡️ fallback 추가 제안- category: place.categoryGroupName,
+ category: place.categoryGroupName || place.categoryName || '',📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| description: place.categoryName, | ||||||
| phone: place.phone || '전화번호 없음', | ||||||
| address: place.addressName, | ||||||
|
|
@@ -99,6 +147,9 @@ function RecommendContent() { | |||||
| places={places} | ||||||
| selectedPlaceId={selectedPlaceId} | ||||||
| onSelectPlace={setSelectedPlaceId} | ||||||
| selectedCategory={effectiveCategory} | ||||||
| onCategoryChange={handleCategoryChange} | ||||||
| meetingType={meetingType} | ||||||
| /> | ||||||
| </div> | ||||||
|
|
||||||
|
|
@@ -195,6 +246,9 @@ function RecommendContent() { | |||||
| places={places} | ||||||
| selectedPlaceId={selectedPlaceId} | ||||||
| onSelectPlace={setSelectedPlaceId} | ||||||
| selectedCategory={effectiveCategory} | ||||||
| onCategoryChange={handleCategoryChange} | ||||||
| meetingType={meetingType} | ||||||
| /> | ||||||
| </section> | ||||||
| </div> | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,13 +23,17 @@ interface KakaoMapRecommendProps { | |
| onSelectPlace?: (placeId: number) => void; | ||
| selectedCategory?: string; | ||
| onCategoryChange?: (category: string) => void; | ||
| meetingType?: '회의' | '친목' | null; | ||
| } | ||
|
|
||
| const CATEGORIES = [ | ||
| // 전체 카테고리 목록 | ||
| 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' }, | ||
| ]; | ||
|
Comment on lines
+29
to
37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 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 -nRepository: 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.tsxRepository: SWYP-mingling/Frontend Length of output: 2855
둘 중 하나로 통일해야 합니다. 🐛 권장 사항: ALL_CATEGORIES의 ID를 create 페이지와 일치시키기- { id: '스터디카페', label: '스터디카페', icon: '/icon/place/studycafe' },
+ { id: '스터디 카페', label: '스터디 카페', icon: '/icon/place/studycafe' },또는 🤖 Prompt for AI Agents |
||
|
|
||
| export default function KakaoMapRecommend({ | ||
|
|
@@ -41,10 +45,26 @@ export default function KakaoMapRecommend({ | |
| selectedPlaceId, | ||
| selectedCategory = '', | ||
| onCategoryChange, | ||
| meetingType, | ||
| }: KakaoMapRecommendProps) { | ||
| // 1. 지도 객체를 state로 관리 (줌 컨트롤 제어용) | ||
| const [map, setMap] = useState<kakao.maps.Map | null>(null); | ||
|
|
||
| // 상위 카테고리에 따라 하위 카테고리 필터링 | ||
| const categories = useMemo(() => { | ||
| if (meetingType === '회의') { | ||
| // 회의: 스터디카페, 장소 대여 | ||
| return ALL_CATEGORIES.filter((cat) => cat.id === '스터디카페' || cat.id === '장소 대여'); | ||
| } else if (meetingType === '친목') { | ||
| // 친목: 식당, 술집, 카페, 놀거리 | ||
| return ALL_CATEGORIES.filter( | ||
| (cat) => cat.id === '식당' || cat.id === '술집' || cat.id === '카페' || cat.id === '놀거리' | ||
| ); | ||
| } | ||
| // meetingType이 없으면 전체 카테고리 표시 | ||
| return ALL_CATEGORIES; | ||
| }, [meetingType]); | ||
|
|
||
| // 선택된 장소 찾기 | ||
| const selectedPlace = useMemo(() => { | ||
| if (!selectedPlaceId || places.length === 0) return null; | ||
|
|
@@ -113,7 +133,7 @@ export default function KakaoMapRecommend({ | |
|
|
||
| {/* 상단 카테고리 필터 (Floating) */} | ||
| <div className="scrollbar-hide absolute top-4 right-0 left-0 z-20 flex justify-start gap-2 overflow-x-hidden px-4"> | ||
| {CATEGORIES.map((cat) => ( | ||
| {categories.map((cat) => ( | ||
| <button | ||
| key={cat.id} | ||
| onClick={() => onCategoryChange?.(cat.id)} | ||
|
|
||
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.
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