diff --git a/package-lock.json b/package-lock.json index cd10e0dc..3ac8b7a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "react-hot-toast": "^2.4.1", "react-icons": "^5.3.0", "react-intersection-observer": "^9.13.1", + "react-kakao-maps-sdk": "^1.1.27", "react-modal": "^3.16.1", "react-spinners": "^0.14.1", "tailwind-merge": "^2.5.4", @@ -62,6 +63,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-storybook": "^0.11.0", + "kakao.maps.d.ts": "^0.1.40", "postcss": "^8.4.47", "prettier-plugin-tailwindcss": "^0.6.8", "storybook": "^8.4.4", @@ -3049,6 +3051,7 @@ "version": "0.3.7", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.7.tgz", "integrity": "sha512-rNoqXKSm/P1EJw/lrzyaQepC6KfryLFSShA+jl1mbPYqutXlvZWwm0x03W6jMHaYJqIOmc7QarD+GVfG9hO7XQ==", + "deprecated": "newer syntax features were not transpiled", "dev": true, "license": "MIT", "dependencies": { @@ -6625,9 +6628,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.62.3", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.3.tgz", - "integrity": "sha512-Jp/nYoz8cnO7kqhOlSv8ke/0MJRJVGuZ0P/JO9KQ+f45mpN90hrerzavyTKeSoT/pOzeoOUkv1Xd0wPsxAWXfg==", + "version": "5.62.7", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.7.tgz", + "integrity": "sha512-fgpfmwatsrUal6V+8EC2cxZIQVl9xvL7qYa03gsdsCy985UTUlS4N+/3hCzwR0PclYDqisca2AqR1BVgJGpUDA==", "license": "MIT", "funding": { "type": "github", @@ -6646,12 +6649,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.62.3", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.3.tgz", - "integrity": "sha512-y2zDNKuhgiuMgsKkqd4AcsLIBiCfEO8U11AdrtAUihmLbRNztPrlcZqx2lH1GacZsx+y1qRRbCcJLYTtF1vKsw==", + "version": "5.62.7", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.7.tgz", + "integrity": "sha512-+xCtP4UAFDTlRTYyEjLx0sRtWyr5GIk7TZjZwBu4YaNahi3Rt2oMyRqfpfVrtwsqY2sayP4iXVCwmC+ZqqFmuw==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.62.3" + "@tanstack/query-core": "5.62.7" }, "funding": { "type": "github", @@ -6662,9 +6665,9 @@ } }, "node_modules/@tanstack/react-query-devtools": { - "version": "5.62.3", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.62.3.tgz", - "integrity": "sha512-4iaQap/iP5ErS094u1WehFntHtjRo6g5HJMvyHovBVbsxnvgPc6AtKAw7qxPPoKy6Wj5Bew0045eYP5phiiBmw==", + "version": "5.62.7", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.62.7.tgz", + "integrity": "sha512-wxXsdTZJRs//hMtJMU5aNlUaTclRFPqLvDNeWbRj8YpGD3aoo4zyu53W55W2DY16+ycg3fti21uCW4N9oyj91w==", "dev": true, "license": "MIT", "dependencies": { @@ -6675,7 +6678,7 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-query": "^5.62.3", + "@tanstack/react-query": "^5.62.7", "react": "^18 || ^19" } }, @@ -6981,9 +6984,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.14.tgz", - "integrity": "sha512-NzahNKvjNhVjuPBQ+2G7WlxstQ+47kXZNHlUvFakDViuIEfGY926GqhMueQFZ7woG+sPiQKlF36XfrIUVSUfFg==", + "version": "18.3.16", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.16.tgz", + "integrity": "sha512-oh8AMIC4Y2ciKufU8hnKgs+ufgbA/dhPTACaZPM86AbwX9QwnFtSoPWEeRUj8fge+v6kFt78BXcDhAU1SrrAsw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7015,9 +7018,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.3.tgz", - "integrity": "sha512-uTYkxTLkYp41nq/ULXyXMtkNT1vu5fXJoqad6uTNCOGat5t9cLgF4vMNLBXsTOXpdOI44XzKPY1M5RRm0bQHuw==", + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz", + "integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==", "dev": true, "license": "MIT", "peerDependencies": { @@ -8847,9 +8850,9 @@ } }, "node_modules/chromatic": { - "version": "11.20.0", - "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-11.20.0.tgz", - "integrity": "sha512-Btdli1qoAI01UKmk3Iqe6vKhAhePRXqNI/2uKKy2R16q7SN/5kLTqhd1JI20LFOZSnH3xSJaUXeJ2xZOJB//3A==", + "version": "11.20.1", + "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-11.20.1.tgz", + "integrity": "sha512-cuuf707JDj4EeONIZkgfob4IYrhThfbAJybWmNOj89ealtKKzzlH+4pm5qhZjmXKsFrmPqTWzslbmfKsrXX6pg==", "dev": true, "license": "MIT", "bin": { @@ -12633,6 +12636,12 @@ "node": ">=4.0" } }, + "node_modules/kakao.maps.d.ts": { + "version": "0.1.40", + "resolved": "https://registry.npmjs.org/kakao.maps.d.ts/-/kakao.maps.d.ts-0.1.40.tgz", + "integrity": "sha512-nX69MB1ok04epe3OqS+/tEeWBbU31GSQbvDPJmQRRltzzqn6t4jBsO5v1nzalUjCKzwcH2CptOc767NZ7Hbu3g==", + "license": "MIT" + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -14726,6 +14735,20 @@ "dev": true, "license": "MIT" }, + "node_modules/react-kakao-maps-sdk": { + "version": "1.1.27", + "resolved": "https://registry.npmjs.org/react-kakao-maps-sdk/-/react-kakao-maps-sdk-1.1.27.tgz", + "integrity": "sha512-1EwYkYsjTDRFqysKStDasFMrFTXcLx2AyRlqMoWD7ONWhRqpjx9M874hkhEEHrnypP2eSIhhDLe0EiSKp3bd2Q==", + "license": "MIT", + "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" + } + }, "node_modules/react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", @@ -18034,9 +18057,9 @@ } }, "node_modules/zod": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.0.tgz", - "integrity": "sha512-Hz+wiY8yD0VLA2k/+nsg2Abez674dDGTai33SwNvMPuf9uIrBC9eFgIMQxBBbHFxVXi8W+5nX9DcAh9YNSQm/w==", + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", + "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index ae6f9875..ce8baade 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "react-hot-toast": "^2.4.1", "react-icons": "^5.3.0", "react-intersection-observer": "^9.13.1", + "react-kakao-maps-sdk": "^1.1.27", "react-modal": "^3.16.1", "react-spinners": "^0.14.1", "tailwind-merge": "^2.5.4", @@ -67,6 +68,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-storybook": "^0.11.0", + "kakao.maps.d.ts": "^0.1.40", "postcss": "^8.4.47", "prettier-plugin-tailwindcss": "^0.6.8", "storybook": "^8.4.4", diff --git a/src/app/(pages)/kakao-map/page.tsx b/src/app/(pages)/kakao-map/page.tsx new file mode 100644 index 00000000..5b72e53a --- /dev/null +++ b/src/app/(pages)/kakao-map/page.tsx @@ -0,0 +1,110 @@ +"use client"; + +import React, { useState, useCallback } from "react"; +import Script from "next/script"; +import { Map, MapMarker, useKakaoLoader } from "react-kakao-maps-sdk"; + +interface Coords { + lat: number; + lng: number; +} + +declare global { + interface Window { + daum: { + Postcode: new (config: { + oncomplete: (data: { address: string; zonecode: string; [key: string]: any }) => void; + }) => { open: () => void }; + }; + } +} + +const KakaoMapPage = () => { + const [address, setAddress] = useState(""); + const [coords, setCoords] = useState({ lat: 37.5665, lng: 126.978 }); + + // useKakaoLoader를 사용해 Kakao Maps 스크립트 로드 + const [loading, error] = useKakaoLoader({ + appkey: process.env.NEXT_PUBLIC_KAKAO_APP_KEY as string, + libraries: ["services"], // 추가 옵션으로 services 라이브러리를 로드 + }); + + // 주소 검색 함수 (주소 → 좌표 변환) + const searchAddress = useCallback(() => { + if (!address) return; + if (typeof window === "undefined" || !window.kakao?.maps?.services) { + console.error("Kakao Maps Services not available yet"); + return; + } + + const geocoder = new window.kakao.maps.services.Geocoder(); + geocoder.addressSearch(address, (result: any[], status: string) => { + if (status === window.kakao.maps.services.Status.OK && result.length > 0) { + const { x, y } = result[0]; // x: 경도, y: 위도 + setCoords({ lat: parseFloat(y), lng: parseFloat(x) }); + } else { + alert("주소를 찾을 수 없습니다. 정확한 주소를 입력해주세요."); + } + }); + }, [address]); + + // 우편번호 검색 버튼 클릭 시 팝업 열기 + const handleOpenPostcode = useCallback(() => { + if (typeof window === "undefined" || !window.daum) return; + + new window.daum.Postcode({ + oncomplete: (data) => { + setAddress(data.address); + }, + }).open(); + }, []); + + return ( +
+ {/* Daum Postcode 스크립트 로드 */} +