Skip to content

Commit

Permalink
Merge pull request #197 from boostcampwm-2022/feat/#196
Browse files Browse the repository at this point in the history
식당 마커 클릭 시 식당정보 미리보기 구현
  • Loading branch information
junghyunbak authored Dec 13, 2022
2 parents 2cb95b5 + 94d4a03 commit 98ea9bf
Show file tree
Hide file tree
Showing 13 changed files with 263 additions and 89 deletions.
55 changes: 19 additions & 36 deletions client/src/components/MainMap/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,27 @@ import hamburgerImageSrc from '@assets/images/hamburger.svg';
import hotdogImageSrc from '@assets/images/hotdog.svg';
import userImageSrc from '@assets/images/user.svg';

import { ReactComponent as GpsIcon } from '@assets/images/gps.svg';
import { ReactComponent as PointCircleIcon } from '@assets/images/point-circle.svg';

import { useMeetLocationStore, useSelectedCategoryStore } from '@store/index';
import {
useSelectedCategoryStore,
useMeetLocationStore,
useSelectedRestaurantDataStore,
useMapStore,
} from '@store/index';
import { useSocketStore } from '@store/socket';

import { CATEGORY_TYPE } from '@constants/category';
import { DEFAULT_ZOOM } from '@constants/map';

import LoadingScreen from '@components/LoadingScreen';
import { useNaverMaps } from '@hooks/useNaverMaps';
import useCurrentLocation from '@hooks/useCurrentLocation';

import classes from '@styles/marker.module.css';

import '@utils/MarkerClustering.js';

import { Socket } from 'socket.io-client';

import { MapControlBox, MapLayout, MapLoadingBox, MapBox } from './styles';
import { MapLayout, MapLoadingBox, MapBox } from './styles';

interface RestaurantType {
id: string;
Expand Down Expand Up @@ -73,15 +74,14 @@ function MainMap({ restaurantData, joinList }: PropsType) {

const joinListMarkersRef = useRef<Map<UserIdType, naver.maps.Marker>>(new Map());
const joinListInfoWindowsRef = useRef<Map<UserIdType, naver.maps.InfoWindow>>(new Map());

const infoWindowsRef = useRef<naver.maps.InfoWindow[]>([]);

const markerClusteringObjectsRef = useRef<Map<CATEGORY_TYPE, MarkerClustering>>(new Map());

const { selectedCategoryData } = useSelectedCategoryStore((state) => state);
const { socket } = useSocketStore((state) => state);
const { userLocation, updateUserLocation, getCurrentLocation } = useCurrentLocation();
const { meetLocation } = useMeetLocationStore();
const { updateMap } = useMapStore((state) => state);
const { meetLocation } = useMeetLocationStore((state) => state);
const { updateSelectedRestaurantData } = useSelectedRestaurantDataStore((state) => state);

const setMapLocation = (location: LocationType | naver.maps.Coord | null) => {
const map = mapRef.current;
Expand Down Expand Up @@ -305,8 +305,14 @@ function MainMap({ restaurantData, joinList }: PropsType) {
infoWindowsRef.current.push(infoWindow);

// 마커 클릭 이벤트 등록
naver.maps.Event.addListener(marker, 'click', () => {
naver.maps.Event.addListener(marker, 'click', (event) => {
infoWindow.open(map, marker);

updateSelectedRestaurantData(restaurant);

map.setCenter(marker.getPosition());

event.pointerEvent.stop();
});
});

Expand Down Expand Up @@ -340,6 +346,7 @@ function MainMap({ restaurantData, joinList }: PropsType) {

closeAllRestaurantMarkerInfoWindow();
closeAllUserMarkerInfoWindow();
updateSelectedRestaurantData(null);
});
return onDragendListener;
};
Expand Down Expand Up @@ -401,6 +408,7 @@ function MainMap({ restaurantData, joinList }: PropsType) {
return;
}

updateMap(mapRef.current);
setMeetingBoundary(mapRef.current);
const initListener = onInit(mapRef.current);
const clickListener = onClick(mapRef.current);
Expand Down Expand Up @@ -449,31 +457,6 @@ function MainMap({ restaurantData, joinList }: PropsType) {
</MapLoadingBox>
)}
<MapBox ref={mapDivRef} />
<MapControlBox>
<button type="button" onClick={() => setMapLocation(meetLocation)}>
<PointCircleIcon />
</button>
<button
type="button"
onClick={async () => {
/**
* MainPage로 이동 될 부분이라
* 함수로 따로 분리하지 않았습니다.
*/
if (!(socket instanceof Socket)) {
return;
}

const location = await getCurrentLocation();
socket.emit('changeMyLocation', { userLat: location.lat, userLng: location.lng });
updateUserLocation(location);

setMapLocation(userLocation);
}}
>
<GpsIcon />
</button>
</MapControlBox>
</MapLayout>
);
}
Expand Down
23 changes: 0 additions & 23 deletions client/src/components/MainMap/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,3 @@ export const MapBox = styled.div`
outline: none;
}
`;

export const MapControlBox = styled.div`
position: absolute;
left: 0;
bottom: 0;
margin: 0 0 18px 8px;
z-index: ${palette.MAP_CONTROLLER_Z_INDEX};
gap: 10px;
display: flex;
flex-direction: column;
button {
width: 40px;
height: 40px;
background-color: white;
border: none;
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0px 0px 4px rgb(0 0 0 / 50%);
}
`;
53 changes: 53 additions & 0 deletions client/src/components/MapController/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Socket } from 'socket.io-client';

import { ReactComponent as GpsIcon } from '@assets/images/gps.svg';
import { ReactComponent as PointCircleIcon } from '@assets/images/point-circle.svg';

import useCurrentLocation from '@hooks/useCurrentLocation';

