From a1c2783d78dc5a2b6c0452fbcb4df064dadffdee Mon Sep 17 00:00:00 2001 From: pjookim <pjookim@naver.com> Date: Sun, 8 Dec 2024 22:48:54 +0900 Subject: [PATCH] refactor: clean up imports, improve code formatting, and remove unused TestData file --- src/components/MyTripCollaborators.js | 2 +- src/components/MyTripWeather.js | 16 +- src/components/PlaceDetails.js | 36 ++-- src/components/PlaceDirections.js | 134 +++++++-------- src/components/PlaceReview.js | 6 +- src/constants/TestData.js | 232 -------------------------- src/hooks/useKakaoMap.js | 20 +-- src/pages/Home.js | 20 +-- src/pages/Login.js | 4 +- src/pages/MapView.js | 217 ------------------------ src/styles/KoreaMap.css | 2 +- src/styles/Map.css | 11 +- src/styles/MyTrip.css | 2 +- src/styles/MyTripCollaborators.css | 4 +- src/styles/NewTrip.css | 8 +- src/styles/PlaceDirections.css | 2 +- 16 files changed, 116 insertions(+), 600 deletions(-) delete mode 100644 src/constants/TestData.js delete mode 100644 src/pages/MapView.js diff --git a/src/components/MyTripCollaborators.js b/src/components/MyTripCollaborators.js index b2b17ac..e1cf60f 100644 --- a/src/components/MyTripCollaborators.js +++ b/src/components/MyTripCollaborators.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import axios from 'axios'; import { FaUserPlus, FaUsers } from 'react-icons/fa'; import { useAuth } from '../App'; diff --git a/src/components/MyTripWeather.js b/src/components/MyTripWeather.js index 952f21d..b118be1 100644 --- a/src/components/MyTripWeather.js +++ b/src/components/MyTripWeather.js @@ -49,7 +49,7 @@ const MyTripWeather = ({ location }) => { const response = await axios.get( `https://api.openweathermap.org/data/2.5/forecast?q=${cityName}&appid=${API_KEY}&units=metric&lang=kr` ); - + const dailyData = response.data.list.reduce((acc, item) => { const date = new Date(item.dt * 1000).toLocaleDateString(); if (!acc[date]) { @@ -57,8 +57,8 @@ const MyTripWeather = ({ location }) => { } return acc; }, {}); - - setWeatherData(Object.values(dailyData).slice(0, 3)); // 3일치만 표시 + + setWeatherData(Object.values(dailyData).slice(0, 3)); setLoading(false); } catch (error) { console.error('날씨 데이터 가져오기 실패:', error); @@ -83,22 +83,20 @@ const MyTripWeather = ({ location }) => { </h4> <div className="weather-days"> {loading ? ( - // 로딩 중 shimmer 효과 Array(3).fill(null).map((_, index) => ( <div> </div> )) ) : ( - // 실제 날씨 데이터 weatherData.map((day, index) => ( <div key={index} className="weather-day"> <div className="weather-date"> - {index === 0 ? '오늘' : - index === 1 ? '내일' : - '모레'} + {index === 0 ? '오늘' : + index === 1 ? '내일' : + '모레'} </div> <div className="weather-info"> - <img + <img src={`https://openweathermap.org/img/wn/${day.weather[0].icon}.png`} alt={day.weather[0].description} /> diff --git a/src/components/PlaceDetails.js b/src/components/PlaceDetails.js index 864ef4e..989a0e7 100644 --- a/src/components/PlaceDetails.js +++ b/src/components/PlaceDetails.js @@ -57,11 +57,9 @@ const PlaceDetails = ({ place, onClose }) => { }; }, [onClose]); - // HTML 문자열을 안전하게 렌더링하는 함수 const renderHTML = (htmlString) => { if (!htmlString) return null; - - // <br> 태그를 줄바꿈으로 변환 + return htmlString.split('<br>').map((text, index, array) => ( <React.Fragment key={index}> {text} @@ -90,14 +88,14 @@ const PlaceDetails = ({ place, onClose }) => { )} <div className="detail-info"> <p className="location"> - <FaMapMarkerAlt className="icon" /> - <strong>주소:</strong> + <FaMapMarkerAlt className="icon" /> + <strong>주소:</strong> <span>{renderHTML(place.location || place.address)}</span> </p> {place.tel && ( <p className="tel"> - <FaPhoneAlt className="icon" /> - <strong>전화:</strong> + <FaPhoneAlt className="icon" /> + <strong>전화:</strong> <span>{renderHTML(place.tel)}</span> </p> )} @@ -107,22 +105,22 @@ const PlaceDetails = ({ place, onClose }) => { <> {placeDetails.restdate && ( <p> - <FaCalendarAlt className="icon" /> - <strong>쉬는날:</strong> + <FaCalendarAlt className="icon" /> + <strong>쉬는날:</strong> <span>{renderHTML(placeDetails.restdate)}</span> </p> )} {placeDetails.usetime && ( <p> - <FaClock className="icon" /> - <strong>이용시간:</strong> + <FaClock className="icon" /> + <strong>이용시간:</strong> <span>{renderHTML(placeDetails.usetime)}</span> </p> )} {placeDetails.parking && ( <p> - <FaParking className="icon" /> - <strong>주차장:</strong> + <FaParking className="icon" /> + <strong>주차장:</strong> <span>{renderHTML(placeDetails.parking)}</span> </p> )} @@ -134,22 +132,22 @@ const PlaceDetails = ({ place, onClose }) => { <> {placeDetails.eventstartdate && placeDetails.eventenddate && ( <p> - <FaCalendarAlt className="icon" /> - <strong>기간:</strong> + <FaCalendarAlt className="icon" /> + <strong>기간:</strong> <span>{`${placeDetails.eventstartdate} ~ ${placeDetails.eventenddate}`}</span> </p> )} {placeDetails.sponsor1 && ( <p> - <FaPhoneAlt className="icon" /> - <strong>주최자:</strong> + <FaPhoneAlt className="icon" /> + <strong>주최자:</strong> <span>{renderHTML(placeDetails.sponsor1)}</span> </p> )} {placeDetails.usetimefestival && ( <p> - <FaMoneyBillWave className="icon" /> - <strong>이용 요금:</strong> + <FaMoneyBillWave className="icon" /> + <strong>이용 요금:</strong> <span>{renderHTML(placeDetails.usetimefestival)}</span> </p> )} diff --git a/src/components/PlaceDirections.js b/src/components/PlaceDirections.js index 4f6904b..cf444ce 100644 --- a/src/components/PlaceDirections.js +++ b/src/components/PlaceDirections.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useCallback, useRef } from 'react'; +import React, { useEffect, useState, useRef } from 'react'; import axios from 'axios'; import '../styles/PlaceDirections.css'; @@ -86,12 +86,12 @@ const PlaceDirections = ({ startPlace, endPlace, map, onClose }) => { }); setClusterer(newClusterer); - return () => { - if (clusterer) { - clusterer.clear(); - } - }; - } + return () => { + if (clusterer) { + clusterer.clear(); + } + }; + } }, [map]); useEffect(() => { @@ -101,7 +101,7 @@ const PlaceDirections = ({ startPlace, endPlace, map, onClose }) => { } }; }, [activeInfowindow]); - + const searchPlaces = () => { @@ -164,12 +164,12 @@ const PlaceDirections = ({ startPlace, endPlace, map, onClose }) => { searchResultsList.push(placeInfo); }); - clusterer.addMarkers(newMarkers); - - setMarkers(newMarkers.map((marker, i) => ({ - marker: marker, - overlay: newOverlays[i] - }))); + clusterer.addMarkers(newMarkers); + + setMarkers(newMarkers.map((marker, i) => ({ + marker: marker, + overlay: newOverlays[i] + }))); setSearchResults(searchResultsList); map.setBounds(bounds); @@ -232,19 +232,19 @@ const PlaceDirections = ({ startPlace, endPlace, map, onClose }) => { const findRoute = async () => { if (!selectedStart || !selectedEnd) { - alert('출발지와 도착지를 모두 선택해주세요.'); - return; + alert('출발지와 도착지를 모두 선택해주세요.'); + return; } setLoading(true); try { - const url = `https://apis-navi.kakaomobility.com/v1/directions?origin=${selectedStart.coordinates.lng},${selectedStart.coordinates.lat}&destination=${selectedEnd.coordinates.lng},${selectedEnd.coordinates.lat}&priority=RECOMMEND`; + const url = `https://apis-navi.kakaomobility.com/v1/directions?origin=${selectedStart.coordinates.lng},${selectedStart.coordinates.lat}&destination=${selectedEnd.coordinates.lng},${selectedEnd.coordinates.lat}&priority=RECOMMEND`; - const response = await axios.get(url, { - headers: { - Authorization: `KakaoAK ${process.env.REACT_APP_KAKAO_MAP_API_KEY}` - } - }); + const response = await axios.get(url, { + headers: { + Authorization: `KakaoAK ${process.env.REACT_APP_KAKAO_MAP_API_KEY}` + } + }); const path = response.data.routes[0].sections[0].roads.map(road => road.vertexes); const linePath = []; @@ -254,12 +254,10 @@ const PlaceDirections = ({ startPlace, endPlace, map, onClose }) => { } }); - // 기존 경로 삭제 if (map.polyline) { map.polyline.setMap(null); } - // 새 경로 그리기 const polyline = new window.kakao.maps.Polyline({ path: linePath, strokeWeight: 5, @@ -270,26 +268,25 @@ const PlaceDirections = ({ startPlace, endPlace, map, onClose }) => { polyline.setMap(map); map.polyline = polyline; - // 경로 정보 설정 const distance = response.data.routes[0].summary.distance; const duration = response.data.routes[0].summary.duration; const fare = response.data.routes[0].summary.fare; const guides = response.data.routes[0].sections[0].guides.filter(guide => guide.type !== 100 && guide.type !== 101); - setRouteInfo({ - distance: (distance / 1000).toFixed(1) + 'km', - duration: Math.round(duration / 60) + '분', - fare: fare ? { - taxi: fare.taxi.toLocaleString() + '원', - toll: fare.toll ? fare.toll.toLocaleString() + '원' : '0원' - } : null, - guides: guides.map(guide => ({ - name: guide.name, - guidance: guide.guidance, - distance: guide.distance - })) - }); + setRouteInfo({ + distance: (distance / 1000).toFixed(1) + 'km', + duration: Math.round(duration / 60) + '분', + fare: fare ? { + taxi: fare.taxi.toLocaleString() + '원', + toll: fare.toll ? fare.toll.toLocaleString() + '원' : '0원' + } : null, + guides: guides.map(guide => ({ + name: guide.name, + guidance: guide.guidance, + distance: guide.distance + })) + }); // 지도 범위 설정 const bounds = new window.kakao.maps.LatLngBounds(); @@ -298,25 +295,12 @@ const PlaceDirections = ({ startPlace, endPlace, map, onClose }) => { map.setBounds(bounds); } catch (error) { - console.error('길찾기 실패:', error); - alert('경로를 찾을 수 없습니다.'); + console.error('길찾기 실패:', error); + alert('경로를 찾을 수 없습니다.'); } finally { - setLoading(false); + setLoading(false); } -}; - - // useEffect(() => { - // const handleClickOutside = (event) => { - // if (directionsRef.current && !directionsRef.current.contains(event.target)) { - // onClose(); - // } - // }; - - // document.addEventListener('mousedown', handleClickOutside); - // return () => { - // document.removeEventListener('mousedown', handleClickOutside); - // }; - // }, [onClose]); + }; return ( <div className="place-directions" ref={directionsRef}> @@ -395,30 +379,30 @@ const PlaceDirections = ({ startPlace, endPlace, map, onClose }) => { <p>총 거리: {routeInfo.distance}</p> <p>예상 소요 시간: {routeInfo.duration}</p> {routeInfo.fare && ( - <> - <p>예상 택시 요금: {routeInfo.fare.taxi}</p> - <p>통행료: {routeInfo.fare.toll}</p> - </> + <> + <p>예상 택시 요금: {routeInfo.fare.taxi}</p> + <p>통행료: {routeInfo.fare.toll}</p> + </> )} - <div - className="directions-route-guides-header" - onClick={() => setShowGuides(!showGuides)} + <div + className="directions-route-guides-header" + onClick={() => setShowGuides(!showGuides)} > - <h4>상세 경로 안내</h4> - <span className={`toggle-icon ${showGuides ? 'open' : ''}`}> - ▼ - </span> + <h4>상세 경로 안내</h4> + <span className={`toggle-icon ${showGuides ? 'open' : ''}`}> + ▼ + </span> </div> {showGuides && ( - <div className="directions-route-guides"> - {routeInfo.guides.map((guide, index) => ( - <div key={index} className="directions-guide-item"> - {guide.name && <strong>{guide.name}: </strong>} - <span>{guide.guidance}</span> - <small>({(guide.distance/1000).toFixed(1)}km)</small> - </div> - ))} - </div> + <div className="directions-route-guides"> + {routeInfo.guides.map((guide, index) => ( + <div key={index} className="directions-guide-item"> + {guide.name && <strong>{guide.name}: </strong>} + <span>{guide.guidance}</span> + <small>({(guide.distance / 1000).toFixed(1)}km)</small> + </div> + ))} + </div> )} </div> )} diff --git a/src/components/PlaceReview.js b/src/components/PlaceReview.js index efd8a7d..992f3aa 100644 --- a/src/components/PlaceReview.js +++ b/src/components/PlaceReview.js @@ -50,12 +50,11 @@ const PlaceReview = ({ placeId, placeName }) => { return; } - // 데이터 형식 수정 const reviewData = { user_id: user._id, - place_id: String(placeId), // 명시적으로 문자열로 변환 + place_id: String(placeId), place_name: placeName, - rating: Number(rating), // 명시적으로 숫자로 변환 + rating: Number(rating), comment: newReview.trim() }; @@ -78,7 +77,6 @@ const PlaceReview = ({ placeId, placeName }) => { setHover(0); } } catch (error) { - // 더 자세한 에러 정보 로깅 console.error('서버 에러 응답:', { status: error.response?.status, data: error.response?.data, diff --git a/src/constants/TestData.js b/src/constants/TestData.js deleted file mode 100644 index 0485031..0000000 --- a/src/constants/TestData.js +++ /dev/null @@ -1,232 +0,0 @@ -export const TRIPS_DATA = [ - { - id: 1, - name: '부산 3일 여행', - start_date: '2024-10-07', - end_date: '2024-10-09', - location: '부산', - plans: { - day1: { // 해운대 권역 - places: [ - { - id: 987810, - type: 12, - name: '동백섬', - location: '부산 해운대구 우동 710-1', - coordinates: { lat: 35.1530, lng: 129.1525 } - }, - { - id: 126081, - type: 12, - name: '해운대해수욕장', - location: '부산 해운대구 해운대해변로 264', - coordinates: { lat: 35.1586, lng: 129.1603 } - }, - { - id: 3, - name: '마린시티', - location: '부산 해운대구 마린시티2로 33', - coordinates: { lat: 35.1587, lng: 129.1485 } - }, - { - id: 4, - name: '광안리해수욕장', - location: '부산 수영구 광안해변로 219', - coordinates: { lat: 35.1533, lng: 129.1187 } - }, - { - id: 5, - name: '센텀시티', - location: '부산 해운대구 센텀남대로 35', - coordinates: { lat: 35.1689, lng: 129.1312 } - } - ], - route: [126081, 987810, 3, 4, 5] - }, - day2: { // 남포동/영도 권역 - places: [ - { - id: 6, - name: '자갈치시장', - location: '부산 중구 자갈치해안로 52', - coordinates: { lat: 35.0967, lng: 129.0305 } - }, - { - id: 7, - name: '국제시장', - location: '부산 중구 국제시장2길 25', - coordinates: { lat: 35.1017, lng: 129.0284 } - }, - { - id: 8, - name: '용두산공원', - location: '부산 중구 용두산길 37-55', - coordinates: { lat: 35.1009, lng: 129.0325 } - }, - { - id: 9, - name: '태종대', - location: '부산 영도구 전망로 24', - coordinates: { lat: 35.0597, lng: 129.0849 } - }, - { - id: 10, - name: '영도대교', - location: '부산 중구 영도대교로', - coordinates: { lat: 35.0955, lng: 129.0386 } - } - ], - route: [6, 7, 8, 9, 10] - }, - day3: { // 금정/동래 권역 - places: [ - { - id: 11, - name: '범어사', - location: '부산 금정구 범어사로 250', - coordinates: { lat: 35.2849, lng: 129.0657 } - }, - { - id: 12, - name: '금정산성', - location: '부산 금정구 금성동', - coordinates: { lat: 35.2521, lng: 129.0524 } - }, - { - id: 13, - name: '동래온천', - location: '부산 동래구 온천장1길 19', - coordinates: { lat: 35.2056, lng: 129.0831 } - }, - { - id: 14, - name: '동래읍성', - location: '부산 동래구 동래역사관길 18', - coordinates: { lat: 35.2048, lng: 129.0936 } - }, - { - id: 15, - name: '부산시립박물관', - location: '부산 남구 유엔평화로 63', - coordinates: { lat: 35.1293, lng: 129.0904 } - } - ], - route: [11, 12, 13, 14, 15] - } - } - }, - { - id: 2, - name: '제주도 겨울 여행', - start_date: '2024-12-01', - end_date: '2024-12-03', - location: '제주도', - plans: { - day1: { // 제주 서부 - places: [ - { - id: 1, - name: '협재해수욕장', - location: '제주특별자치도 제주시 한림읍 협재리', - coordinates: { lat: 33.3940, lng: 126.2394 } - }, - { - id: 2, - name: '금능해수욕장', - location: '제주특별자치도 제주시 한림읍 금능리', - coordinates: { lat: 33.3891, lng: 126.2350 } - }, - { - id: 3, - name: '오설록 티뮤지엄', - location: '제주특별자치도 서귀포시 안덕면 신화역사로 15', - coordinates: { lat: 33.3066, lng: 126.2899 } - }, - { - id: 4, - name: '카멜리아힐', - location: '제주특별자치도 서귀포시 안덕면 병악로 166', - coordinates: { lat: 33.2887, lng: 126.3711 } - }, - { - id: 5, - name: '산방산', - location: '제주특별자치도 서귀포시 안덕면 사계리', - coordinates: { lat: 33.2368, lng: 126.3127 } - } - ], - route: [1, 2, 3, 4, 5] - }, - day2: { // 제주 동부 - places: [ - { - id: 6, - name: '성산일출봉', - location: '제주특별자치도 서귀포시 성산읍 성산리', - coordinates: { lat: 33.4587, lng: 126.9425 } - }, - { - id: 7, - name: '우도', - location: '제주특별자치도 제주시 우도면', - coordinates: { lat: 33.5219, lng: 126.9514 } - }, - { - id: 8, - name: '섭지코지', - location: '제주특별자치도 서귀포시 성산읍 고성리', - coordinates: { lat: 33.4238, lng: 126.9277 } - }, - { - id: 9, - name: '비자림', - location: '제주특별자치도 제주시 구좌읍 비자숲길 55', - coordinates: { lat: 33.4894, lng: 126.8060 } - }, - { - id: 10, - name: '만장굴', - location: '제주특별자치도 제주시 구좌읍 만장굴길 182', - coordinates: { lat: 33.5283, lng: 126.7714 } - } - ], - route: [6, 7, 8, 9, 10] - }, - day3: { // 제주 중부/남부 - places: [ - { - id: 11, - name: '천지연폭포', - location: '제주특별자치도 서귀포시 천지동 667-7', - coordinates: { lat: 33.2447, lng: 126.5544 } - }, - { - id: 12, - name: '정방폭포', - location: '제주특별자치도 서귀포시 동홍동 299-3', - coordinates: { lat: 33.2445, lng: 126.5717 } - }, - { - id: 13, - name: '중문관광단지', - location: '제주특별자치도 서귀포시 중문관광로 72번길 35', - coordinates: { lat: 33.2506, lng: 126.4121 } - }, - { - id: 14, - name: '한라산 국립공원', - location: '제주특별자치도 제주시 해안동', - coordinates: { lat: 33.3616, lng: 126.5292 } - }, - { - id: 15, - name: '용두암', - location: '제주특별자치도 제주시 용담2동', - coordinates: { lat: 33.5161, lng: 126.5116 } - } - ], - route: [11, 12, 13, 14, 15] - } - } - } -]; \ No newline at end of file diff --git a/src/hooks/useKakaoMap.js b/src/hooks/useKakaoMap.js index c6f36da..4726959 100644 --- a/src/hooks/useKakaoMap.js +++ b/src/hooks/useKakaoMap.js @@ -15,7 +15,6 @@ const UseKakaoMap = (initialLocation) => { const handleZoomChange = useCallback(() => { const level = mapInstanceRef.current.getLevel(); console.log('Current zoom level:', level); - console.log('markers', markersRef.current); markersRef.current.forEach(({ marker, overlay }) => { if (overlay) { overlay.setMap(level <= 7 ? mapInstanceRef.current : null); @@ -39,9 +38,9 @@ const UseKakaoMap = (initialLocation) => { }; const mapInstance = new window.kakao.maps.Map(container, options); mapInstanceRef.current = mapInstance; - + window.kakao.maps.event.addListener(mapInstance, 'zoom_changed', handleZoomChange); - + setMap(mapInstance); } catch (error) { console.error('Error creating map:', error); @@ -49,10 +48,7 @@ const UseKakaoMap = (initialLocation) => { }, [initialLocation, handleZoomChange]); const clearMap = useCallback(() => { - console.log('clearMap1'); if (!map) return; - console.log('clearMap2'); - console.log(markers); markers.forEach(marker => { if (marker.marker) { @@ -127,13 +123,13 @@ const UseKakaoMap = (initialLocation) => { }; }, []); - return { - map, - setMap, - markers, - setMarkers, + return { + map, + setMap, + markers, + setMarkers, clearMap, - mapContainerRef + mapContainerRef }; }; diff --git a/src/pages/Home.js b/src/pages/Home.js index 5e8bf1b..79fd977 100644 --- a/src/pages/Home.js +++ b/src/pages/Home.js @@ -1,17 +1,17 @@ import React, { useEffect, useState, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; -import AddPlace from '../components/AddPlace'; -import PlaceDirections from '../components/PlaceDirections'; import { FaArrowLeft, FaUser } from 'react-icons/fa'; +import { toast } from 'react-toastify'; +import axios from 'axios'; import MyTrip from '../components/MyTrip'; import Map from '../components/Map'; import PlaceDetails from '../components/PlaceDetails'; import NewTrip from '../components/NewTrip'; +import AddPlace from '../components/AddPlace'; +import PlaceDirections from '../components/PlaceDirections'; import useKakaoMap from '../hooks/useKakaoMap'; -import axios from 'axios'; -import '../styles/HomePage.css'; import MapSearch from '../components/MapSearch'; -import { toast } from 'react-toastify'; +import '../styles/HomePage.css'; const API_URL = process.env.REACT_APP_SERVER_URL; const WS_URL = process.env.REACT_APP_WS_URL; @@ -28,11 +28,11 @@ const Home = () => { const [directionInfo, setDirectionInfo] = useState(null); const [selectedLocation, setSelectedLocation] = useState({ latitude: 37.2829, - longitude: 127.0435 + longitude: 127.0435 // 아주대학교 }); const [ws, setWs] = useState(null); - const { map, setMap, markers, setMarkers, clearMap } = useKakaoMap(selectedLocation); + const { map,setMarkers, clearMap } = useKakaoMap(selectedLocation); useEffect(() => { const fetchTrips = async () => { @@ -187,13 +187,13 @@ const Home = () => { setselectedTrip(trip); clearMap(); - + const newMarkers = []; const bounds = new window.kakao.maps.LatLngBounds(); const linePath = []; const allPlaces = Object.values(trip.plans).flatMap(day => { - return day.route.map(routeId => + return day.route.map(routeId => day.places.find(place => place.id === routeId) ); }); @@ -543,7 +543,7 @@ const Home = () => { trips={trips} /> )} - <Map/> + <Map /> </div> </div> </div> diff --git a/src/pages/Login.js b/src/pages/Login.js index 954f71d..23bc4e4 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -1,9 +1,9 @@ -import React, { useEffect,useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useAuth, useToast } from '../App'; import axios from 'axios'; -import '../styles/Login.css'; import jwt_decode from 'jwt-decode'; +import '../styles/Login.css'; const API_URL = process.env.REACT_APP_SERVER_URL; diff --git a/src/pages/MapView.js b/src/pages/MapView.js deleted file mode 100644 index 5b5a129..0000000 --- a/src/pages/MapView.js +++ /dev/null @@ -1,217 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import DatePicker from 'react-datepicker'; -import 'react-datepicker/dist/react-datepicker.css'; -import '../styles/MapView.css'; -import axios from 'axios'; - -const MapView = () => { - const [selectedDate, setSelectedDate] = useState(null); - const [places, setPlaces] = useState({}); - const [map, setMap] = useState(null); - const [keyword, setKeyword] = useState(''); - const [startPlace, setStartPlace] = useState(null); - const [endPlace, setEndPlace] = useState(null); - const [routeInfo, setRouteInfo] = useState(null); - const [favorites, setFavorites] = useState([]); // 즐겨찾기 상태 추가 - - useEffect(() => { - const { kakao } = window; - - const container = document.getElementById('map'); - const options = { - center: new kakao.maps.LatLng(37.28, 127.04), - level: 3, - }; - const mapInstance = new kakao.maps.Map(container, options); - setMap(mapInstance); - }, []); - - const searchPlaces = () => { - if (!keyword.trim()) { - alert('검색어를 입력하세요'); - return; - } - - const { kakao } = window; - const ps = new kakao.maps.services.Places(); - - ps.keywordSearch(keyword, (data, status) => { - if (status === kakao.maps.services.Status.OK) { - const bounds = new kakao.maps.LatLngBounds(); - - data.forEach((place) => { - const markerPosition = new kakao.maps.LatLng(place.y, place.x); - const marker = new kakao.maps.Marker({ - position: markerPosition, - map: map, - }); - - bounds.extend(markerPosition); - - kakao.maps.event.addListener(marker, 'click', () => { - if (!selectedDate) { - alert('날짜를 먼저 선택하세요.'); - return; - } - - const dateKey = selectedDate.toLocaleDateString(); - const placeInfo = { name: place.place_name, address: place.address_name, lat: place.y, lng: place.x }; - - setPlaces((prev) => ({ - ...prev, - [dateKey]: [...(prev[dateKey] || []), placeInfo], - })); - }); - }); - - map.setBounds(bounds); - } else { - alert('장소 검색 실패: 장소를 찾을 수 없습니다.'); - } - }); - }; - - const toggleFavorite = (place) => { - setFavorites((prevFavorites) => { - if (prevFavorites.some(fav => fav.name === place.name)) { - return prevFavorites.filter(fav => fav.name !== place.name); - } else { - return [...prevFavorites, place]; - } - }); - }; - - const setStart = (place) => { - setStartPlace(place); - alert(`출발지: ${place.name}`); - }; - - const setEnd = (place) => { - setEndPlace(place); - alert(`도착지: ${place.name}`); - }; - - const findRoute = async () => { - if (!startPlace || !endPlace) { - alert('출발지와 도착지를 설정해 주세요.'); - return; - } - - const url = `https://apis-navi.kakaomobility.com/v1/directions?origin=${startPlace.lng},${startPlace.lat}&destination=${endPlace.lng},${endPlace.lat}&waypoints=&priority=RECOMMEND&road_details=false`; - - try { - const response = await axios.get(url, { - headers: { - Authorization: `KakaoAK ${process.env.REACT_APP_KAKAO_MAP_API_KEY}` - } - }); - - const path = response.data.routes[0].sections[0].roads.map((road) => road.vertexes); - const linePath = []; - path.forEach((coordinates) => { - for (let i = 0; i < coordinates.length; i += 2) { - linePath.push(new window.kakao.maps.LatLng(coordinates[i + 1], coordinates[i])); - } - }); - - const polyline = new window.kakao.maps.Polyline({ - path: linePath, - strokeWeight: 5, - strokeColor: '#FF0000', - strokeOpacity: 0.7, - strokeStyle: 'solid' - }); - polyline.setMap(map); - - const distance = response.data.routes[0].summary.distance; - setRouteInfo({ distance: (distance / 1000).toFixed(2) + ' km' }); - - } catch (error) { - console.error('길찾기 실패:', error.response ? error.response.data : error.message); - alert('경로를 찾을 수 없습니다.'); - } - }; - - return ( - <div className="container"> - <div className="content-box"> - <div className="top-section"> - <div className="map-section" id="map"></div> - - <div className="sidebar"> - <div className="section"> - <h2 className="section-title">일정 추가</h2> - <DatePicker - selected={selectedDate} - onChange={(date) => setSelectedDate(date)} - dateFormat="yyyy-MM-dd" - className="date-picker" - placeholderText="날짜를 선택하세요" - /> - <div className="search-container"> - <input - type="text" - className="search-input" - placeholder="장소 검색" - value={keyword} - onChange={(e) => setKeyword(e.target.value)} - /> - <button className="search-button" onClick={searchPlaces}> - 검색 - </button> - </div> - - <div className="places-list"> - <h3>추가된 일정</h3> - {Object.keys(places).map((date) => ( - <div key={date}> - <h4>{date}</h4> - <ul> - {places[date].map((place, index) => ( - <li key={index} className="place-item"> - <strong>{place.name}</strong> - {place.address} - <div> - <button onClick={() => setStart(place)}>출발지</button> - <button onClick={() => setEnd(place)}>도착지</button> - <button onClick={() => toggleFavorite(place)}> - {favorites.some(fav => fav.name === place.name) ? '즐겨찾기 취소' : '즐겨찾기 추가'} - </button> - </div> - </li> - ))} - </ul> - </div> - ))} - </div> - </div> - </div> - </div> - - <div className="route-section"> - <button className="route-button" onClick={findRoute}> - 경로 찾기 - </button> - {routeInfo && ( - <div className="route-info"> - <p>총 거리: {routeInfo.distance}</p> - </div> - )} - </div> - - {/* 즐겨찾기 목록 */} - <div className="favorites-list"> - <h3>즐겨찾기 목록</h3> - <ul> - {favorites.map((place, index) => ( - <li key={index}> - <strong>{place.name}</strong> - {place.address} - </li> - ))} - </ul> - </div> - </div> - </div> - ); -}; - -export default MapView; diff --git a/src/styles/KoreaMap.css b/src/styles/KoreaMap.css index a035c64..8a8dfb8 100644 --- a/src/styles/KoreaMap.css +++ b/src/styles/KoreaMap.css @@ -29,7 +29,7 @@ } .korea-map-container path.selected { - fill: #4a90e2; + fill: var(--primary-color); } @media screen and (max-width: 768px) { diff --git a/src/styles/Map.css b/src/styles/Map.css index 1144136..f47c46d 100644 --- a/src/styles/Map.css +++ b/src/styles/Map.css @@ -143,7 +143,7 @@ } .confirm-button { - background-color: #4CAF50; + background-color: var(--primary-color); color: white; } @@ -152,15 +152,6 @@ color: white; } -/* .add-button { - background: none; - border: none; - color: #4CAF50; - cursor: pointer; - padding: 0.5rem; - font-size: 1.2rem; -} */ - .search-result-item { display: flex; justify-content: space-between; diff --git a/src/styles/MyTrip.css b/src/styles/MyTrip.css index 5d799dd..7214ab3 100644 --- a/src/styles/MyTrip.css +++ b/src/styles/MyTrip.css @@ -122,7 +122,7 @@ } .place-item.drag-over { - border-top: 2px solid #4CAF50; + border-top: 2px solid var(--primary-color); } .place-item:hover { diff --git a/src/styles/MyTripCollaborators.css b/src/styles/MyTripCollaborators.css index d7fee09..3b1cbc3 100644 --- a/src/styles/MyTripCollaborators.css +++ b/src/styles/MyTripCollaborators.css @@ -25,7 +25,7 @@ .add-collaborator-btn { background: none; border: none; - color: #007bff; + color: var(--primary-color); cursor: pointer; padding: 5px; } @@ -63,7 +63,7 @@ } .add-collaborator-form button { - background-color: #007bff; + background-color: var(--primary-color); color: white; border: none; padding: 8px 15px; diff --git a/src/styles/NewTrip.css b/src/styles/NewTrip.css index 92ce358..109c6f0 100644 --- a/src/styles/NewTrip.css +++ b/src/styles/NewTrip.css @@ -74,18 +74,18 @@ } .react-calendar__tile--active { - background: #4285f4 !important; + background: var(--primary-color) !important; } .react-calendar__tile--rangeStart, .react-calendar__tile--rangeEnd { - background: #4285f4 !important; + background: var(--primary-color) !important; color: white !important; } .react-calendar__tile--inRange { background: #e8f0fe !important; - color: #4285f4 !important; + color: var(--primary-color) !important; } .trip-name-input { @@ -118,7 +118,7 @@ .location-search-input:focus { outline: none; - border-color: #4a90e2; + border-color: var(--primary-color); box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.2); } diff --git a/src/styles/PlaceDirections.css b/src/styles/PlaceDirections.css index 6e32507..b73604b 100644 --- a/src/styles/PlaceDirections.css +++ b/src/styles/PlaceDirections.css @@ -112,7 +112,7 @@ } .directions-search-result-item .phone { - color: #2196F3; + color: var(--primary-color); } .directions-place-actions { -- GitLab