-
아마존 E-commerce 클론 -29) Google Map적용하기NODE.JS 2021. 5. 30. 15:38
먼저 console.cloud.google.com에가서 프로젝트를 생성한다.
새로운 credential을 생성한다.
키를 복사해서
enable을 클릭하고 manage로 들어간다.
아까 복사한 api key를 최상위 폴더의 .env파일에 저장한다.
JWT_SECRET = somethingsecret PAYPAL_CLIENT_ID = AeYAR3plI8AMo9Tmu-NUmDnNzEk5K1Pmhu1csipoH_Y7RGnOi5s6fcJywoGgahvu4ENE9ran7hBCAqoq GOOGLE_API_KEY = AIzaSyD_nYNcNYSFLZiSqDN29mnbdKUTPb93Neg
다음과 같이 googleAPI를 입력한다.
server.js(paypal처럼)
app.get('/api/config/google', (req, res) => { res.send(process.env.GOOGLE_API_KEY || ''); });
frontend 폴더로 가서 npm install @react-google-maps/api 해준다.
이제 지도를 보여줄 페이지를 만든다.
screens>MapScreen.js
import React, { useEffect, useState,useRef } from 'react' import LoadingBox from '../components/LoadingBox' import {LoadScript,GoogleMap,StandaloneSearchBox,Marker} from '@react-google-maps/api'; import axios from '../../node_modules/axios/index'; import { USER_ADDRESSS_MAP_CONFIRM } from '../constants/userConstants'; import { useDispatch } from 'react-redux'; const libs=['places']; const defaultLocation = {lat:45.516, lng:-73.56}; function MapScreen() { const [googleApiKey, setGoogleApiKey] = useState('') const [center, setCenter] = useState(defaultLocation)//얘는 googlemap을 위해서 const [location, setLocation] = useState(center)//얘는 Marker를 위해서 const mapRef = useRef(null); const placeRef = useRef(null); const markerRef = useRef(null); useEffect(() => { const fetch = async ()=>{ const{data} = await axios.Cancel('/api/config/google');//백엔드에서 googleApiKey를 받아온다. setGoogleApiKey(data); getUserCurrentLocation(); } fetch(); }, []) const onLoad= (map)=>{ mapRef.current = map; } const onMarkerLoad = (marker)=>{ markerRef.current = marker; } const onLoadPlaces = (place)=>{ placeRef.current = place } const onIdle = ()=>{ setLocation({lat:mapRef.current.center.lat(), lng:mapRef.current.center.lng()}) } const onPlacesChanged =()=>{ const place = placeRef.current.getPlaces()[0].geometry.location; setCenter({lat:place.lat(), lng:place.lng()}) setLocation({lat:place.lat(), lng:place.lng()}) } const dispatch = useDispatch() const onConfirm = ()=>{ const places = placeRef.current.getPlaces(); if(places && places.length ===1){ dispatch({ type:USER_ADDRESSS_MAP_CONFIRM,//주소를 확정짓는 action작성 payload:{ lat:location.lat, lng:location.lng, address:places[0].formatted_address, name:places[0].name, vicinity:places[0].vicinity, googleAddressId:places[0].id } }) alert('location selecte successfully') }else{ alert('Please enter your address') } } const getUserCurrentLocation = ()=>{//사용자의 현재위치 받아오기 if(!navigator.geolocation){ alert('Geolocation is not supported by this browser.') }else{ navigator.geolocation.getCurrentPosition((position)=>{ setCenter({ lat:position.coords.latitude, lng:position.coords.longitude }) setLocation({ lat:position.coords.latitude, lng:position.coords.longitude }) }) } } return googleApiKey ? ( <div className="full-container"> <LoadScript libraries={libs} googleMapsApiKey={googleApiKey}> <GoogleMap id="sample-map" mapContainerStyle={{height:'100%',width:'100%' }} center={center} zoom={15} onLoad={onLoad}onIdle={onIdle} > <StandaloneSearchBox onLoad={onLoadPlaces} onPlacesChanged={onPlacesChanged}> <div className="map-input-box"> <input type="text" placeholder="Enter your address" /> <button className="primary" onClick={onConfirm} type="button">Confirm</button> </div> </StandaloneSearchBox> <Marker position={location} onLoad={onMarkerLoad}></Marker> </GoogleMap> </LoadScript> </div> ) : <LoadingBox></LoadingBox> } export default MapScreen
action은 스크린에서 바로 보내줬으니,
reducer를 작성하자.
export const userAddressmapReducer = (state={}, action)=>{ switch(action.type){ case USER_ADDRESSS_MAP_CONFIRM: return {address:action.payload}; default: return state; } }
store.js
userAddressMap:userAddressmapReducer })
이제 ShippingAddressScreen에서 지도에서 선택한 위치를 가져오도록 설정한다.
지도에서 선택하기 버튼을 만들고 버튼을 누르면 지도페이지로 가도록 설정한다.
제출 버튼을 누른 경우를 다음과 같이 수정해서 만약 지도에서 고른 경우엔 새로운 위치정보를 저장하고 ,
선택하지 않은 경우에는 이전 주소로 그대로 간다.
import { saveShippingAddress } from '../actions/cartActions' const [lat, setLat] = useState(shippingAddress.lat); const [lng, setLng] = useState(shippingAddress.lng) const userAddressMap = useSelector(state => state.userAddressMap) const {address: addressMap} = userAddressMap const dispatch = useDispatch() const submitHandler= (e) =>{ e.preventDefault(); const newLat = addressMap? addressMap.lat: lat; const newLng = addressMap? addressMap.lng:lng; if(addressMap){//지도에서 선택은 한 경우 setLat(addressMap.lat); setLng(addressMap.lng); } let moveOn = true; if(!newLat ||!newLng){//지도가 올바르게 선택되지 않았다면 moveOn = window.confirm( 'You did not set your location on map. Continue?' ) } if(moveOn){//지도에서 올바르게 선택된경우 dispatch(saveShippingAddress({fullName, address, city, postalCode, country, lat:newLat, lng:newLng}))//새로운 좌표로 등록해놓는다. props.history.push('/payment') } } const chooseOnMap=() =>{ dispatch(saveShippingAddress({fullName, address, city, postalCode, country, lat, lng}))//지도 페이지로 가기전에 일단 현재데이터를 저장한다. props.history.push('/map') } ... <div> <label htmlFor="country">Country</label> <input type="text" id = "country" placeholder="Enter country" value = {country} onChange={e=>setCountry(e.target.value)} required/> </div> <div> <label htmlFor="chooseOnMap">Location</label> <button type="button" onClick={chooseOnMap}>Choose On Map</button> </div> <div>
로그인 한 사람만 가게 privateRoute로 app.js에 다음과 같이 페이지를 추가해준다.
import MapScreen from './screens/MapScreen'; <PrivateRoute path="/map" component={MapScreen} exact></PrivateRoute>
추가로 주소를 지도에서 선택하고 입력이 완료되면 페이지를 이동시켜보도록 하자.
mapScreen.js
function MapScreen(props) { const onConfirm = ()=>{ const places = placeRef.current.getPlaces(); if(places && places.length ===1){ dispatch({ type:USER_ADDRESSS_MAP_CONFIRM, payload:{ lat:location.lat, lng:location.lng, address:places[0].formatted_address, name:places[0].name, vicinity:places[0].vicinity, googleAddressId:places[0].id } }) alert('location selecte successfully') props.history.push('/shipping') }else{ alert('Please enter your address') } }
추가로 이제 ordermodel에 lat, lng를 추가하자.
shippingAddress:{ fullName:{ type:String, required:true }, address:{ type:String, required:true }, city:{ type:String, required:true }, postalCode:{ type:String, required:true }, country:{ type:String, required:true }, lat: Number, lng:Number },
지도에서 선택하고 나면 order>shippingAddress>lng, lat가 추가된것을 확인할 수 있다.
'NODE.JS' 카테고리의 다른 글
아마존 E-commerce 클론 -31) Order Receipt 이메일로 보내기 (0) 2021.05.30 아마존 E-commerce 클론 -30) Pagination적용하기 (0) 2021.05.30 아마존 E-commerce 클론 -28) Rate & Review 생성하기 (0) 2021.05.30 아마존 E-commerce 클론 -27) Search Box ,Search Filter기능 , Side bar, sort & Filter 만들기 (0) 2021.05.29 아마존 E-commerce 클론 -26) Top Seller Carousel 추가하고, 장바구니 설정하기(동일 주문자의 상품만 장바구니에 추가가능) (0) 2021.05.29