diff --git a/frontend/src/components/google-maps/map/CarFfeineMap.tsx b/frontend/src/components/google-maps/map/CarFfeineMap.tsx index e2cf86f85..330f4266d 100644 --- a/frontend/src/components/google-maps/map/CarFfeineMap.tsx +++ b/frontend/src/components/google-maps/map/CarFfeineMap.tsx @@ -5,7 +5,7 @@ import DataDownloader from '@ui/DataDownloader'; import CarFfeineMapListener from './CarFfeineListener'; const UserFilterListener = lazy(() => import('./UserFilterListener')); -const MarkersContainers = lazy(() => import('@marker/MarkerContainers')); +const MarkersContainers = lazy(() => import('@marker/components/MarkerContainers')); const ToastContainer = lazy(() => import('@ui/ToastContainer')); const ClientStationFilters = lazy(() => import('@ui/ClientStationFilters')); const MapController = lazy(() => import('@ui/MapController')); diff --git a/frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/LargeDeltaAreaMarkerContainer.tsx b/frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/LargeDeltaAreaMarkerContainer.tsx deleted file mode 100644 index e847de937..000000000 --- a/frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/LargeDeltaAreaMarkerContainer.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { useEffect } from 'react'; - -import { markerInstanceStore } from '@stores/google-maps/markerInstanceStore'; - -import { useClusterMarkers } from './hooks/useClusterMarkers'; -import { useRenderClusterMarkers } from './hooks/useRenderClusterMarker'; - -const LargeDeltaAreaMarkerContainer = () => { - const { data: clusterMarkers, isSuccess } = useClusterMarkers(); - - const { - createNewMarkerInstances, - getRemainedMarkerInstances, - removeMarkersOutsideBounds, - removeAllMarkers, - renderClusterMarkers, - } = useRenderClusterMarkers(); - - useEffect(() => { - return () => { - // MarkerContainers 컴포넌트에서 SmallMediumDeltaAreaMarkerContainer 컴포넌트가 unmount될 때 모든 마커를 지워준다. - removeAllMarkers(markerInstanceStore.getState()); - }; - }, []); - - if (clusterMarkers === undefined || !isSuccess) { - return <>; - } - - const newMarkerInstances = createNewMarkerInstances( - markerInstanceStore.getState(), - clusterMarkers - ); - - const remainedMarkerInstances = getRemainedMarkerInstances( - markerInstanceStore.getState(), - clusterMarkers - ); - - removeMarkersOutsideBounds(markerInstanceStore.getState(), clusterMarkers); - renderClusterMarkers(newMarkerInstances, clusterMarkers); - - markerInstanceStore.setState([...remainedMarkerInstances, ...newMarkerInstances]); - - return <>; -}; - -export default LargeDeltaAreaMarkerContainer; diff --git a/frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/hooks/useRenderClusterMarker.tsx b/frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/hooks/useRenderClusterMarker.tsx deleted file mode 100644 index 966d47cce..000000000 --- a/frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/hooks/useRenderClusterMarker.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import { createRoot } from 'react-dom/client'; - -import StyledClusterMarker from '@marker/LargeDeltaAreaMarkerContainer/components/StyledClusterMarker'; - -import { getStoreSnapshot } from '@utils/external-state/tools'; - -import { getGoogleMapStore, googleMapActions } from '@stores/google-maps/googleMapStore'; -import type { MarkerInstance } from '@stores/google-maps/markerInstanceStore'; - -import type { ClusterMarker } from '@type'; - -export const useRenderClusterMarkers = () => { - const googleMap = getStoreSnapshot(getGoogleMapStore()); - - const createNewMarkerInstances = ( - prevMarkerInstances: MarkerInstance[], - markers: ClusterMarker[] - ) => { - const newMarkers = markers.filter((marker) => - prevMarkerInstances.every((prevMarker) => prevMarker.id !== marker.id) - ); - - const newMarkerInstances = newMarkers.map((marker) => { - const { latitude: lat, longitude: lng, id, count } = marker; - - const markerInstance = new google.maps.marker.AdvancedMarkerElement({ - position: { lat, lng }, - title: `영역 내 충전소 개수: ${count}`, - }); - - return { - id, - instance: markerInstance, - }; - }); - - bindMarkerClickHandler(newMarkerInstances, newMarkers); - - return newMarkerInstances; - }; - - const removeMarkersOutsideBounds = ( - prevMarkerInstances: MarkerInstance[], - currentMarkers: ClusterMarker[] - ) => { - const markersOutOfBounds = prevMarkerInstances.filter((prevMarker) => - currentMarkers.every((currentMarker) => currentMarker.id !== prevMarker.id) - ); - - markersOutOfBounds.forEach((marker) => { - marker.instance.map = null; - }); - }; - - const removeAllMarkers = (prevMarkerInstances: MarkerInstance[]) => { - prevMarkerInstances.forEach((marker) => { - marker.instance.map = null; - }); - }; - - const getRemainedMarkerInstances = ( - prevMarkerInstances: MarkerInstance[], - currentMarkers: ClusterMarker[] - ) => { - return prevMarkerInstances.filter((markerInstance) => - currentMarkers.some((marker) => marker.id === markerInstance.id) - ); - }; - - const renderClusterMarkers = (markerInstances: MarkerInstance[], markers: ClusterMarker[]) => { - markerInstances.forEach(({ instance: markerInstance, id }) => { - const container = document.createElement('div'); - - container.style.opacity = '0'; - container.classList.add('marker-animation'); - container.addEventListener('animationend', () => { - container.classList.remove('marker-animation'); - container.style.opacity = '1'; - }); - - markerInstance.content = container; - markerInstance.map = googleMap; - - const markerInformation = markers.find((clusterMarker) => clusterMarker.id === id); - - createRoot(container).render(); - }); - }; - - const bindMarkerClickHandler = ( - markerInstances: MarkerInstance[], - newMarkers: ClusterMarker[] - ) => { - markerInstances.forEach(({ instance: markerInstance, id: stationId }) => { - markerInstance.addListener('click', () => { - const targetMarker = newMarkers.find((marker) => marker.id === stationId); - const currentZoom = googleMap.getZoom(); - - googleMapActions.moveTo( - { lat: targetMarker.latitude, lng: targetMarker.longitude }, - currentZoom + 1 - ); - }); - }); - }; - - return { - createNewMarkerInstances, - removeMarkersOutsideBounds, - getRemainedMarkerInstances, - renderClusterMarkers, - removeAllMarkers, - }; -}; diff --git a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/components/RegionMarkerRenderer.tsx b/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/components/RegionMarkerRenderer.tsx deleted file mode 100644 index b3233bfda..000000000 --- a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/components/RegionMarkerRenderer.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { useEffect } from 'react'; - -import { useRenderRegionMarker } from '../hooks/useRenderRegionMarker'; -import type { Region } from '../types'; - -export interface RegionMarkerProps { - region: Region; -} - -const RegionMarkerRenderer = ({ region }: RegionMarkerProps) => { - const { renderRegionMarker } = useRenderRegionMarker(); - - useEffect(() => { - const unmountRegionMarker = renderRegionMarker(region); - - return unmountRegionMarker; - }, []); - - return <>; -}; - -export default RegionMarkerRenderer; diff --git a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/hooks/useRenderRegionMarker.tsx b/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/hooks/useRenderRegionMarker.tsx deleted file mode 100644 index 7e2448542..000000000 --- a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/hooks/useRenderRegionMarker.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { createRoot } from 'react-dom/client'; - -import { useExternalValue } from '@utils/external-state'; - -import { getGoogleMapStore, googleMapActions } from '@stores/google-maps/googleMapStore'; - -import RegionMarker from '../components/RegionMarker'; -import type { Region } from '../types'; - -export const useRenderRegionMarker = () => { - const googleMap = useExternalValue(getGoogleMapStore()); - - const renderRegionMarker = (region: Region) => { - const { latitude, longitude, count, regionName } = region; - - const container = document.createElement('div'); - - container.style.opacity = '0'; - container.classList.add('marker-animation'); - container.addEventListener('animationend', () => { - container.classList.remove('marker-animation'); - container.style.opacity = '1'; - }); - - const markerInstance = new google.maps.marker.AdvancedMarkerElement({ - position: { lat: latitude, lng: longitude }, - map: googleMap, - title: regionName, - content: container, - }); - - createRoot(container).render(); - - markerInstance.addListener('click', () => { - googleMapActions.moveTo({ lat: latitude, lng: longitude }, 12); - }); - - return () => { - markerInstance.map = null; - }; - }; - - return { renderRegionMarker }; -}; diff --git a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/SmallMediumDeltaAreaMarkerContainer.tsx b/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/SmallMediumDeltaAreaMarkerContainer.tsx deleted file mode 100644 index 05915ecc8..000000000 --- a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/SmallMediumDeltaAreaMarkerContainer.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { useEffect } from 'react'; - -import { useStationMarkers } from '@marker/SmallMediumDeltaAreaMarkerContainer/hooks/useStationMarkers'; - -import { useExternalValue } from '@utils/external-state'; - -import { deltaAreaStore } from '@stores/google-maps/deltaAreaStore'; -import type { DeltaAreaState } from '@stores/google-maps/deltaAreaStore/types'; -import type { MarkerInstance } from '@stores/google-maps/markerInstanceStore'; -import { markerInstanceStore } from '@stores/google-maps/markerInstanceStore'; - -import { useRenderStationMarker } from './hooks/useRenderStationMarker'; - -const SmallMediumDeltaAreaMarkerContainer = () => { - const { data: stationMarkers, isSuccess } = useStationMarkers(); - const { - createNewMarkerInstances, - getRemainedMarkerInstances, - removeMarkersOutsideBounds, - removeAllMarkers, - renderDefaultMarkers, - renderCarffeineMarkers, - } = useRenderStationMarker(); - const deltaAreaState = useExternalValue(deltaAreaStore); - - const renderMarkerByDeltaAreaState = ( - deltaAreaState: DeltaAreaState, - markerInstances: MarkerInstance[] - ) => { - if (deltaAreaState === 'small') { - renderCarffeineMarkers(markerInstances, stationMarkers); - } - if (deltaAreaState === 'medium') { - renderDefaultMarkers(markerInstances, stationMarkers); - } - }; - - useEffect(() => { - if (stationMarkers !== undefined) { - renderMarkerByDeltaAreaState(deltaAreaState, markerInstanceStore.getState()); - } - }, [deltaAreaState]); - - useEffect(() => { - return () => { - // MarkerContainers 컴포넌트에서 HighZoomMarkerContainer 컴포넌트가 unmount될 때 모든 마커를 지워준다. - removeAllMarkers(markerInstanceStore.getState()); - }; - }, []); - - if (stationMarkers === undefined || !isSuccess) { - return <>; - } - - const newMarkerInstances = createNewMarkerInstances( - markerInstanceStore.getState(), - stationMarkers - ); - - const remainedMarkerInstances = getRemainedMarkerInstances( - markerInstanceStore.getState(), - stationMarkers - ); - - removeMarkersOutsideBounds(markerInstanceStore.getState(), stationMarkers); - renderMarkerByDeltaAreaState(deltaAreaState, newMarkerInstances); - - markerInstanceStore.setState([...remainedMarkerInstances, ...newMarkerInstances]); - - return <>; -}; - -export default SmallMediumDeltaAreaMarkerContainer; diff --git a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/hooks/useRenderStationMarker.tsx b/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/hooks/useRenderStationMarker.tsx deleted file mode 100644 index 039cb0d93..000000000 --- a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/hooks/useRenderStationMarker.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import { createRoot } from 'react-dom/client'; - -import { getStoreSnapshot } from '@utils/external-state/tools'; - -import { getGoogleMapStore } from '@stores/google-maps/googleMapStore'; -import type { MarkerInstance } from '@stores/google-maps/markerInstanceStore'; - -import { useStationInfoWindow } from '@hooks/google-maps/useStationInfoWindow'; -import useMediaQueries from '@hooks/useMediaQueries'; - -import { useNavigationBar } from '@ui/Navigator/NavigationBar/hooks/useNavigationBar'; -import StationDetailsWindow from '@ui/StationDetailsWindow'; - -import type { StationDetails, StationMarker, StationSummary } from '@type'; - -import CarFfeineMarker from '../components/CarFfeineMarker'; -import { MARKER_COLORS } from '../components/CarFfeineMarker/CarFfeineMarker.style'; -import { DEFAULT_MARKER_SIZE_RATIO } from '../constants'; - -export const useRenderStationMarker = () => { - const googleMap = getStoreSnapshot(getGoogleMapStore()); - - const { openStationInfoWindow } = useStationInfoWindow(); - const { openLastPanel } = useNavigationBar(); - const screen = useMediaQueries(); - - const createNewMarkerInstance = (marker: StationDetails) => { - const { latitude: lat, longitude: lng, stationName, stationId } = marker; - - const markerInstance = new google.maps.marker.AdvancedMarkerElement({ - position: { lat, lng }, - title: stationName, - }); - - bindMarkerClickHandler([{ id: stationId, instance: markerInstance }]); - - return markerInstance; - }; - - const createNewMarkerInstances = ( - prevMarkerInstances: MarkerInstance[], - markers: StationMarker[] - ) => { - const newMarkers = markers.filter((marker) => - prevMarkerInstances.every((prevMarker) => prevMarker.id !== marker.stationId) - ); - - const newMarkerInstances = newMarkers.map((marker) => { - const { latitude: lat, longitude: lng, stationName, stationId: id } = marker; - - const markerInstance = new google.maps.marker.AdvancedMarkerElement({ - position: { lat, lng }, - title: stationName, - }); - - return { - id, - instance: markerInstance, - }; - }); - - bindMarkerClickHandler(newMarkerInstances); - - return newMarkerInstances; - }; - - const removeMarkersOutsideBounds = ( - prevMarkerInstances: MarkerInstance[], - currentMarkers: StationMarker[] - ) => { - const markersOutOfBounds = prevMarkerInstances.filter((prevMarker) => - currentMarkers.every((currentMarker) => currentMarker.stationId !== prevMarker.id) - ); - - markersOutOfBounds.forEach((marker) => { - marker.instance.map = null; - }); - }; - - const removeAllMarkers = (prevMarkerInstances: MarkerInstance[]) => { - prevMarkerInstances.forEach((marker) => { - marker.instance.map = null; - }); - }; - - const getRemainedMarkerInstances = ( - prevMarkerInstances: MarkerInstance[], - currentMarkers: StationMarker[] - ) => { - return prevMarkerInstances.filter((markerInstance) => - currentMarkers.some((marker) => marker.stationId === markerInstance.id) - ); - }; - - const renderDefaultMarkers = ( - markerInstances: MarkerInstance[], - markers: StationMarker[] | StationSummary[] - ) => { - markers.forEach((marker) => { - const markerInstance = markerInstances.find( - (markerInstance) => markerInstance.id === marker.stationId - )?.instance; - - const markerColor = - marker.availableCount > 0 ? MARKER_COLORS.available : MARKER_COLORS.noAvailable; - - if (markerInstance) { - const defaultMarkerDesign = new google.maps.marker.PinElement({ - scale: DEFAULT_MARKER_SIZE_RATIO, - background: markerColor.background, - borderColor: markerColor.border, - glyph: '', - }); - - markerInstance.map = googleMap; - defaultMarkerDesign.element.style.opacity = '0'; - defaultMarkerDesign.element.classList.add('marker-animation'); - defaultMarkerDesign.element.addEventListener('animationend', () => { - defaultMarkerDesign.element.classList.remove('marker-animation'); - defaultMarkerDesign.element.style.opacity = '1'; - }); - markerInstance.content = defaultMarkerDesign.element; - } - }); - }; - - const renderCarffeineMarkers = ( - markerInstances: MarkerInstance[], - markers: StationMarker[] | StationSummary[] - ) => { - markerInstances.forEach(({ instance: markerInstance, id: stationId }) => { - const container = document.createElement('div'); - container.style.opacity = '0'; - container.classList.add('marker-animation'); - container.addEventListener('animationend', () => { - container.classList.remove('marker-animation'); - container.style.opacity = '1'; - }); - markerInstance.content = container; - markerInstance.map = googleMap; - - const markerInformation = markers.find( - (stationMarker) => stationMarker.stationId === stationId - ); - - createRoot(container).render(); - }); - }; - - const bindMarkerClickHandler = (markerInstances: MarkerInstance[]) => { - markerInstances.forEach(({ instance: markerInstance, id: stationId }) => { - markerInstance.addListener('click', () => { - openStationInfoWindow(stationId, markerInstance); - - if (!screen.get('isMobile')) { - openLastPanel(); - } - }); - }); - }; - - return { - createNewMarkerInstance, - createNewMarkerInstances, - removeMarkersOutsideBounds, - getRemainedMarkerInstances, - renderDefaultMarkers, - renderCarffeineMarkers, - removeAllMarkers, - }; -}; diff --git a/frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/LargeDeltaAreaMarkerContainer.tsx b/frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/LargeDeltaAreaMarkerContainer.tsx new file mode 100644 index 000000000..640b5c693 --- /dev/null +++ b/frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/LargeDeltaAreaMarkerContainer.tsx @@ -0,0 +1,20 @@ +import ClusterMarkerRenderer from './components/ClusterMarkerRenderer'; +import { useClusterMarkersQuery } from './hooks/useClusterMarkersQuery'; + +const LargeDeltaAreaMarkerContainer = () => { + const { data: clusterMarkers, isSuccess } = useClusterMarkersQuery(); + + if (clusterMarkers === undefined || !isSuccess) { + return <>; + } + + return ( + <> + {clusterMarkers.map((cluster) => ( + + ))} + + ); +}; + +export default LargeDeltaAreaMarkerContainer; diff --git a/frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/components/ClusterMarkerRenderer.tsx b/frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/components/ClusterMarkerRenderer.tsx new file mode 100644 index 000000000..bb88db6fa --- /dev/null +++ b/frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/components/ClusterMarkerRenderer.tsx @@ -0,0 +1,23 @@ +import { useLayoutEffect } from 'react'; + +import { useMarker } from '@marker/hooks/useMarker'; + +import type { ClusterMarker } from '@type'; + +interface Props { + cluster: ClusterMarker; +} + +const ClusterMarkerRenderer = ({ cluster }: Props) => { + const { renderClusterMarker } = useMarker(); + + useLayoutEffect(() => { + const unmount = renderClusterMarker(cluster); + + return unmount; + }, []); + + return <>; +}; + +export default ClusterMarkerRenderer; diff --git a/frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/components/StyledClusterMarker.stories.tsx b/frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/components/StyledClusterMarker.stories.tsx similarity index 100% rename from frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/components/StyledClusterMarker.stories.tsx rename to frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/components/StyledClusterMarker.stories.tsx diff --git a/frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/components/StyledClusterMarker.tsx b/frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/components/StyledClusterMarker.tsx similarity index 100% rename from frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/components/StyledClusterMarker.tsx rename to frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/components/StyledClusterMarker.tsx diff --git a/frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/hooks/useClusterMarkers.ts b/frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/hooks/useClusterMarkersQuery.ts similarity index 98% rename from frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/hooks/useClusterMarkers.ts rename to frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/hooks/useClusterMarkersQuery.ts index 5805ee557..167c43342 100644 --- a/frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/hooks/useClusterMarkers.ts +++ b/frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/hooks/useClusterMarkersQuery.ts @@ -64,7 +64,7 @@ export const fetchClusterMarkers = async () => { return clusterMarkers; }; -export const useClusterMarkers = () => { +export const useClusterMarkersQuery = () => { return useQuery({ queryKey: [QUERY_KEY_CLUSTER_MARKERS], queryFn: fetchClusterMarkers, diff --git a/frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/index.ts b/frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/index.ts similarity index 100% rename from frontend/src/components/google-maps/marker/LargeDeltaAreaMarkerContainer/index.ts rename to frontend/src/components/google-maps/marker/components/LargeDeltaAreaMarkerContainer/index.ts diff --git a/frontend/src/components/google-maps/marker/MarkerContainers.tsx b/frontend/src/components/google-maps/marker/components/MarkerContainers/MarkerContainers.tsx similarity index 62% rename from frontend/src/components/google-maps/marker/MarkerContainers.tsx rename to frontend/src/components/google-maps/marker/components/MarkerContainers/MarkerContainers.tsx index 90e1389d8..15321f940 100644 --- a/frontend/src/components/google-maps/marker/MarkerContainers.tsx +++ b/frontend/src/components/google-maps/marker/components/MarkerContainers/MarkerContainers.tsx @@ -2,9 +2,9 @@ import { useExternalValue } from '@utils/external-state'; import { deltaAreaStore } from '@stores/google-maps/deltaAreaStore'; -import LargeDeltaAreaMarkerContainer from './LargeDeltaAreaMarkerContainer'; -import MaxDeltaAreaMarkerContainer from './MaxDeltaAreaMarkerContainer'; -import SmallMediumDeltaAreaMarkerContainer from './SmallMediumDeltaAreaMarkerContainer'; +import LargeDeltaAreaMarkerContainer from '../LargeDeltaAreaMarkerContainer'; +import MaxDeltaAreaMarkerContainer from '../MaxDeltaAreaMarkerContainer'; +import SmallMediumDeltaAreaMarkerContainer from '../SmallMediumDeltaAreaMarkerContainer/SmallMediumDeltaAreaContainer'; const MarkerContainers = () => { const deltaAreaState = useExternalValue(deltaAreaStore); @@ -14,7 +14,6 @@ const MarkerContainers = () => { {(deltaAreaState === 'medium' || deltaAreaState === 'small') && ( )} - {/* 이 아래는 앞으로 추가될 기능을 미리 대응하는 컴포넌트 */} {deltaAreaState === 'large' && } {deltaAreaState === 'max' && } diff --git a/frontend/src/components/google-maps/marker/components/MarkerContainers/index.ts b/frontend/src/components/google-maps/marker/components/MarkerContainers/index.ts new file mode 100644 index 000000000..441fb451f --- /dev/null +++ b/frontend/src/components/google-maps/marker/components/MarkerContainers/index.ts @@ -0,0 +1,3 @@ +import MarkerContainers from './MarkerContainers'; + +export default MarkerContainers; diff --git a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/MaxDeltaAreaMarkerContainer.tsx b/frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/MaxDeltaAreaMarkerContainer.tsx similarity index 83% rename from frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/MaxDeltaAreaMarkerContainer.tsx rename to frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/MaxDeltaAreaMarkerContainer.tsx index 4bc5adc1a..f8c668f9d 100644 --- a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/MaxDeltaAreaMarkerContainer.tsx +++ b/frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/MaxDeltaAreaMarkerContainer.tsx @@ -1,8 +1,8 @@ import RegionMarkerRenderer from './components/RegionMarkerRenderer'; -import { useRegionMarkers } from './hooks/useRegionMarkers'; +import { useRegionMarkersQuery } from './hooks/useRegionMarkersQuery'; const MaxDeltaAreaMarkerContainer = () => { - const { data: regions, isSuccess, isError } = useRegionMarkers(); + const { data: regions, isSuccess, isError } = useRegionMarkersQuery(); if (!regions || !isSuccess || isError) { return <>; } diff --git a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/components/RegionMarker.stories.tsx b/frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/components/RegionMarker.stories.tsx similarity index 100% rename from frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/components/RegionMarker.stories.tsx rename to frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/components/RegionMarker.stories.tsx diff --git a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/components/RegionMarker.tsx b/frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/components/RegionMarker.tsx similarity index 100% rename from frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/components/RegionMarker.tsx rename to frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/components/RegionMarker.tsx diff --git a/frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/components/RegionMarkerRenderer.tsx b/frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/components/RegionMarkerRenderer.tsx new file mode 100644 index 000000000..01d3ef12a --- /dev/null +++ b/frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/components/RegionMarkerRenderer.tsx @@ -0,0 +1,23 @@ +import { useLayoutEffect } from 'react'; + +import { useMarker } from '@marker/hooks/useMarker'; + +import type { Region } from '../types'; + +export interface RegionMarkerProps { + region: Region; +} + +const RegionMarkerRenderer = ({ region }: RegionMarkerProps) => { + const { renderRegionMarker } = useMarker(); + + useLayoutEffect(() => { + const unmount = renderRegionMarker(region); + + return unmount; + }, []); + + return <>; +}; + +export default RegionMarkerRenderer; diff --git a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/hooks/useRegionMarkers.ts b/frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/hooks/useRegionMarkersQuery.ts similarity index 94% rename from frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/hooks/useRegionMarkers.ts rename to frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/hooks/useRegionMarkersQuery.ts index df81c25f6..97c9f49b9 100644 --- a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/hooks/useRegionMarkers.ts +++ b/frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/hooks/useRegionMarkersQuery.ts @@ -20,7 +20,7 @@ export const fetchRegionMarkers = async () => { return stationMarkers; }; -export const useRegionMarkers = () => { +export const useRegionMarkersQuery = () => { return useQuery({ queryKey: [QUERY_KEY_REGION_MARKERS], queryFn: fetchRegionMarkers, diff --git a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/index.ts b/frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/index.ts similarity index 100% rename from frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/index.ts rename to frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/index.ts diff --git a/frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/types/index.ts b/frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/types/index.ts similarity index 100% rename from frontend/src/components/google-maps/marker/MaxDeltaAreaMarkerContainer/types/index.ts rename to frontend/src/components/google-maps/marker/components/MaxDeltaAreaMarkerContainer/types/index.ts diff --git a/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/SmallMediumDeltaAreaContainer.tsx b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/SmallMediumDeltaAreaContainer.tsx new file mode 100644 index 000000000..d11f6e0cb --- /dev/null +++ b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/SmallMediumDeltaAreaContainer.tsx @@ -0,0 +1,31 @@ +import { useExternalValue } from '@utils/external-state'; + +import { deltaAreaStore } from '@stores/google-maps/deltaAreaStore'; + +import CarffeineMarkerRenderer from './components/marker/CarffeineMarkerRenderer'; +import DefaultMarkerRenderer from './components/marker/DefaultMarkerRenderer'; +import { useStationMarkersQuery } from './hooks/useStationMarkersQuery'; + +const SmallMediumDeltaAreaMarkerContainer = () => { + const { data: stationMarkers, isSuccess } = useStationMarkersQuery(); + const deltaAreaState = useExternalValue(deltaAreaStore); + + if (!isSuccess) { + return <>; + } + + return ( + <> + {stationMarkers.map((stationMarker) => { + if (deltaAreaState === 'small') { + return ; + } + if (deltaAreaState === 'medium') { + return ; + } + })} + + ); +}; + +export default SmallMediumDeltaAreaMarkerContainer; diff --git a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeine.stories.tsx b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeine.stories.tsx similarity index 100% rename from frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeine.stories.tsx rename to frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeine.stories.tsx diff --git a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.style.ts b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.style.ts similarity index 100% rename from frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.style.ts rename to frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.style.ts diff --git a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.test.tsx b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.test.tsx similarity index 100% rename from frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.test.tsx rename to frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.test.tsx diff --git a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.tsx b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.tsx similarity index 100% rename from frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.tsx rename to frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.tsx diff --git a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/index.ts b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/index.ts similarity index 100% rename from frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/index.ts rename to frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/index.ts diff --git a/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/marker/CarffeineMarkerRenderer.tsx b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/marker/CarffeineMarkerRenderer.tsx new file mode 100644 index 000000000..9f5e50160 --- /dev/null +++ b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/marker/CarffeineMarkerRenderer.tsx @@ -0,0 +1,23 @@ +import { useLayoutEffect } from 'react'; + +import { useMarker } from '@marker/hooks/useMarker'; + +import type { StationMarker } from '@type'; + +interface Props { + station: StationMarker; +} + +const CarffeineMarkerRenderer = ({ station }: Props) => { + const { renderCarffeineMarker } = useMarker(); + + useLayoutEffect(() => { + const unmount = renderCarffeineMarker(station); + + return unmount; + }, []); + + return <>; +}; + +export default CarffeineMarkerRenderer; diff --git a/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/marker/DefaultMarkerRenderer.tsx b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/marker/DefaultMarkerRenderer.tsx new file mode 100644 index 000000000..8672e2401 --- /dev/null +++ b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/components/marker/DefaultMarkerRenderer.tsx @@ -0,0 +1,28 @@ +import { useLayoutEffect } from 'react'; + +import { useMarker } from '@marker/hooks/useMarker'; + +import { markerInstanceStore } from '@stores/google-maps/markerInstanceStore'; + +import type { StationMarker } from '@type'; + +interface Props { + station: StationMarker; +} + +const DefaultMarkerRenderer = ({ station }: Props) => { + const { renderDefaultMarker } = useMarker(); + + useLayoutEffect(() => { + // 검색 결과로 강제 생성한 마커에 대해선 새로운 마커 생성을 시도하지 않도록 한다. + if (markerInstanceStore.getState().every(({ id }) => id !== station.stationId)) { + const unmount = renderDefaultMarker(station); + + return unmount; + } + }, []); + + return <>; +}; + +export default DefaultMarkerRenderer; diff --git a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/constants/index.ts b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/constants/index.ts similarity index 100% rename from frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/constants/index.ts rename to frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/constants/index.ts diff --git a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/hooks/useStationMarkers.ts b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/hooks/useStationMarkersQuery.ts similarity index 98% rename from frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/hooks/useStationMarkers.ts rename to frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/hooks/useStationMarkersQuery.ts index e95f9277c..0adfb295b 100644 --- a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/hooks/useStationMarkers.ts +++ b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/hooks/useStationMarkersQuery.ts @@ -90,7 +90,7 @@ export const fetchStationMarkers = async () => { return stationMarkers; }; -export const useStationMarkers = () => { +export const useStationMarkersQuery = () => { const { fastChargeStationFilter, privateStationFilter, diff --git a/frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/index.ts b/frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/index.ts similarity index 100% rename from frontend/src/components/google-maps/marker/SmallMediumDeltaAreaMarkerContainer/index.ts rename to frontend/src/components/google-maps/marker/components/SmallMediumDeltaAreaMarkerContainer/index.ts diff --git a/frontend/src/components/google-maps/marker/hooks/useMarker.tsx b/frontend/src/components/google-maps/marker/hooks/useMarker.tsx new file mode 100644 index 000000000..5611a8df4 --- /dev/null +++ b/frontend/src/components/google-maps/marker/hooks/useMarker.tsx @@ -0,0 +1,141 @@ +import { createRoot } from 'react-dom/client'; + +import StyledClusterMarker from '@marker/components/LargeDeltaAreaMarkerContainer/components/StyledClusterMarker'; +import RegionMarker from '@marker/components/MaxDeltaAreaMarkerContainer/components/RegionMarker'; +import type { Region } from '@marker/components/MaxDeltaAreaMarkerContainer/types'; +import CarFfeineMarker from '@marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker'; +import { + addMarkerInstanceToExternalStore, + createMarkerDomElement, + createMarkerInstance, + getDefaultMarkerDesign, + removeMarkerInstanceFromExternalStore, +} from '@marker/tools'; + +import { getGoogleMapStore, googleMapActions } from '@stores/google-maps/googleMapStore'; + +import { useStationInfoWindow } from '@hooks/google-maps/useStationInfoWindow'; +import useMediaQueries from '@hooks/useMediaQueries'; + +import { useNavigationBar } from '@ui/Navigator/NavigationBar/hooks/useNavigationBar'; +import StationDetailsWindow from '@ui/StationDetailsWindow'; + +import type { ClusterMarker, StationMarker } from '@type'; + +export const useMarker = () => { + const screen = useMediaQueries(); + const { openLastPanel } = useNavigationBar(); + const { openStationInfoWindow } = useStationInfoWindow(); + + const renderDefaultMarker = (station: StationMarker) => { + const { latitude, longitude, stationId } = station; + + const defaultMarkerDesign = getDefaultMarkerDesign(station.availableCount > 0); + const markerInstance = createMarkerInstance(latitude, longitude); + + markerInstance.content = defaultMarkerDesign.element; + + bindStationMarkerClickEvent(markerInstance, stationId); + addMarkerInstanceToExternalStore(markerInstance, stationId); + + return () => { + markerInstance.map = null; + removeMarkerInstanceFromExternalStore(stationId); + }; + }; + + const renderCarffeineMarker = (station: StationMarker) => { + const { latitude, longitude, stationId } = station; + const markerInstance = createMarkerInstance(latitude, longitude); + const container = createMarkerDomElement(); + + markerInstance.content = container; + + bindStationMarkerClickEvent(markerInstance, stationId); + addMarkerInstanceToExternalStore(markerInstance, stationId); + + createRoot(container).render(); + + return () => { + markerInstance.map = null; + removeMarkerInstanceFromExternalStore(stationId); + }; + }; + + const renderClusterMarker = (cluster: ClusterMarker) => { + const { latitude, longitude, count } = cluster; + + const markerInstance = createMarkerInstance(latitude, longitude); + const container = createMarkerDomElement(); + + markerInstance.content = container; + + bindClusterMarkerClickEvent(markerInstance, cluster); + createRoot(container).render(); + + return () => { + markerInstance.map = null; + }; + }; + + const renderRegionMarker = (region: Region) => { + const { latitude, longitude, count, regionName } = region; + + const markerInstance = createMarkerInstance(latitude, longitude); + const container = createMarkerDomElement(); + + markerInstance.title = regionName; + markerInstance.content = container; + + bindRegionMarkerClickEvent(markerInstance, region); + createRoot(container).render(); + + return () => { + markerInstance.map = null; + }; + }; + + const bindStationMarkerClickEvent = ( + markerInstance: google.maps.marker.AdvancedMarkerElement, + stationId: string + ) => { + markerInstance.addListener('click', () => { + openStationInfoWindow(stationId, markerInstance); + + if (!screen.get('isMobile')) { + openLastPanel(); + } + }); + }; + + const bindClusterMarkerClickEvent = ( + markerInstance: google.maps.marker.AdvancedMarkerElement, + cluster: ClusterMarker + ) => { + const { latitude, longitude } = cluster; + + markerInstance.addListener('click', () => { + const currentZoom = getGoogleMapStore().getState().getZoom(); + + googleMapActions.moveTo({ lat: latitude, lng: longitude }, currentZoom + 1); + }); + }; + + const bindRegionMarkerClickEvent = ( + markerInstance: google.maps.marker.AdvancedMarkerElement, + region: Region + ) => { + const { latitude, longitude } = region; + + markerInstance.addListener('click', () => { + googleMapActions.moveTo({ lat: latitude, lng: longitude }, 12); + }); + }; + + return { + renderDefaultMarker, + renderCarffeineMarker, + renderClusterMarker, + renderRegionMarker, + }; +}; diff --git a/frontend/src/components/google-maps/marker/tools/index.ts b/frontend/src/components/google-maps/marker/tools/index.ts new file mode 100644 index 000000000..65eadd767 --- /dev/null +++ b/frontend/src/components/google-maps/marker/tools/index.ts @@ -0,0 +1,58 @@ +import { MARKER_COLORS } from '@marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.style'; +import { DEFAULT_MARKER_SIZE_RATIO } from '@marker/components/SmallMediumDeltaAreaMarkerContainer/constants'; + +import { getGoogleMapStore } from '@stores/google-maps/googleMapStore'; +import { markerInstanceStore } from '@stores/google-maps/markerInstanceStore'; + +const animateMarkers = (marker: HTMLElement) => { + marker.style.opacity = '0'; + marker.classList.add('marker-animation'); + + marker.addEventListener('animationend', () => { + marker.classList.remove('marker-animation'); + marker.style.opacity = '1'; + }); +}; + +export const getDefaultMarkerDesign = (isAvailable: boolean) => { + const markerColor = isAvailable ? MARKER_COLORS.available : MARKER_COLORS.noAvailable; + + const defaultMarkerDesign = new google.maps.marker.PinElement({ + scale: DEFAULT_MARKER_SIZE_RATIO, + background: markerColor.background, + borderColor: markerColor.border, + glyph: '', + }); + + animateMarkers(defaultMarkerDesign.element); + + return defaultMarkerDesign; +}; + +export const createMarkerDomElement = () => { + const container = document.createElement('div'); + + animateMarkers(container); + + return container; +}; + +export const createMarkerInstance = (latitude: number, longitude: number) => { + const markerInstance = new google.maps.marker.AdvancedMarkerElement({ + position: new google.maps.LatLng(latitude, longitude), + map: getGoogleMapStore().getState(), + }); + + return markerInstance; +}; + +export const addMarkerInstanceToExternalStore = ( + instance: google.maps.marker.AdvancedMarkerElement, + id: string +) => { + markerInstanceStore.setState((prev) => [...prev, { id, instance }]); +}; + +export const removeMarkerInstanceFromExternalStore = (id: string) => { + markerInstanceStore.setState((prev) => prev.filter((markerInstance) => markerInstance.id !== id)); +}; diff --git a/frontend/src/components/ui/MapController.tsx b/frontend/src/components/ui/MapController.tsx index 6b19f454c..055378cee 100644 --- a/frontend/src/components/ui/MapController.tsx +++ b/frontend/src/components/ui/MapController.tsx @@ -3,8 +3,8 @@ import { css } from 'styled-components'; import { BiCurrentLocation } from 'react-icons/bi'; -import { useClusterMarkers } from '@marker/LargeDeltaAreaMarkerContainer/hooks/useClusterMarkers'; -import { useStationMarkers } from '@marker/SmallMediumDeltaAreaMarkerContainer/hooks/useStationMarkers'; +import { useClusterMarkersQuery } from '@marker/components/LargeDeltaAreaMarkerContainer/hooks/useClusterMarkersQuery'; +import { useStationMarkersQuery } from '@marker/components/SmallMediumDeltaAreaMarkerContainer/hooks/useStationMarkersQuery'; import { googleMapActions } from '@stores/google-maps/googleMapStore'; @@ -15,8 +15,8 @@ import Loader from '@common/Loader'; import { MOBILE_BREAKPOINT } from '@constants'; const MapController = () => { - const { isFetching: isStationMarkerFetching } = useStationMarkers(); - const { isFetching: isClusterMarkerFetching } = useClusterMarkers(); + const { isFetching: isStationMarkerFetching } = useStationMarkersQuery(); + const { isFetching: isClusterMarkerFetching } = useClusterMarkersQuery(); const isMarkerFetching = isStationMarkerFetching || isClusterMarkerFetching; diff --git a/frontend/src/components/ui/StationInfoWindow/StationInfo.tsx b/frontend/src/components/ui/StationInfoWindow/StationInfo.tsx index cf8a569dd..61abc25ea 100644 --- a/frontend/src/components/ui/StationInfoWindow/StationInfo.tsx +++ b/frontend/src/components/ui/StationInfoWindow/StationInfo.tsx @@ -4,7 +4,7 @@ import { getChargerCountsAndAvailability } from '@tools/getChargerCountsAndAvail import type { MouseEvent } from 'react'; import { HiChevronRight } from 'react-icons/hi2'; -import { MARKER_COLORS } from '@marker/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.style'; +import { MARKER_COLORS } from '@marker/components/SmallMediumDeltaAreaMarkerContainer/components/CarFfeineMarker/CarFfeineMarker.style'; import Box from '@common/Box'; import Button from '@common/Button'; diff --git a/frontend/src/components/ui/StationListWindow/StationList.tsx b/frontend/src/components/ui/StationListWindow/StationList.tsx index fe329d473..1834ae1ac 100644 --- a/frontend/src/components/ui/StationListWindow/StationList.tsx +++ b/frontend/src/components/ui/StationListWindow/StationList.tsx @@ -2,7 +2,7 @@ import { css } from 'styled-components'; import { useEffect, useRef } from 'react'; -import { useStationMarkers } from '@marker/SmallMediumDeltaAreaMarkerContainer/hooks/useStationMarkers'; +import { useStationMarkersQuery } from '@marker/components/SmallMediumDeltaAreaMarkerContainer/hooks/useStationMarkersQuery'; import List from '@common/List'; import Text from '@common/Text'; @@ -18,7 +18,7 @@ import { useInfiniteStationSummaries } from './hooks/useInfiniteStationSummaries import { cachedStationSummariesActions } from './tools/cachedStationSummaries'; const StationList = () => { - const { data: filteredMarkers } = useStationMarkers(); + const { data: filteredMarkers } = useStationMarkersQuery(); const { data, isLoading, isError, isFetchingNextPage, fetchNextPage, hasNextPage, error } = useInfiniteStationSummaries(filteredMarkers ?? []); diff --git a/frontend/src/components/ui/StationSearchWindow/hooks/useStationSearchWindow.tsx b/frontend/src/components/ui/StationSearchWindow/hooks/useStationSearchWindow.tsx index e4f0b5b67..a10871607 100644 --- a/frontend/src/components/ui/StationSearchWindow/hooks/useStationSearchWindow.tsx +++ b/frontend/src/components/ui/StationSearchWindow/hooks/useStationSearchWindow.tsx @@ -1,11 +1,11 @@ +import { getChargerCountsAndAvailability } from '@tools/getChargerCountsAndAvailability'; + import type { ChangeEvent, FocusEvent, FormEvent, MouseEvent } from 'react'; import { useState } from 'react'; import { useQueryClient } from '@tanstack/react-query'; -import { useRenderStationMarker } from '@marker/SmallMediumDeltaAreaMarkerContainer/hooks/useRenderStationMarker'; - -import { useSetExternalState } from '@utils/external-state'; +import { useMarker } from '@marker/hooks/useMarker'; import { googleMapActions } from '@stores/google-maps/googleMapStore'; import { markerInstanceStore } from '@stores/google-maps/markerInstanceStore'; @@ -16,17 +16,12 @@ import useMediaQueries from '@hooks/useMediaQueries'; import { useNavigationBar } from '@ui/Navigator/NavigationBar/hooks/useNavigationBar'; -import { - QUERY_KEY_SEARCHED_STATION, - QUERY_KEY_STATION_DETAILS, - QUERY_KEY_STATION_MARKERS, -} from '@constants/queryKeys'; +import { QUERY_KEY_SEARCHED_STATION } from '@constants/queryKeys'; import { SERVER_URL } from '@constants/server'; import type { StationDetails, StationPosition } from '@type'; import StationDetailsWindow from '../../StationDetailsWindow/index'; -import { convertStationDetailsToSummary } from '../tools/convertStationDetailsToSummary'; export const useStationSearchWindow = () => { const queryClient = useQueryClient(); @@ -34,11 +29,10 @@ export const useStationSearchWindow = () => { const [isFocused, setIsFocused] = useState(false); const [searchWord, setSearchWord] = useState(''); - const setMarkerInstances = useSetExternalState(markerInstanceStore); + const { renderDefaultMarker } = useMarker(); const { openLastPanel } = useNavigationBar(); const { openStationInfoWindow } = useStationInfoWindow(); - const { createNewMarkerInstance, renderDefaultMarkers } = useRenderStationMarker(); const screen = useMediaQueries(); @@ -67,7 +61,6 @@ export const useStationSearchWindow = () => { const showStationDetails = async ({ stationId, latitude, longitude }: StationPosition) => { googleMapActions.moveTo({ lat: latitude, lng: longitude }); - queryClient.invalidateQueries({ queryKey: [QUERY_KEY_STATION_MARKERS] }); if (!screen.get('isMobile')) { openLastPanel(); @@ -84,19 +77,23 @@ export const useStationSearchWindow = () => { const stationDetails = await fetch( `${SERVER_URL}/stations/${stationId}` ).then((response) => response.json()); - - const markerInstance = createNewMarkerInstance(stationDetails); - - setMarkerInstances((prev) => [...prev, { id: stationId, instance: markerInstance }]); - - renderDefaultMarkers( - [{ id: stationId, instance: markerInstance }], - [convertStationDetailsToSummary(stationDetails)] + const { quickChargerCount, availableCount } = getChargerCountsAndAvailability( + stationDetails.chargers ); + const { stationName, latitude, longitude, isParkingFree, isPrivate } = stationDetails; + + renderDefaultMarker({ + stationId, + stationName, + latitude, + longitude, + isParkingFree, + isPrivate, + availableCount, + quickChargerCount, + }); - openStationInfoWindow(stationId, markerInstance); - - queryClient.setQueryData([QUERY_KEY_STATION_DETAILS, stationId], stationDetails); + openStationInfoWindow(stationId); } }; diff --git a/frontend/src/mocks/data/regions.ts b/frontend/src/mocks/data/regions.ts index 5dc59d42b..cdf37ed42 100644 --- a/frontend/src/mocks/data/regions.ts +++ b/frontend/src/mocks/data/regions.ts @@ -1,4 +1,4 @@ -import type { Region, RegionName } from '@marker/MaxDeltaAreaMarkerContainer/types'; +import type { Region, RegionName } from '@marker/components/MaxDeltaAreaMarkerContainer/types'; export const regions: Region[] = [ { diff --git a/frontend/src/mocks/handlers/station-markers/stationMarkerHandlers.ts b/frontend/src/mocks/handlers/station-markers/stationMarkerHandlers.ts index 0e0f42618..8ac994b81 100644 --- a/frontend/src/mocks/handlers/station-markers/stationMarkerHandlers.ts +++ b/frontend/src/mocks/handlers/station-markers/stationMarkerHandlers.ts @@ -101,7 +101,7 @@ export const stationMarkerHandlers = [ console.log('찾은 충전소 갯수: ' + foundStations.length); return res( - // ctx.delay(1000), + ctx.delay(1000), ctx.status(200), ctx.json({ stations: foundStations, diff --git a/frontend/src/tools/getChargerCountsAndAvailability.ts b/frontend/src/tools/getChargerCountsAndAvailability.ts index 1026cda26..9d6748471 100644 --- a/frontend/src/tools/getChargerCountsAndAvailability.ts +++ b/frontend/src/tools/getChargerCountsAndAvailability.ts @@ -18,6 +18,7 @@ export const getChargerCountsAndAvailability = (chargers: Charger[]) => { const availableQuickChargerCount = quickChargers.filter( ({ state }) => state === 'STANDBY' ).length; + const availableCount = availableStandardChargerCount + availableQuickChargerCount; const standardChargerCount = standardChargers.length; const quickChargerCount = quickChargers.length; @@ -28,5 +29,6 @@ export const getChargerCountsAndAvailability = (chargers: Charger[]) => { availableQuickChargerCount, standardChargerCount, quickChargerCount, + availableCount, }; };