import { useSocketStore } from '@store/socket';
import { useMeetLocationStore, useMapStore } from '@store/index';

import { MapControlBox } from './styles';

function MapController() {
const { getCurrentLocation, updateUserLocation } = useCurrentLocation();
const { socket } = useSocketStore((state) => state);
const { map } = useMapStore((state) => state);
const { meetLocation } = useMeetLocationStore();

return (
<MapControlBox>
<button
type="button"
onClick={async () => {
if (!(socket instanceof Socket) || !map) {
return;
}

const location = await getCurrentLocation();
socket.emit('changeMyLocation', { userLat: location.lat, userLng: location.lng });
updateUserLocation(location);

map.setCenter(location);
}}
>
<GpsIcon />
</button>
<button
type="button"
onClick={() => {
if (!map || !meetLocation) {
return;
}

map.setCenter(meetLocation);
}}
>
<PointCircleIcon />
</button>
</MapControlBox>
);
}

export default MapController;
25 changes: 25 additions & 0 deletions client/src/components/MapController/styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import styled from 'styled-components';
import * as palette from '@styles/Variables';

export const MapControlBox = styled.div`
position: absolute;
left: 0;
bottom: 0;
margin: 0 0 18px 8px;
z-index: ${palette.MAP_CONTROLLER_Z_INDEX};
gap: 10px;
display: flex;
flex-direction: column;
button {
width: 40px;
height: 40px;
background-color: white;
border: none;
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0px 0px 4px rgb(0 0 0 / 50%);
}
`;
8 changes: 8 additions & 0 deletions client/src/components/RestaurantDetailLayer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ function RestaurantDetailLayer() {
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 999 }}
transition={{ duration: 1 }}
/**
* 식당 요약정보 -> 식당 상세정보 경로로 레이어가 열렸을 때
* 다시 돌아갔을 경우에도 식당 요약정보가 닫히지 않도록 하기 위함.
* window에 등록한 이벤트 리스너를 실행시키지 않는다.
*/
onClick={(event) => {
event.stopPropagation();
}}
>
<RestaurantDetailModal
updateRestaurantDetailLayerStatus={updateRestaurantDetailLayerStatus}
Expand Down
62 changes: 62 additions & 0 deletions client/src/components/RestaurantPreview/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useEffect, useRef } from 'react';
import RestaurantRow from '@components/RestaurantRow';
import { AnimatePresence } from 'framer-motion';
import { useRestaurantDetailLayerStatusStore, useSelectedRestaurantDataStore } from '@store/index';
import { RESTAURANT_LIST_TYPES, RESTAURANT_DETAIL_TYPES } from '@constants/modal';
import { RestaurantPreviewBox, RestaurantPreviewLayout } from './styles';

function RestaurantPreview() {
const modalRef = useRef<HTMLDivElement>(null);

const { updateRestaurantDetailLayerStatus } = useRestaurantDetailLayerStatusStore(
(state) => state
);
const { selectedRestaurantData, updateSelectedRestaurantData } = useSelectedRestaurantDataStore(
(state) => state
);

useEffect(() => {
const modalCloseWindowEvent = (e: Event) => {
const { target } = e;

if (modalRef.current && target instanceof HTMLElement && modalRef.current.contains(target)) {
return;
}

updateSelectedRestaurantData(null);
};

window.addEventListener('click', modalCloseWindowEvent);

return () => {
window.removeEventListener('click', modalCloseWindowEvent);
};
}, []);

return (
<RestaurantPreviewLayout ref={modalRef}>
{selectedRestaurantData && (
<AnimatePresence>
<RestaurantPreviewBox
initial={{ opacity: 0, y: '100%' }}
animate={{ opacity: 1, y: '0%' }}
exit={{ opacity: 0, y: '100%' }}
transition={{
duration: 0.5,
}}
onClick={() => {
updateRestaurantDetailLayerStatus(RESTAURANT_DETAIL_TYPES.show);
}}
>
<RestaurantRow
restaurant={selectedRestaurantData}
restaurantListType={RESTAURANT_LIST_TYPES.filtered}
/>
</RestaurantPreviewBox>
</AnimatePresence>
)}
</RestaurantPreviewLayout>
);
}

export default RestaurantPreview;
14 changes: 14 additions & 0 deletions client/src/components/RestaurantPreview/styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import styled from 'styled-components';
import * as palette from '@styles/Variables';
import { motion } from 'framer-motion';

export const RestaurantPreviewLayout = styled.div`
z-index: ${palette.MAP_CONTROLLER_Z_INDEX};
`;

export const RestaurantPreviewBox = styled(motion.div)`
width: 100%;
border-top-right-radius: 5px;
border-top-left-radius: 5px;
padding: 1% 3% 2% 3%;
`;
2 changes: 0 additions & 2 deletions client/src/components/RestaurantRow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import { RESTAURANT_LIST_TYPES } from '@constants/modal';
import RestaurantVoteButton from '@components/RestaurantVoteButton';
import { distanceToDisplay } from '@utils/distance';

import { useEffect, useState } from 'react';
import { NAVER_LAT, NAVER_LNG } from '@constants/map';
import {
RestaurantRowBox,
DistanceBox,
Expand Down
3 changes: 1 addition & 2 deletions client/src/components/RestaurantRow/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ export const RestaurantRowBox = styled(motion.div)`
background-color: white;
box-sizing: border-box;
border-radius: 10px;
border: 0.1px solid ${palette.BORDER};
box-shadow: 0 0 3px 3px ${palette.BORDER};
box-shadow: 0 0 3px 2px ${palette.BORDER};
flex: none;
display: flex;
flex-direction: row;
Expand Down
Loading

0 comments on commit 98ea9bf

Please sign in to comment.