Skip to content

Commit

Permalink
feat: google map 지도로 변경 (#162)
Browse files Browse the repository at this point in the history
* refactor: 음식점 API 타입 지정 (#134)

Co-authored-by: Minjae Kim <[email protected]>
Co-authored-by: 황준승 <[email protected]>

* fix: Map 컴포넌트 위경도 뒤바뀜 오류 수정 (#134)

* refactor: 음식점 카드 컴포넌트 API명세에 맞게 수정 (#134)

* refactor: 불필요한 export 제거 (#134)

Co-authored-by: Minjae Kim <[email protected]>
Co-authored-by: 황준승 <[email protected]>

* refactor: handler 타입 지정 (#134)

Co-authored-by: Minjae Kim <[email protected]>
Co-authored-by: 황준승 <[email protected]>

* feat: 메인페이지 UI구현 (#134)

Co-authored-by: Minjae Kim <[email protected]>
Co-authored-by: 황준승 <[email protected]>

* style: 위경도 타입 파일로 분리 (#134)

Co-authored-by: Minjae Kim <[email protected]>
Co-authored-by: 황준승 <[email protected]>

* feat: 음식점 카드 클릭시 메인좌표 이동 기능 구현 (#134)

Co-authored-by: Minjae Kim <[email protected]>
Co-authored-by: 황준승 <[email protected]>

* design: footer 문구 수정 (#138)

Co-authored-by: Minjae Kim <[email protected]>
Co-authored-by: 황준승 <[email protected]>

* feat: 음식점 클릭시 마커 구분 (#134)

* refactor: 메인페이지 scroll 개선 및 footer 추가 (#134)

* feat: 맵 모달 구현 (#134)

* refactor: MainPage 파일 제거

* refactor: MainPage 파일 복구 (#134)

* feat: 데이터 생성 (#134)

* refactor: search bar 파일 제거 (#134)

* feat: 음식점 카드 클릭시 기능 구현 (#134)

* feat: 지도 모달 안의 컨텐츠 구성 (#134)

* refactor: 메인페이지 디자인 수정 및 음식점 개수 동기화 (#134)

* design: 모달 내 폰트사이즈 수정 (#134)

* refactor: 지도 2중 생성 오류 처리 및 훅 분리 (#134)

지도 생성 로직 분리

* feat: 지도 마커 클릭시 음식점 정보 확인 기능 구현 (#134)

* refactor: 불필요한 코드 삭제 (#134)

* fix: 이미지 import 오류 해결 (#134)

* fix: lint 오류 해결 (#134)

* refactor: 카카오 지도 코드 제거 (#151)

* chore: 구글 지도 환경 설정 (#151)

react-wrapper 라이브러리 설치

* feat: 구글 지도 기본 화면 구현 (#151)

* feat: property명 구글 api에 맞게 수정 (#151)

latitude -> lat, longitude-> lng

* feat: 지도에 레스토랑 마커 구현 (#151)

* feat: 레스토랑 카드 클릭 시 해당 좌표로 지도 이동 (#151)

* feat: 마커 클릭 시 해당 좌표로 지도 이동 및 모달 슬라이드업 구현 (#151)

* feat: 지도 언어 한국어로 설정 (#151)

* feat: 지도 컴포넌트 스토리북 구현 (#151)

* fix: 변수명 오류 수정 (#151)

* feat: 전제조회 비동기 구현 (#151)

* fix: lint error 수정 (#151)

---------

Co-authored-by: Minjae Kim <[email protected]>
Co-authored-by: 황준승 <[email protected]>
  • Loading branch information
3 people authored and TaeyeonRoyce committed Aug 3, 2023
1 parent c500324 commit f330973
Show file tree
Hide file tree
Showing 17 changed files with 181 additions and 5,598 deletions.
7 changes: 0 additions & 7 deletions frontend/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,5 @@ const config: StorybookConfig = {

return config;
},
previewHead: head => `
${head}
<script
type="text/javascript"
src="//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.KAKAO_MAP_API_KEY}&libraries=services"
></script>
`,
};
export default config;
32 changes: 17 additions & 15 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,30 @@
"test": "jest"
},
"dependencies": {
"@testing-library/jest-dom": "^5.16.5",
"msw": "^1.2.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"styled-components": "^6.0.2",
"webpack": "^5.88.1",
"webpack-cli": "^5.1.4",
"html-webpack-plugin": "^5.5.3",
"fork-ts-checker-webpack-plugin": "^8.0.0",
"dotenv": "^16.3.1",
"interpolate-html-plugin": "^4.0.0",
"copy-webpack-plugin": "^11.0.0",
"ts-loader": "^9.4.4",
"@googlemaps/react-wrapper": "^1.1.35",
"@storybook/react": "^7.0.25",
"@storybook/react-webpack5": "^7.0.25",
"@testing-library/jest-dom": "^5.16.5",
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@types/styled-components": "^5.1.26",
"babel-plugin-root-import": "^6.6.0",
"copy-webpack-plugin": "^11.0.0",
"dotenv": "^16.3.1",
"fork-ts-checker-webpack-plugin": "^8.0.0",
"html-webpack-plugin": "^5.5.3",
"interpolate-html-plugin": "^4.0.0",
"msw": "^1.2.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"storybook": "^7.0.25",
"styled-components": "^6.0.2",
"ts-loader": "^9.4.4",
"typescript": "^5.1.6",
"webpack": "^5.88.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"webpack-merge": "^5.9.0",
"babel-plugin-root-import": "^6.6.0"
"webpack-merge": "^5.9.0"
},
"devDependencies": {
"@babel/core": "^7.22.5",
Expand All @@ -54,6 +55,7 @@
"@stylelint/postcss-css-in-js": "^0.38.0",
"@svgr/webpack": "^8.0.1",
"@testing-library/react": "^14.0.0",
"@types/google.maps": "^3.53.5",
"@types/jest": "^29.5.3",
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
Expand Down
4 changes: 0 additions & 4 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>celuveat</title>
<script
type="text/javascript"
src="//dapi.kakao.com/v2/maps/sdk.js?appkey=%KAKAO_MAP_API_KEY%&libraries=services"
></script>
</head>
<body>
<noscript>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/@types/api.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ export interface RestaurantData {
name: string;
category: string;
roadAddress: string;
latitude: number;
longitude: number;
lat: number;
lng: number;
phoneNumber: string;
naverMapUrl: string;
celebs: { id: number; name: string; youtubeChannelName: string; profileImageUrl: string }[];
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/@types/map.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface Coordinate {
longitude: number;
latitude: number;
lng: number;
lat: number;
}
2 changes: 1 addition & 1 deletion frontend/src/@types/restaurant.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { RestaurantData } from './api.types';

export type Restaurant = Omit<RestaurantData, 'celebs'>;
export type RestaurantModalInfo = Omit<Restaurant, 'latitude' | 'longitude'>;
export type RestaurantModalInfo = Omit<Restaurant, 'lat' | 'lng'>;
7 changes: 6 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { Wrapper } from '@googlemaps/react-wrapper';
import MainPage from './pages/MainPage';

function App() {
return <MainPage />;
return (
<Wrapper apiKey={process.env.GOOGLE_MAP_API_KEY} language="ko">
<MainPage />
</Wrapper>
);
}

export default App;
34 changes: 14 additions & 20 deletions frontend/src/components/@common/Map/Map.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { Wrapper } from '@googlemaps/react-wrapper';
import type { Meta, StoryObj } from '@storybook/react';
import Map from './Map';

const meta: Meta<typeof Map> = {
title: 'Map',
component: Map,
decorators: [
Story => (
<Wrapper apiKey={process.env.GOOGLE_MAP_API_KEY} language="ko">
{/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it */}
<Story />
</Wrapper>
),
],
};

export default meta;
Expand All @@ -12,25 +21,10 @@ type Story = StoryObj<typeof Map>;

export const Default: Story = {
args: {
width: '500px',
height: '300px',
level: 3,
mainPosition: { longitude: 127.050727, latitude: 37.5057482 },
markers: [{ longitude: 127.050727, latitude: 37.5057482 }],
},
};

export const MapWithManyMarkers: Story = {
args: {
width: '1000px',
height: '400px',
level: 6,
mainPosition: { longitude: 127.050727, latitude: 37.5057482 },
markers: [
{ longitude: 127.023432, latitude: 37.5043233 },
{ longitude: 127.050727, latitude: 37.5057482 },
{ longitude: 127.034234, latitude: 37.5023415 },
{ longitude: 127.062341, latitude: 37.5123423 },
],
center: { lat: 37.5057482, lng: 127.050727 },
zoom: 12,
size: { width: '600px', height: '600px' },
restaurants: [],
clickMarker: () => {},
},
};
88 changes: 20 additions & 68 deletions frontend/src/components/@common/Map/Map.tsx
Original file line number Diff line number Diff line change
@@ -1,77 +1,29 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-new */
/* eslint-disable @typescript-eslint/no-explicit-any */

import { useEffect, useRef, useState } from 'react';
import { useRef } from 'react';
import { styled } from 'styled-components';
import { RestaurantData } from '~/@types/api.types';
import useDrawMap from './hooks/useDrawMap';
import useMarker from './hooks/useMarker';
import { Coordinate } from '~/@types/map.types';
import useCreateMap from './hooks/useCreateMap';

interface MapProps {
width: string;
height: string;
level: number;
mainPosition: Coordinate;
markers: Coordinate[];
markerClickEvent: (position: Coordinate) => void;
center: google.maps.LatLngLiteral;
zoom: number;
size: { width: string; height: string };
restaurants: RestaurantData[];
clickMarker: ({ lat, lng }: Coordinate) => void;
}

function Map({ width, height, level, mainPosition, markers, markerClickEvent }: MapProps) {
const container = useRef();
const { kakaoMap } = useCreateMap({ mainPosition, level, container });
const { latitude, longitude } = mainPosition;
const [currentMarker, setCurrentMarker] = useState(null);

const kakaoMakers = markers.map(marker => {
const position = new window.kakao.maps.LatLng(marker.latitude, marker.longitude);
const imageSize = new window.kakao.maps.Size(24, 35);
const imageSrc = 'https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/markerStar.png';
const markerImage = new window.kakao.maps.MarkerImage(imageSrc, imageSize);

return new window.kakao.maps.Marker({
map: kakaoMap,
position,
image: markerImage,
});
});

useEffect(() => {
if (!kakaoMap) return;

kakaoMakers.forEach(marker => {
const markerLatitude = Number(marker.getPosition().getLat().toFixed(7));
const markerLongitude = Number(marker.getPosition().getLng().toFixed(7));

marker.setMap(kakaoMap);
marker.setZIndex(1);

window.kakao.maps.event.addListener(marker, 'click', () => {
markerClickEvent({ latitude: markerLatitude, longitude: markerLongitude });
});
});
}, [kakaoMap]);
function Map({ center, zoom, size, restaurants, clickMarker }: MapProps) {
const googleMapRef = useRef();
const { googleMap } = useDrawMap({ mapRef: googleMapRef, center, zoom });
useMarker({ map: googleMap, restaurants, clickMarker });

useEffect(() => {
if (!kakaoMap) return;
if (currentMarker) currentMarker.setMap(null);
// 이동할 위도 경도 위치를 생성합니다
const position = new window.kakao.maps.LatLng(latitude, longitude);

// 지도 중심을 이동 시킵니다
kakaoMap.setCenter(position);

// 마커를 생성합니다
const newMarker = new window.kakao.maps.Marker({
map: kakaoMap,
position,
});

newMarker.setMap(kakaoMap);
newMarker.setZIndex(2);

setCurrentMarker(newMarker);
}, [mainPosition]);

return <div ref={container} style={{ width, height }} />;
return <StyledMap ref={googleMapRef} size={size} id="map" />;
}

export default Map;

const StyledMap = styled.div<{ size: { width: string; height: string } }>`
width: ${({ size }) => size.width};
height: ${({ size }) => size.height};
`;
8 changes: 4 additions & 4 deletions frontend/src/components/@common/Map/hooks/useCreateMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import { useEffect, useState } from 'react';
import { Coordinate } from '~/@types/map.types';

const useCreateMap = ({
mainPosition,
center,
level,
container,
}: {
mainPosition: Coordinate;
center: Coordinate;
level: number;
container: React.RefObject<HTMLDivElement>;
}) => {
const { latitude, longitude } = mainPosition;
const { lat, lng } = center;
const [kakaoMap, setKakaoMap] = useState(null);

useEffect(() => {
const options = {
center: new window.kakao.maps.LatLng(latitude, longitude),
center: new window.kakao.maps.LatLng(lat, lng),
level,
};
const map = new window.kakao.maps.Map(container.current, options);
Expand Down
29 changes: 29 additions & 0 deletions frontend/src/components/@common/Map/hooks/useDrawMap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useState } from 'react';

interface UseDrawMapProps {
mapRef: React.MutableRefObject<HTMLDivElement>;
center: google.maps.LatLngLiteral;
zoom: number;
}

const useDrawMap = ({ mapRef, center, zoom }: UseDrawMapProps) => {
const [googleMap, setGoogleMap] = useState<google.maps.Map>(null);

// center를 중심으로 지도 그리기 로직
useEffect(() => {
const newMap = new window.google.maps.Map(mapRef.current, { center, zoom });

setGoogleMap(newMap);
}, [mapRef]);

useEffect(() => {
if (!googleMap) return;

googleMap.panTo(center);
}, [center]);

return { googleMap };
};

export default useDrawMap;
39 changes: 39 additions & 0 deletions frontend/src/components/@common/Map/hooks/useMarker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useState } from 'react';
import { RestaurantData } from '~/@types/api.types';
import { Coordinate } from '~/@types/map.types';

interface UseMarkerProps {
map: google.maps.Map;
restaurants: RestaurantData[];
clickMarker: ({ lat, lng }: Coordinate) => void;
}

const useMarker = ({ map, restaurants, clickMarker }: UseMarkerProps) => {
const [markers, setMarkers] = useState([]);
// 마커를 지도에 표시하는 로직
useEffect(() => {
if (!map) return;

const newMarkers = restaurants.map(restaurant => {
const { lat, lng } = restaurant;
const newMarker = new window.google.maps.Marker({
position: { lat, lng },
map,
});
newMarker.setMap(map);

newMarker.addListener('click', () => {
clickMarker({ lat, lng });
});

return newMarker;
});

setMarkers(newMarkers);
}, [map, restaurants]);

return { markers };
};

export default useMarker;
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export const Default: Story = {
name: '스시렌',
category: '일식당',
roadAddress: '서울 강남구 선릉로146길 27-8 2F',
latitude: 37.5222779,
longitude: 127.0423149,
lat: 37.5222779,
lng: 127.0423149,
phoneNumber: '010-8072-2032',
naverMapUrl: 'https://naver.me/58HxhMsl',
images: [
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/RestaurantCard/RestaurantCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function RestaurantCard({ restaurant, celebs, size, onClick }: RestaurantCardPro

return (
<StyledContainer onClick={onClick}>
<StyledImage alt={`${name} 대표 이미지`} src={`images/${images[0].name}`} />
<StyledImage alt={`${name} 대표 이미지`} src={`image-data/${images[0].name}`} />
<StyledInfo>
<StyledCategory>{category}</StyledCategory>
<h5>{name}</h5>
Expand Down
Loading

0 comments on commit f330973

Please sign in to comment.