| name | map-feature |
| description | Guide for the Map page feature (Kakao Maps integration, location search, store category filtering). Use when working on map components, search bar, bottom sheet, detail sheet, store/pickup filters, or Kakao Map API integration. Triggers on "map", "kakao map", "location search", "store category", "bottom sheet", "map marker", "nearby", "autocomplete", "suggest". |
Map Feature Guide
File Structure
src/
โโโ pages/Map/
โ โโโ Map.tsx # Main map page (state management)
โ
โโโ components/map/
โ โโโ MapSearchBar.tsx # Search input + autocomplete dropdown
โ โโโ MapCard.tsx # Location card in bottom sheet
โ โโโ MapDetailSheet.tsx # Location detail bottom sheet
โ โโโ MapView.tsx # Kakao Map markers + overlays
โ โโโ MapFloatingView.tsx # Source toggle (keco/zerowaste/all)
โ โโโ bottomSheet/
โ โโโ MapBottomSheet.tsx # Bottom sheet container
โ โโโ StoreCategoryFilter.tsx # Store category filter UI
โ โโโ FilterContent.tsx # Pickup category filter
โ
โโโ api/services/map/
โ โโโ map.service.ts # API client (MapService class)
โ โโโ map.type.ts # TypeScript types + STORE_CATEGORIES
โ โโโ map.queries.ts # React Query options
โ
โโโ hooks/
โโโ useKakaoLoaderOrigin.tsx # Kakao Maps SDK loader
Data Flow
Map.tsx (state owner)
โโโ useQuery(MapQueries.getLocations) โ MapService.getLocations()
โโโ MapSearchBar โ MapService.suggestPlaces() / searchLocations()
โโโ MapBottomSheet โ MapCard[] โ handleSetSelectedId()
โโโ MapDetailSheet โ MapService.getLocationDetail()
โโโ MapView โ kakao.maps.Map + MapMarker[]
โโโ StoreCategoryFilter โ selectedStoreCategories state
Key State
const [center, setCenter] = useState({ lat, lng });
const [mapZoom, setMapZoom] = useState(3);
const [selectedId, setSelectedId] = useState<number | null>(null);
const [selectedStoreCategories, setSelectedStoreCategories] = useState<string[]>([]);
const [searchResults, setSearchResults] = useState<LocationListResponse | null>(null);
const [toggle, setToggle] = useState<ToggleType>('all');
API Types
{ lat, lon, radius?, zoom?, store_category?, pickup_category? }
{ id, name, source, road_address?, latitude, longitude, distance_km?,
distance_text?, store_category?, is_open?, is_holiday?,
start_time?, end_time?, phone?, pickup_categories?, place_url?, kakao_place_id? }
{ place_name, address, latitude, longitude, place_url? }
{ id, name, source, road_address?, lot_address?, latitude?, longitude?,
store_category, pickup_categories, phone?, place_url?, kakao_place_id?,
collection_items?, introduction? }
Store Categories
const STORE_CATEGORIES = [
{ key: 'refill_zero', label: '์ ๋ก์จ์ด์คํธ' },
{ key: 'cafe_bakery', label: '์นดํ/๋ฒ ์ด์ปค๋ฆฌ' },
{ key: 'vegan_dining', label: '๋น๊ฑด/์๋น' },
{ key: 'upcycle_recycle', label: '์
์ฌ์ดํด/์ฌํ์ฉ' },
{ key: 'book_workshop', label: '๋์๊ด/๊ณต๋ฐฉ' },
{ key: 'market_mart', label: '๋งํธ/์์ฅ' },
{ key: 'lodging', label: '์๋ฐ' },
{ key: 'public_dropbox', label: '๋ฌด์ธ ์๊ฑฐํจ' },
{ key: 'general', label: '๊ธฐํ' },
];
Environment Variables
| Variable | Description |
|---|
VITE_KAKAO_MAP_API_KEY | Kakao Maps JavaScript SDK key |
VITE_API_BASE_URL | Backend API base URL |
Kakao Map Integration
- SDK loader:
useKakaoLoaderOrigin hook (loads react-kakao-maps-sdk)
- Map component:
<Map> from react-kakao-maps-sdk
- Markers:
<MapMarker> with custom overlay
- Pan/zoom events:
onCenterChanged, onZoomChanged
Common Patterns
Search flow
- User types in MapSearchBar
- Debounce (300ms) โ
MapService.suggestPlaces(q)
- Show dropdown with SuggestEntry[]
- User selects โ pan map to coordinates +
MapService.searchLocations()
Filter flow
- User opens StoreCategoryFilter
- Toggle categories โ temporary state
- "๊ฒฐ๊ณผ๋ณด๊ธฐ" button โ
setSelectedStoreCategories()
- useEffect triggers
refetch() with new store_category param
Detail flow
- User taps MapCard
setSelectedId(id) โ MapDetailSheet opens
MapService.getLocationDetail(id) โ show detail
Directions
window.open(`https://map.kakao.com/link/to/${name},${lat},${lng}`)
Known Issues
- Query key caching:
MapQueries.getLocations uses static query key โ different map positions return cached data
- Multiple refetch effects: Three
useEffect hooks call refetch() with different conditions
- MapView marker key: Uses array index instead of item ID
- Silent error handling: MapDetailSheet/MapSearchBar swallow API errors