diff --git a/.pnp.cjs b/.pnp.cjs index 477a9161..d37c8212 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -3928,6 +3928,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["regenerator-runtime", "npm:0.14.0"]\ ],\ "linkType": "HARD"\ + }],\ + ["npm:7.23.1", {\ + "packageLocation": "./.yarn/cache/@babel-runtime-npm-7.23.1-9b8781107c-0cd0d43e6e.zip/node_modules/@babel/runtime/",\ + "packageDependencies": [\ + ["@babel/runtime", "npm:7.23.1"],\ + ["regenerator-runtime", "npm:0.14.0"]\ + ],\ + "linkType": "HARD"\ }]\ ]],\ ["@babel/template", [\ @@ -4143,6 +4151,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["react", "npm:18.2.0"],\ ["react-dom", "virtual:040d27df013de8c2443d97cd34785bd6338b0d64a4a625937768b1a38353fca7b8404d53a1248b5c67570c2a031bc43d100149c15012f4485eb41e15d763240d#npm:18.2.0"],\ ["react-is", "npm:18.2.0"],\ + ["react-kakao-maps-sdk", "virtual:8ec4233c825b2c709f2ff549456a05fb98060d621f5df14748cda36fdb51190eccc2e438466f7464c85557cdad97eb73aa6580e78bca957a1149bfc58c6ddf34#npm:1.1.21"],\ ["react-toastify", "virtual:8ec4233c825b2c709f2ff549456a05fb98060d621f5df14748cda36fdb51190eccc2e438466f7464c85557cdad97eb73aa6580e78bca957a1149bfc58c6ddf34#npm:9.1.3"],\ ["styled-components", "virtual:8ec4233c825b2c709f2ff549456a05fb98060d621f5df14748cda36fdb51190eccc2e438466f7464c85557cdad97eb73aa6580e78bca957a1149bfc58c6ddf34#npm:5.3.11"],\ ["styled-reset", "virtual:8ec4233c825b2c709f2ff549456a05fb98060d621f5df14748cda36fdb51190eccc2e438466f7464c85557cdad97eb73aa6580e78bca957a1149bfc58c6ddf34#npm:4.5.1"],\ @@ -6525,6 +6534,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["kakao.maps.d.ts", [\ + ["npm:0.1.39", {\ + "packageLocation": "./.yarn/cache/kakao.maps.d.ts-npm-0.1.39-333b43bbc2-b89c3ee7d6.zip/node_modules/kakao.maps.d.ts/",\ + "packageDependencies": [\ + ["kakao.maps.d.ts", "npm:0.1.39"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["lines-and-columns", [\ ["npm:1.2.4", {\ "packageLocation": "./.yarn/cache/lines-and-columns-npm-1.2.4-d6c7cc5799-0c37f9f7fa.zip/node_modules/lines-and-columns/",\ @@ -7104,6 +7122,34 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["react-kakao-maps-sdk", [\ + ["npm:1.1.21", {\ + "packageLocation": "./.yarn/cache/react-kakao-maps-sdk-npm-1.1.21-dbdf5986a0-c30bd27f79.zip/node_modules/react-kakao-maps-sdk/",\ + "packageDependencies": [\ + ["react-kakao-maps-sdk", "npm:1.1.21"]\ + ],\ + "linkType": "SOFT"\ + }],\ + ["virtual:8ec4233c825b2c709f2ff549456a05fb98060d621f5df14748cda36fdb51190eccc2e438466f7464c85557cdad97eb73aa6580e78bca957a1149bfc58c6ddf34#npm:1.1.21", {\ + "packageLocation": "./.yarn/__virtual__/react-kakao-maps-sdk-virtual-afec6341b7/0/cache/react-kakao-maps-sdk-npm-1.1.21-dbdf5986a0-c30bd27f79.zip/node_modules/react-kakao-maps-sdk/",\ + "packageDependencies": [\ + ["react-kakao-maps-sdk", "virtual:8ec4233c825b2c709f2ff549456a05fb98060d621f5df14748cda36fdb51190eccc2e438466f7464c85557cdad97eb73aa6580e78bca957a1149bfc58c6ddf34#npm:1.1.21"],\ + ["@babel/runtime", "npm:7.23.1"],\ + ["@types/react", "npm:18.2.21"],\ + ["@types/react-dom", "npm:18.2.7"],\ + ["kakao.maps.d.ts", "npm:0.1.39"],\ + ["react", "npm:18.2.0"],\ + ["react-dom", "virtual:040d27df013de8c2443d97cd34785bd6338b0d64a4a625937768b1a38353fca7b8404d53a1248b5c67570c2a031bc43d100149c15012f4485eb41e15d763240d#npm:18.2.0"]\ + ],\ + "packagePeers": [\ + "@types/react-dom",\ + "@types/react",\ + "react-dom",\ + "react"\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["react-slick", [\ ["npm:0.29.0", {\ "packageLocation": "./.yarn/cache/react-slick-npm-0.29.0-28db290b04-67ce498191.zip/node_modules/react-slick/",\ diff --git a/apps/jurumarble/package.json b/apps/jurumarble/package.json index c5c17e93..757ca862 100644 --- a/apps/jurumarble/package.json +++ b/apps/jurumarble/package.json @@ -22,6 +22,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-is": "^18.2.0", + "react-kakao-maps-sdk": "^1.1.21", "react-toastify": "^9.1.3", "styled-components": "^5.3.6", "styled-reset": "^4.5.1" diff --git a/apps/jurumarble/public/favicon.ico b/apps/jurumarble/public/favicon.ico new file mode 100644 index 00000000..44e9b6f7 Binary files /dev/null and b/apps/jurumarble/public/favicon.ico differ diff --git a/apps/jurumarble/src/app/layout.tsx b/apps/jurumarble/src/app/layout.tsx index 3fe7bf4c..0aa644b1 100644 --- a/apps/jurumarble/src/app/layout.tsx +++ b/apps/jurumarble/src/app/layout.tsx @@ -6,6 +6,8 @@ import type { Metadata } from "next"; import { ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; import { injectStyle } from "react-toastify/dist/inject-style"; +import { KAKAO_MAP_API_KEY } from "lib/constants"; +import Script from "next/script"; export const metadata: Metadata = { title: "주루마블", @@ -16,6 +18,12 @@ if (typeof window !== "undefined") { injectStyle(); } +declare global { + interface Window { + kakao: any; + } +} + export default function RootLayout({ children }: { children: React.ReactNode }) { return ( @@ -33,6 +41,11 @@ export default function RootLayout({ children }: { children: React.ReactNode }) + ); } diff --git a/apps/jurumarble/src/app/map/components/MapContainer.tsx b/apps/jurumarble/src/app/map/components/MapContainer.tsx new file mode 100644 index 00000000..216b7cf6 --- /dev/null +++ b/apps/jurumarble/src/app/map/components/MapContainer.tsx @@ -0,0 +1,199 @@ +"use client"; + +import { Button } from "components/button"; +import React, { useEffect, useRef, useState } from "react"; +import styled from "styled-components"; +import useDrinksMapService from "../services/useDrinksMapService"; +import { Map, MapMarker } from "react-kakao-maps-sdk"; +import { useToggle } from "@react-hookz/web"; +import RegionBottomSheet from "./RegionBottomsheet"; +import DrinkItem from "app/stemp/components/DrinkItem"; +import { ExImg1 } from "public/images"; +import RegionSmallSelect from "./RegionSmallSelect"; +import { DRINK_INFO_SORT_LIST } from "lib/constants"; + +const MapContainer = () => { + const [on, toggle] = useToggle(); + const mapRef = useRef(null); + const [mapXY, setMapXY] = useState({ + startX: 33.64225953272826, + startY: 119.06076029979886, + endX: 40.856225138838, + endY: 132.02500466772065, + }); + + const { drinksList } = useDrinksMapService({ + startX: mapXY.startX, + startY: mapXY.startY, + endX: mapXY.endX, + endY: mapXY.endY, + page: 0, + size: 100, + }); + const [sortBy, setSortBy] = useState("ByPopularity"); + + const onChangeDrinkInfoSortOption = (sortOption: string) => { + setSortBy(sortOption); + }; + + const [state, setState] = useState({ + // 지도의 초기 위치 서울 시청 + center: { lat: 36.75158343784174, lng: 127.90408370095267 }, + // 지도 위치 변경시 panto를 이용할지에 대해서 정의 + isPanto: false, + level: 13, + }); + + useEffect(() => { + // 윈도우 리사이즈 실행 + setTimeout(() => { + window.dispatchEvent(new Event("resize")); + }, 1000); + }, []); + + const onIdleMap = () => { + const map = mapRef.current; + if (map) { + const bounds = map.getBounds(); + const ne = bounds.getNorthEast(); + const sw = bounds.getSouthWest(); + setMapXY({ + startX: sw.getLat(), + startY: sw.getLng(), + endX: ne.getLat(), + endY: ne.getLng(), + }); + } + }; + + const setChangeMapCenter = (lat: number, lng: number) => { + setState({ + center: { lat, lng }, + isPanto: true, + level: 11, + }); + setTimeout(() => { + onIdleMap(); + }, 100); + }; + + return ( + + + +

+ 여행지 근처의 +
우리술을 찾아드려요 +

+ + +
+
+ 여행지를 설정하면
+ 여행지의 우리술을 확인할 수 있어요 +
+
+ + onIdleMap()} + > + + {drinksList.map(({ latitude, longitude }) => ( + + ))} + + + + + + {drinksList.map(({ drinkId, name, region, latitude, longitude }) => ( + { + setChangeMapCenter(latitude, longitude); + }} + selectedDrinkList={[]} + /> + ))} + + +
+ ); +}; + +const Container = styled.div` + width: 100%; + height: 100%; +`; + +const TopBox = styled.section` + padding: 20px; + .title { + color: ${({ theme }) => theme.colors.black_01}; + text-align: left; + ${({ theme }) => theme.typography.headline02}; + padding-bottom: 8px; + } + + .description { + color: ${({ theme }) => theme.colors.black_02}; + ${({ theme }) => theme.typography.body_long03}; + } +`; + +const SettingWrapper = styled.div` + width: 100%; + display: flex; + justify-content: space-between; +`; + +const FilterBox = styled.div` + display: flex; + justify-content: flex-end; + padding: 16px 20px 32px 20px; +`; + +const DrinkBox = styled.div` + display: flex; + flex-direction: column; + gap: 8px; + padding: 0 20px; +`; + +export default MapContainer; diff --git a/apps/jurumarble/src/app/map/components/RegionBottomsheet.tsx b/apps/jurumarble/src/app/map/components/RegionBottomsheet.tsx new file mode 100644 index 00000000..5acf08a6 --- /dev/null +++ b/apps/jurumarble/src/app/map/components/RegionBottomsheet.tsx @@ -0,0 +1,159 @@ +import { Button, Portal } from "components/index"; +import { REGION_LIST_BOUNDS } from "lib/constants"; +import { transitions } from "lib/styles"; +import Image from "next/image"; +import React from "react"; +import { SvgIcPrev, SvgIcX } from "src/assets/icons/components"; +import styled, { css } from "styled-components"; + +interface Props { + on: boolean; + onToggleDrinkSearchModal: () => void; + setChangeMapCenter: (lat: number, lng: number) => void; +} + +const RegionBottomSheet = ({ on, onToggleDrinkSearchModal, setChangeMapCenter }: Props) => { + if (!on) return null; + + return ( + + + + 지역 설정 + + + + + + 지역을 선택해주세요{" "} + {" "} + + + {REGION_LIST_BOUNDS.map(({ label, value, lat, long }) => ( + { + setChangeMapCenter(lat, long); + onToggleDrinkSearchModal(); + }} + > + {label} + + ))} + + + + + + + + + ); +}; + +const BottomSheet = styled.div` + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: 9999; +`; + +const Inner = styled.div` + position: absolute; + z-index: 9999; + background-color: white; + bottom: 0; + right: 0; + left: 0; + margin: auto; + width: 100%; + max-width: 720px; + height: 90%; + animation: ${transitions.popInFromBottom} 0.4s ease-in-out; + border-radius: 16px 16px 0px 0px; + padding: 26px 20px 20px 20px; +`; + +const Background = styled.div` + display: block; + width: 100%; + height: 100%; + background-color: black; + position: absolute; + left: 0; + top: 0; + opacity: 0.4; +`; + +const Title = styled.div` + display: flex; + ${({ theme }) => css` + ${theme.typography.headline03} + `} + justify-content: center; + padding-bottom: 36px; +`; + +const Exit = styled.div` + position: absolute; + top: 26px; + right: 20px; + width: 24px; + height: 24px; + cursor: pointer; +`; + +const SelectBox = styled.div` + border-radius: 8px; + border: 1px solid ${({ theme }) => theme.colors.black_05}; + width: 100%; + display: flex; + justify-content: center; + align-items: center; + padding: 10px 16px; + color: ${({ theme }) => theme.colors.black_03}; + ${({ theme }) => theme.typography.button01} + gap: 4px; + margin-bottom: 8px; +`; + +const List = styled.div` + width: 100%; + border-radius: 8px; + border: 1px solid ${({ theme }) => theme.colors.line_01}; + overflow-y: scroll; + height: calc(90% - 134px); + -ms-overflow-style: none; + scrollbar-width: none; + ::-webkit-scrollbar { + display: none; + } +`; + +const RegionItem = styled.div` + padding: 16px; + text-align: center; + color: ${({ theme }) => theme.colors.black_02}; + ${({ theme }) => theme.typography.button02} + border-bottom: 1px solid ${({ theme }) => theme.colors.line_01}; + :active { + background-color: ${({ theme }) => theme.colors.bg_01}; + } +`; + +const ButtonWrapper = styled.div` + width: 100%; + position: absolute; + bottom: 0; + left: 0; + padding: 20px; +`; + +export default RegionBottomSheet; diff --git a/apps/jurumarble/src/app/map/components/RegionSmallSelect.tsx b/apps/jurumarble/src/app/map/components/RegionSmallSelect.tsx new file mode 100644 index 00000000..b8472e94 --- /dev/null +++ b/apps/jurumarble/src/app/map/components/RegionSmallSelect.tsx @@ -0,0 +1,59 @@ +import styled, { css } from "styled-components"; +import { useToggle } from "@monorepo/hooks"; +import SvgIcExpandMore from "src/assets/icons/components/IcExpandMore"; +import { Select } from "components/selectBox"; + +interface Props { + defaultOption: string; + onChangeSortOption: (id: string) => void; + options: { value: string; label: string }[]; +} + +function RegionSmallSelect({ defaultOption, onChangeSortOption, options }: Props) { + const [isOpen, onToggleOpen] = useToggle(); + + return ( + + + + ); +} + +const SelectStyled = styled.span<{ isOpen: boolean }>` + ${({ theme, isOpen }) => css` + ${theme.typography.button01}; + color: ${theme.colors.black_03}; + width: 85px; + /* height: 40px; */ + .selected-label { + border: 1px solid ${theme.colors.line_01}; + border-radius: 8px; + padding: 10px 12px; + } + svg { + ${isOpen && "transform: rotateX( 180deg )"} + } + #select-list { + width: 100px; + height: 78px; + display: flex; + flex-direction: column; + align-items: center; + padding: 8px 0; + gap: 20px; + } + #indicator { + display: flex; + } + `} +`; + +export default RegionSmallSelect; diff --git a/apps/jurumarble/src/app/map/page.tsx b/apps/jurumarble/src/app/map/page.tsx new file mode 100644 index 00000000..336b6ddf --- /dev/null +++ b/apps/jurumarble/src/app/map/page.tsx @@ -0,0 +1,16 @@ +import BottomBar from "components/BottomBar"; +import Header from "components/Header"; +import React from "react"; +import MapContainer from "./components/MapContainer"; + +const MapPage = () => { + return ( + <> +
+ + + + ); +}; + +export default MapPage; diff --git a/apps/jurumarble/src/app/map/services/useDrinksMapService.ts b/apps/jurumarble/src/app/map/services/useDrinksMapService.ts new file mode 100644 index 00000000..abe6e84e --- /dev/null +++ b/apps/jurumarble/src/app/map/services/useDrinksMapService.ts @@ -0,0 +1,34 @@ +import { useInfiniteQuery } from "@tanstack/react-query"; +import { useInfiniteScroll } from "@monorepo/hooks"; +import { reactQueryKeys } from "lib/queryKeys"; +import { getDrinksMap } from "lib/apis/drink"; + +export default function useDrinksMapService(params: { + startX: number; + startY: number; + endX: number; + endY: number; + page: number; + size: number; +}) { + const { startX, startY, endX, endY, page, size } = params; + const { data, fetchNextPage } = useInfiniteQuery( + reactQueryKeys.drinksMap(startX, startY, endX, endY, page, size), + ({ pageParam }) => getDrinksMap({ ...params, page: pageParam?.page || 0 }), + { + getNextPageParam: ({ last, number }) => { + if (last) return undefined; + return { + page: number + 1, + }; + }, + keepPreviousData: true, + }, + ); + + const [subscribe] = useInfiniteScroll(fetchNextPage); + + const drinksList = data?.pages.flatMap((page) => page.content) ?? []; + + return { drinksList, subscribe }; +} diff --git a/apps/jurumarble/src/app/stemp/components/DrinkItem.tsx b/apps/jurumarble/src/app/stemp/components/DrinkItem.tsx index f24ed668..df45ac1e 100644 --- a/apps/jurumarble/src/app/stemp/components/DrinkItem.tsx +++ b/apps/jurumarble/src/app/stemp/components/DrinkItem.tsx @@ -6,7 +6,14 @@ import styled, { css, useTheme } from "styled-components"; import useDrinkStempService from "../service/useDrinkStempService"; interface Props { - drinkInfo: DrinkInfo; + drinkInfo: + | DrinkInfo + | { + id: number; + name: string; + productName: string; + image: string; + }; onClickReplaceDrinkInfo: (e: React.MouseEvent) => void; selectedDrinkList?: string[]; } @@ -54,6 +61,7 @@ const Container = styled.button<{ selected: boolean | undefined }>` padding: 16px; border-radius: 16px; cursor: pointer; + width: 100%; ${({ theme, selected }) => selected && css` diff --git a/apps/jurumarble/src/app/vote/page.tsx b/apps/jurumarble/src/app/vote/page.tsx index 99564b86..e18307d8 100644 --- a/apps/jurumarble/src/app/vote/page.tsx +++ b/apps/jurumarble/src/app/vote/page.tsx @@ -15,6 +15,7 @@ import VoteDescription from "./[id]/components/VoteDescription"; import Path from "lib/Path"; import useExecuteVoteService from "./[id]/services/useExecuteVoteService"; import useInfiniteMainListService from "./services/useGetVoteListService"; +import { useMemo } from "react"; export type Drag = "up" | "down" | null; @@ -35,6 +36,16 @@ function VoteHomePage() { const { title, imageA, imageB, titleA, titleB, detail, voteId, region } = mainVoteList[nowShowing] || {}; + const safeImageA = useMemo(() => { + console.log(imageA); + if (!imageA || imageA === "string") return EmptyAImg; + return imageA; + }, [imageA]); + const safeImageB = useMemo(() => { + if (!imageB || imageB === "string") return EmptyAImg; + return imageB; + }, [imageB]); + const { mutateBookMark, bookMarkCheckQuery } = usePostBookmarkService(voteId); const { mutate, select } = useExecuteVoteService(voteId); @@ -85,8 +96,8 @@ function VoteHomePage() { isBookmark={isBookmark} /> , }, { diff --git a/apps/jurumarble/src/lib/apis/drink.ts b/apps/jurumarble/src/lib/apis/drink.ts index 899d5bab..20491f32 100644 --- a/apps/jurumarble/src/lib/apis/drink.ts +++ b/apps/jurumarble/src/lib/apis/drink.ts @@ -1,5 +1,5 @@ import { DrinkInfoSortType } from "src/types/common"; -import { DrinkListResponse } from "src/types/drink"; +import { DrinkListResponse, DrinkMapResponse } from "src/types/drink"; import { baseApi } from "./http/base"; import { http } from "./http/http"; @@ -65,3 +65,21 @@ export const postDrinkEnjoyAPI = async (drinkId: number) => { }); return response.data; }; + +export interface GetDrinksMapRequest { + startX: number; + startY: number; + endX: number; + endY: number; + page: number; + size: number; +} + +export const getDrinksMap = async (params: GetDrinksMapRequest) => { + const response = await baseApi.get("api/drinks/map", { + params: { + ...params, + }, + }); + return response.data; +}; diff --git a/apps/jurumarble/src/lib/constants.ts b/apps/jurumarble/src/lib/constants.ts index d0bca41c..6705792e 100644 --- a/apps/jurumarble/src/lib/constants.ts +++ b/apps/jurumarble/src/lib/constants.ts @@ -5,6 +5,8 @@ export const SERVER_URL = process.env.NEXT_PUBLIC_SERVER_URL || ""; export const KAKAO_CLIENT_ID = process.env.NEXT_PUBLIC_KAKAO_CLIENT_ID || ""; export const NAVER_CLIENT_ID = process.env.NEXT_PUBLIC_NAVER_CLIENT_ID || ""; + +export const KAKAO_MAP_API_KEY = process.env.NEXT_PUBLIC_KAKAO_MAP_API_KEY || ""; export const KAKAO_LOGIN_REDIRECT_URL = process.env.NODE_ENV === "development" ? `http://localhost:3000/${Path.KAKAO_LOGIN_PROCESS}` @@ -34,6 +36,26 @@ export const REGION_LIST = [ { value: "JEJU", label: "제주" }, ]; +export const REGION_LIST_BOUNDS = [ + { value: "SEOUL", label: "서울", lat: 37.53391, long: 126.9775 }, + { value: "INCHEON", label: "인천", lat: 37.45323333333334, long: 126.70735277777779 }, + { value: "DAEJEON", label: "대전", lat: 36.347119444444445, long: 127.38656666666667 }, + { value: "DAEGU", label: "대구", lat: 35.868541666666665, long: 128.60355277777776 }, + { value: "GWANGJU", label: "광주", lat: 35.156974999999996, long: 126.85336388888888 }, + { value: "BUSAN", label: "부산", lat: 35.17701944444444, long: 129.07695277777776 }, + { value: "ULSAN", label: "울산", lat: 35.53540833333333, long: 129.3136888888889 }, + { value: "SEJONG", label: "세종", lat: 36.4800121, long: 127.289069 }, + { value: "GYEONGGI", label: "경기도", lat: 37.39067, long: 126.7888 }, + { value: "GANGWON", label: "강원도", lat: 38.642618, long: 127.170231 }, + { value: "CHUNGBUK", label: "충청북도", lat: 36.6325, long: 127.49358611111111 }, + { value: "CHUNGNAM", label: "충청남도", lat: 36.32387222222223, long: 127.42295555555556 }, + { value: "GYEONGBUK", label: "경상북도", lat: 36.491286, long: 128.889433 }, + { value: "GYEONGNAM", label: "경상남도", lat: 35.459369, long: 128.214826 }, + { value: "JEONBUK", label: "전라북도", lat: 35.81727, long: 127.11105277777777 }, + { value: "JEONNAM", label: "전라남도", lat: 34.813044444444444, long: 126.465 }, + { value: "JEJU", label: "제주", lat: 33.48569444444445, long: 126.50033333333333 }, +]; + export const DRINK_VOTE_SORT_LIST = [ { value: "ByPopularity", label: "인기순" }, { value: "ByTime", label: "최신순" }, diff --git a/apps/jurumarble/src/lib/queryKeys.ts b/apps/jurumarble/src/lib/queryKeys.ts index 62372af1..8a2b118c 100644 --- a/apps/jurumarble/src/lib/queryKeys.ts +++ b/apps/jurumarble/src/lib/queryKeys.ts @@ -18,6 +18,7 @@ export const queryKeys = { MY_PARTICIPATED_VOTE: "myParticipatedVote" as const, MY_CREATED_VOTE: "myCreatedVote" as const, MY_BOOKMARKED_VOTE: "myBookmarkedVote" as const, + DRINKS_MAP: "drinksMap" as const, }; export const reactQueryKeys = { @@ -38,4 +39,12 @@ export const reactQueryKeys = { detailVoteCount: (id: number) => [queryKeys.DETAIL_VOTE_COUNT, id] as const, detailFilterdAnalysis: (id: number, mbti?: string, gender?: string, age?: string) => [queryKeys.DETAIL_FILTERED_ANALYSIS, id, mbti, gender, age] as const, + drinksMap: ( + startX: number, + startY: number, + endX: number, + endY: number, + page: number, + size: number, + ) => [queryKeys.DRINKS_MAP, startX, startY, endX, endY, page, size] as const, }; diff --git a/apps/jurumarble/src/types/drink.ts b/apps/jurumarble/src/types/drink.ts index 317a7a77..e969420b 100644 --- a/apps/jurumarble/src/types/drink.ts +++ b/apps/jurumarble/src/types/drink.ts @@ -30,6 +30,14 @@ export interface DrinkInfo { enjoyCount: number | null; } +export interface DrinkMapInfo { + drinkId: number; + name: string; + region: string; + latitude: number; + longitude: number; +} + export interface DrinkListResponse { content: DrinkInfo[]; pageable: Pageable; @@ -41,3 +49,15 @@ export interface DrinkListResponse { size: number; empty: boolean; } + +export interface DrinkMapResponse { + content: DrinkMapInfo[]; + pageable: Pageable; + sort: Sort; + first: boolean; + last: boolean; + number: number; + numberOfElements: number; + size: number; + empty: boolean; +} diff --git a/yarn.lock b/yarn.lock index c3df845a..da22bd32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1427,6 +1427,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.22.15": + version: 7.23.1 + resolution: "@babel/runtime@npm:7.23.1" + dependencies: + regenerator-runtime: ^0.14.0 + checksum: 0cd0d43e6e7dc7f9152fda8c8312b08321cda2f56ef53d6c22ebdd773abdc6f5d0a69008de90aa41908d00e2c1facb24715ff121274e689305c858355ff02c70 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.8.4": version: 7.22.11 resolution: "@babel/runtime@npm:7.22.11" @@ -1613,6 +1622,7 @@ __metadata: react: 18.2.0 react-dom: 18.2.0 react-is: ^18.2.0 + react-kakao-maps-sdk: ^1.1.21 react-toastify: ^9.1.3 styled-components: ^5.3.6 styled-reset: ^4.5.1 @@ -3226,6 +3236,13 @@ __metadata: languageName: node linkType: hard +"kakao.maps.d.ts@npm:^0.1.39": + version: 0.1.39 + resolution: "kakao.maps.d.ts@npm:0.1.39" + checksum: b89c3ee7d6e2e86b1f53fa43060097f7cfc11b5a1e6c3862ab0e4126aa17483c6642d24c2a67deaa1c36de3fb604ec3fc7c049e6e4ddb0689782b040fa341526 + languageName: node + linkType: hard + "lines-and-columns@npm:^1.1.6": version: 1.2.4 resolution: "lines-and-columns@npm:1.2.4" @@ -3643,6 +3660,19 @@ __metadata: languageName: node linkType: hard +"react-kakao-maps-sdk@npm:^1.1.21": + version: 1.1.21 + resolution: "react-kakao-maps-sdk@npm:1.1.21" + dependencies: + "@babel/runtime": ^7.22.15 + kakao.maps.d.ts: ^0.1.39 + peerDependencies: + react: ^16.8 || ^17 || ^18 + react-dom: ^16.8 || ^17 || ^18 + checksum: c30bd27f79c18da81a7083ba9b6e39ec1ee0bdfb8d1ae3890b96bf44bf77279a36e44f29ec652de89f97a6e4c1f32bfa3660d738f1b6f3eaf26e14d7c3241d20 + languageName: node + linkType: hard + "react-slick@npm:^0.29.0": version: 0.29.0 resolution: "react-slick@npm:0.29.0"