/** * 장소 검색 다이얼로그 컴포넌트 * - 국내: 카카오맵 API * - 해외: 구글맵 API */ import { useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { X, Search, MapPin, Globe } from "lucide-react"; /** * @param {Object} props * @param {boolean} props.isOpen - 다이얼로그 열림 여부 * @param {Function} props.onClose - 닫기 핸들러 * @param {Function} props.onSelect - 장소 선택 핸들러 ({ name, address, country, lat, lng }) */ function VenueSearchDialog({ isOpen, onClose, onSelect }) { const [region, setRegion] = useState("domestic"); // domestic | overseas const [searchQuery, setSearchQuery] = useState(""); const [results, setResults] = useState([]); const [searching, setSearching] = useState(false); const [error, setError] = useState(null); // 다이얼로그 닫기 시 상태 초기화 const handleClose = () => { setSearchQuery(""); setResults([]); setError(null); onClose(); }; // 지역 변경 시 결과 초기화 const handleRegionChange = (newRegion) => { setRegion(newRegion); setResults([]); setError(null); }; // 검색 실행 const handleSearch = async () => { if (!searchQuery.trim()) { setResults([]); return; } setSearching(true); setError(null); try { const token = localStorage.getItem("adminToken"); if (region === "domestic") { // 카카오맵 API const response = await fetch( `/api/admin/kakao/places?query=${encodeURIComponent(searchQuery)}`, { headers: { Authorization: `Bearer ${token}` }, } ); if (response.ok) { const data = await response.json(); const places = (data.documents || []).map((place) => ({ id: place.id, name: place.place_name, address: place.road_address_name || place.address_name, country: "한국", lat: parseFloat(place.y), lng: parseFloat(place.x), category: place.category_name, })); setResults(places); } else { setError("검색 중 오류가 발생했습니다."); } } else { // 구글맵 API const response = await fetch( `/api/admin/google/places?query=${encodeURIComponent(searchQuery)}`, { headers: { Authorization: `Bearer ${token}` }, } ); if (response.ok) { const data = await response.json(); const places = (data.results || []).map((place) => ({ id: place.place_id, name: place.name, address: place.formatted_address, country: extractCountry(place.formatted_address), lat: place.geometry?.location?.lat, lng: place.geometry?.location?.lng, category: place.types?.[0]?.replace(/_/g, " "), })); setResults(places); } else { setError("검색 중 오류가 발생했습니다."); } } } catch (err) { console.error("장소 검색 오류:", err); setError("검색 중 오류가 발생했습니다."); } finally { setSearching(false); } }; // 주소에서 국가 추출 (구글맵용) const extractCountry = (address) => { if (!address) return ""; const parts = address.split(", "); return parts[parts.length - 1] || ""; }; // 장소 선택 const handleSelectPlace = (place) => { onSelect({ name: place.name, address: place.address, country: place.country, lat: place.lat, lng: place.lng, }); handleClose(); }; return ( {isOpen && ( e.stopPropagation()} > {/* 헤더 */}

장소 검색

{/* 지역 선택 탭 */}
{/* 검색 입력 */}
setSearchQuery(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); handleSearch(); } }} placeholder={ region === "domestic" ? "장소명을 입력하세요 (예: 올림픽홀)" : "장소명을 입력하세요 (예: Tokyo Dome)" } className="w-full pl-12 pr-4 py-3 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" autoFocus />
{/* 에러 메시지 */} {error && (
{error}
)} {/* 검색 결과 */}
{results.length > 0 ? (
{results.map((place) => ( ))}
) : (

장소명을 입력하고 검색해주세요

)}
)}
); } export default VenueSearchDialog;