From fedc8014f7842596a0eb75f6001061aa3c4c743f Mon Sep 17 00:00:00 2001
From: syddl0 <137189866+shroqkf@users.noreply.github.com>
Date: Tue, 13 May 2025 00:15:26 +0900
Subject: [PATCH 1/5] =?UTF-8?q?Fix:=20=EA=B2=80=EC=83=89=20=EA=B2=B0?=
=?UTF-8?q?=EA=B3=BC=20=EC=A7=80=EB=8F=84=20=EB=B0=98=EC=98=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/search/SearchPage.jsx | 2 +-
src/pages/search/components/MapViewer.jsx | 36 ++++
src/pages/search/hooks/useMapViewer.js | 218 ++++++++++++++++++++++
3 files changed, 255 insertions(+), 1 deletion(-)
create mode 100644 src/pages/search/components/MapViewer.jsx
create mode 100644 src/pages/search/hooks/useMapViewer.js
diff --git a/src/pages/search/SearchPage.jsx b/src/pages/search/SearchPage.jsx
index 5cbb388..98a4983 100644
--- a/src/pages/search/SearchPage.jsx
+++ b/src/pages/search/SearchPage.jsx
@@ -3,7 +3,6 @@ import SearchBar from "./components/SearchBar";
import RecentSearchList from "./components/RecentSearchList";
import PlaceList from "./components/SearchPlaceList";
import PlaceBottomSheet from "@pages/map/components/PlaceBottomSheet";
-import MapViewer from "../map/components/MapViewer";
import { getDistanceFromLatLon } from "../map/utils/getDistanceFromLatLon";
import { formatDistance } from "../map/utils/formatDistance";
import { getCompanyPreview } from "@apis/company/getCompanyPreview";
@@ -11,6 +10,7 @@ import { useCompanyData } from "./hooks/useCompanyData";
import { useUserCoords } from "./hooks/useUserCoords";
import useAuthStore from "@/store/authStore";
import HaveToLoginModal from "@components/common/HaveToLoginModal";
+import MapViewer from "./components/MapViewer";
const LOCAL_STORAGE_KEY = "recentSearches";
diff --git a/src/pages/search/components/MapViewer.jsx b/src/pages/search/components/MapViewer.jsx
new file mode 100644
index 0000000..5a04e70
--- /dev/null
+++ b/src/pages/search/components/MapViewer.jsx
@@ -0,0 +1,36 @@
+import { useRef } from "react";
+import useMapViewer from "../hooks/useMapViewer";
+
+const MapViewer = ({
+ places,
+ onMarkerClick,
+ userCoords,
+ moveToCurrentLocation,
+ onMoveComplete,
+ resetMap,
+ center,
+ markerPosition,
+ zoom = 11,
+ selectedPlace,
+ showOnlyLiked,
+}) => {
+ const mapRef = useRef(null);
+
+ useMapViewer({
+ mapRef,
+ places,
+ onMarkerClick,
+ userCoords,
+ moveToCurrentLocation,
+ onMoveComplete,
+ resetMap,
+ center,
+ markerPosition,
+ zoom,
+ selectedPlace,
+ });
+
+ return
;
+};
+
+export default MapViewer;
diff --git a/src/pages/search/hooks/useMapViewer.js b/src/pages/search/hooks/useMapViewer.js
new file mode 100644
index 0000000..248166f
--- /dev/null
+++ b/src/pages/search/hooks/useMapViewer.js
@@ -0,0 +1,218 @@
+import { useEffect, useRef, useCallback, useState } from "react";
+import { loadNaverMapScript } from "@pages/map/utils/loadMapScript";
+import {
+ createMarkerIcon,
+ createUserMarkerIcon,
+} from "@pages/map/utils/mapHelpers";
+
+const useMapViewer = ({
+ mapRef,
+ places,
+ onMarkerClick,
+ userCoords,
+ moveToCurrentLocation,
+ onMoveComplete,
+ resetMap,
+ center,
+ markerPosition,
+ zoom = 11,
+ selectedPlace,
+ showOnlyLiked,
+}) => {
+ const mapInstance = useRef(null);
+ const userMarkerRef = useRef(null);
+ const markersRef = useRef({});
+ const hasAnimatedRef = useRef(false);
+ const [isMapInitialized, setIsMapInitialized] = useState(false);
+
+ const handleMarkerClick = useCallback(
+ (place) => {
+ Object.values(markersRef.current).forEach((marker) => {
+ marker.setIcon(createMarkerIcon(false, false));
+ });
+
+ const clickedMarker = markersRef.current[place.id];
+ if (clickedMarker) {
+ clickedMarker.setIcon(
+ createMarkerIcon(true, showOnlyLiked ? place.liked : false),
+ );
+ }
+
+ onMarkerClick?.(place);
+ },
+ [onMarkerClick, showOnlyLiked],
+ );
+
+ useEffect(() => {
+ if (isMapInitialized || (!userCoords && !center)) return;
+
+ loadNaverMapScript().then(() => {
+ const mapCenter = center
+ ? new window.naver.maps.LatLng(center.lat, center.lng)
+ : new window.naver.maps.LatLng(37.5665, 126.978);
+
+ mapInstance.current = new window.naver.maps.Map(mapRef.current, {
+ center: mapCenter,
+ zoom,
+ });
+
+ setIsMapInitialized(true);
+
+ places.forEach((place) => {
+ if (!place.coords?.lat || !place.coords?.lng) return;
+
+ const isHighlighted =
+ place.isSearchResult ||
+ (selectedPlace && selectedPlace.id === place.id);
+
+ const marker = new window.naver.maps.Marker({
+ position: new window.naver.maps.LatLng(
+ place.coords.lat,
+ place.coords.lng,
+ ),
+ map: mapInstance.current,
+ icon: createMarkerIcon(isHighlighted, place.liked),
+ });
+
+ markersRef.current[place.id] = marker;
+
+ window.naver.maps.Event.addListener(marker, "click", () =>
+ handleMarkerClick(place),
+ );
+ });
+
+ if (markerPosition) {
+ new window.naver.maps.Marker({
+ position: new window.naver.maps.LatLng(
+ markerPosition.lat,
+ markerPosition.lng,
+ ),
+ map: mapInstance.current,
+ icon: createMarkerIcon(true),
+ });
+ }
+ });
+ }, [
+ userCoords,
+ places,
+ center,
+ zoom,
+ selectedPlace,
+ markerPosition,
+ handleMarkerClick,
+ isMapInitialized,
+ mapRef,
+ showOnlyLiked,
+ ]);
+
+ useEffect(() => {
+ if (
+ userCoords &&
+ mapInstance.current &&
+ !hasAnimatedRef.current &&
+ isMapInitialized
+ ) {
+ hasAnimatedRef.current = true;
+
+ const target = new window.naver.maps.LatLng(
+ userCoords.lat,
+ userCoords.lng,
+ );
+ mapInstance.current.panTo(target);
+
+ const zoomTimeout = setTimeout(() => {
+ mapInstance.current.setZoom(17, true);
+
+ if (userMarkerRef.current) {
+ userMarkerRef.current.setMap(null);
+ }
+
+ userMarkerRef.current = new window.naver.maps.Marker({
+ position: target,
+ map: mapInstance.current,
+ icon: createUserMarkerIcon(),
+ });
+ }, 1800);
+
+ return () => clearTimeout(zoomTimeout);
+ }
+ }, [userCoords, isMapInitialized]);
+
+ useEffect(() => {
+ if (moveToCurrentLocation && userCoords && mapInstance.current) {
+ const newCenter = new window.naver.maps.LatLng(
+ userCoords.lat,
+ userCoords.lng,
+ );
+ mapInstance.current.setCenter(newCenter);
+ mapInstance.current.setZoom(17);
+
+ if (userMarkerRef.current) userMarkerRef.current.setMap(null);
+
+ userMarkerRef.current = new window.naver.maps.Marker({
+ position: newCenter,
+ map: mapInstance.current,
+ icon: createUserMarkerIcon(),
+ });
+
+ onMoveComplete?.();
+ }
+ }, [moveToCurrentLocation, userCoords, onMoveComplete]);
+
+ useEffect(() => {
+ if (resetMap && mapInstance.current) {
+ mapInstance.current.setCenter(
+ new window.naver.maps.LatLng(37.5665, 126.978),
+ );
+ mapInstance.current.setZoom(11.5);
+
+ if (userMarkerRef.current) {
+ userMarkerRef.current.setMap(null);
+ userMarkerRef.current = null;
+ }
+ }
+ }, [resetMap]);
+
+ useEffect(() => {
+ if (!mapInstance.current || !isMapInitialized) return;
+
+ const currentMarkerIds = new Set(Object.keys(markersRef.current));
+ const newPlaceIds = new Set(places.map((p) => String(p.id)));
+
+ currentMarkerIds.forEach((id) => {
+ if (!newPlaceIds.has(id)) {
+ markersRef.current[id].setMap(null);
+ delete markersRef.current[id];
+ }
+ });
+
+ places.forEach((place) => {
+ const isHighlighted =
+ place.isSearchResult ||
+ (selectedPlace && selectedPlace.id === place.id);
+
+ const marker = markersRef.current[place.id];
+
+ if (!marker) {
+ const newMarker = new window.naver.maps.Marker({
+ position: new window.naver.maps.LatLng(
+ place.coords.lat,
+ place.coords.lng,
+ ),
+ map: mapInstance.current,
+ icon: createMarkerIcon(isHighlighted, place.liked),
+ });
+
+ markersRef.current[place.id] = newMarker;
+
+ window.naver.maps.Event.addListener(newMarker, "click", () =>
+ handleMarkerClick(place),
+ );
+ } else {
+ marker.setIcon(createMarkerIcon(isHighlighted, place.liked));
+ }
+ });
+ }, [places, selectedPlace, isMapInitialized, handleMarkerClick]);
+};
+
+export default useMapViewer;
From 157f3d1c8de3f1e3f9054345d75786c78afa9dc7 Mon Sep 17 00:00:00 2001
From: syddl0 <137189866+shroqkf@users.noreply.github.com>
Date: Tue, 13 May 2025 00:46:14 +0900
Subject: [PATCH 2/5] =?UTF-8?q?Fix:=20=EC=B0=9C=20=EB=B2=84=ED=8A=BC=20?=
=?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/map/components/PlaceContent.jsx | 20 ++++++--
src/pages/map/hooks/useToggleLike.js | 57 +++++++++++++++++------
2 files changed, 58 insertions(+), 19 deletions(-)
diff --git a/src/pages/map/components/PlaceContent.jsx b/src/pages/map/components/PlaceContent.jsx
index 6b5cb69..7c033d2 100644
--- a/src/pages/map/components/PlaceContent.jsx
+++ b/src/pages/map/components/PlaceContent.jsx
@@ -24,6 +24,7 @@ import { useState } from "react";
const PlaceContent = ({ place, onToggleLike, showMapLink = true }) => {
const userCoords = useUserCoords();
const [showToast, setShowToast] = useState(false);
+ const [isLiking, setIsLiking] = useState(false);
const handleRouteClick = (e) => {
e.preventDefault();
@@ -76,6 +77,20 @@ const PlaceContent = ({ place, onToggleLike, showMapLink = true }) => {
}
};
+ const handleLikeClick = async (e) => {
+ e.stopPropagation();
+ if (isLiking) return;
+
+ setIsLiking(true);
+ try {
+ await onToggleLike?.(place.id);
+ } catch (err) {
+ console.error("좋아요 처리 실패:", err);
+ } finally {
+ setIsLiking(false);
+ }
+ };
+
const fireIcons = {
10: IcFire10,
20: IcFire20,
@@ -157,10 +172,7 @@ const PlaceContent = ({ place, onToggleLike, showMapLink = true }) => {
)}