Skip to content

Commit c73c5f3

Browse files
authored
Merge pull request #121 from FE9-2/feat/postcode
feat: kakao-map ํ…Œ์ŠคํŠธ ํŽ˜์ด์ง€ ์ถ”๊ฐ€ ๋ฐ ํด๋”๋ช… ์ˆ˜์ •
2 parents 85f914f + 201f5aa commit c73c5f3

File tree

10 files changed

+230
-32
lines changed

10 files changed

+230
-32
lines changed

โ€Žpackage-lock.jsonโ€Ž

Lines changed: 46 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

โ€Žpackage.jsonโ€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"react-hot-toast": "^2.4.1",
3030
"react-icons": "^5.3.0",
3131
"react-intersection-observer": "^9.13.1",
32+
"react-kakao-maps-sdk": "^1.1.27",
3233
"react-modal": "^3.16.1",
3334
"react-spinners": "^0.14.1",
3435
"tailwind-merge": "^2.5.4",
@@ -67,6 +68,7 @@
6768
"eslint-config-prettier": "^9.1.0",
6869
"eslint-plugin-prettier": "^5.2.1",
6970
"eslint-plugin-storybook": "^0.11.0",
71+
"kakao.maps.d.ts": "^0.1.40",
7072
"postcss": "^8.4.47",
7173
"prettier-plugin-tailwindcss": "^0.6.8",
7274
"storybook": "^8.4.4",
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
"use client";
2+
3+
import React, { useState, useCallback } from "react";
4+
import Script from "next/script";
5+
import { Map, MapMarker, useKakaoLoader } from "react-kakao-maps-sdk";
6+
7+
interface Coords {
8+
lat: number;
9+
lng: number;
10+
}
11+
12+
declare global {
13+
interface Window {
14+
daum: {
15+
Postcode: new (config: {
16+
oncomplete: (data: { address: string; zonecode: string; [key: string]: any }) => void;
17+
}) => { open: () => void };
18+
};
19+
}
20+
}
21+
22+
const KakaoMapPage = () => {
23+
const [address, setAddress] = useState("");
24+
const [coords, setCoords] = useState<Coords>({ lat: 37.5665, lng: 126.978 });
25+
26+
// useKakaoLoader๋ฅผ ์‚ฌ์šฉํ•ด Kakao Maps ์Šคํฌ๋ฆฝํŠธ ๋กœ๋“œ
27+
const [loading, error] = useKakaoLoader({
28+
appkey: process.env.NEXT_PUBLIC_KAKAO_APP_KEY as string,
29+
libraries: ["services"], // ์ถ”๊ฐ€ ์˜ต์…˜์œผ๋กœ services ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋กœ๋“œ
30+
});
31+
32+
// ์ฃผ์†Œ ๊ฒ€์ƒ‰ ํ•จ์ˆ˜ (์ฃผ์†Œ โ†’ ์ขŒํ‘œ ๋ณ€ํ™˜)
33+
const searchAddress = useCallback(() => {
34+
if (!address) return;
35+
if (typeof window === "undefined" || !window.kakao?.maps?.services) {
36+
console.error("Kakao Maps Services not available yet");
37+
return;
38+
}
39+
40+
const geocoder = new window.kakao.maps.services.Geocoder();
41+
geocoder.addressSearch(address, (result: any[], status: string) => {
42+
if (status === window.kakao.maps.services.Status.OK && result.length > 0) {
43+
const { x, y } = result[0]; // x: ๊ฒฝ๋„, y: ์œ„๋„
44+
setCoords({ lat: parseFloat(y), lng: parseFloat(x) });
45+
} else {
46+
alert("์ฃผ์†Œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ •ํ™•ํ•œ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.");
47+
}
48+
});
49+
}, [address]);
50+
51+
// ์šฐํŽธ๋ฒˆํ˜ธ ๊ฒ€์ƒ‰ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํŒ์—… ์—ด๊ธฐ
52+
const handleOpenPostcode = useCallback(() => {
53+
if (typeof window === "undefined" || !window.daum) return;
54+
55+
new window.daum.Postcode({
56+
oncomplete: (data) => {
57+
setAddress(data.address);
58+
},
59+
}).open();
60+
}, []);
61+
62+
return (
63+
<div className="container mx-auto p-4">
64+
{/* Daum Postcode ์Šคํฌ๋ฆฝํŠธ ๋กœ๋“œ */}
65+
<Script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js" strategy="afterInteractive" />
66+
67+
<h1 className="mb-4 text-2xl font-bold">์šฐํŽธ๋ฒˆํ˜ธ ๊ฒ€์ƒ‰์œผ๋กœ ์ฃผ์†Œ ์ž…๋ ฅ & ์ง€๋„ ํ‘œ์‹œ (useKakaoLoader)</h1>
68+
<div className="mb-4 flex gap-2">
69+
<input
70+
type="text"
71+
placeholder="์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”"
72+
value={address}
73+
onChange={(e) => setAddress(e.target.value)}
74+
className="flex-1 border p-2"
75+
/>
76+
<button onClick={handleOpenPostcode} className="rounded bg-green-500 p-2 text-white hover:bg-green-600">
77+
์šฐํŽธ๋ฒˆํ˜ธ ์ฐพ๊ธฐ
78+
</button>
79+
<button
80+
onClick={searchAddress}
81+
disabled={loading || !!error}
82+
className="rounded bg-blue-500 p-2 text-white hover:bg-blue-600 disabled:bg-gray-400"
83+
>
84+
๊ฒ€์ƒ‰
85+
</button>
86+
</div>
87+
88+
<div className="h-96 w-full border">
89+
{error && <div className="text-red-500">Map load error: {String(error)}</div>}
90+
{loading && !error && (
91+
<div className="flex h-full items-center justify-center text-gray-500">Kakao Maps ๋กœ๋”ฉ ์ค‘...</div>
92+
)}
93+
{!loading && !error && (
94+
<Map center={coords} style={{ width: "100%", height: "100%" }} level={3}>
95+
<MapMarker position={coords}>ํ˜„์žฌ ์œ„์น˜</MapMarker>
96+
</Map>
97+
)}
98+
</div>
99+
100+
{coords && !loading && !error && (
101+
<div className="mt-4 text-lg text-gray-700">
102+
<p>์œ„๋„: {coords.lat}</p>
103+
<p>๊ฒฝ๋„: {coords.lng}</p>
104+
</div>
105+
)}
106+
</div>
107+
);
108+
};
109+
110+
export default KakaoMapPage;

โ€Žsrc/app/(pages)/myAlbaform/(role)/applicant/page.tsxโ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default function ApplicantPage() {
4848
if (!user) {
4949
router.push("/login");
5050
} else if (user.role === userRoles.OWNER) {
51-
router.push("/myAlbaform/owner");
51+
router.push("/myalbaform/owner");
5252
}
5353
}
5454
}, [user, isUserLoading, router]);

โ€Žsrc/app/(pages)/myAlbaform/(role)/owner/page.tsxโ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export default function AlbaList() {
2929
if (!user) {
3030
router.push("/login");
3131
} else if (user.role !== userRoles.OWNER) {
32-
router.push("/myAlbaform/applicant");
32+
router.push("/myalbaform/applicant");
3333
}
3434
}
3535
}, [user, isLoading, router]);

โ€Žsrc/app/(pages)/myAlbaform/page.tsxโ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ export default function MyAlbaForm() {
1515
router.push("/login");
1616
} else {
1717
if (user.role === userRoles.OWNER) {
18-
router.push("/myAlbaform/owner");
18+
router.push("/myalbaform/owner");
1919
} else {
20-
router.push("/myAlbaform/applicant");
20+
router.push("/myalbaform/applicant");
2121
}
2222
}
2323
}

โ€Žsrc/app/components/layout/Header.tsxโ€Ž

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,14 @@ export default function Header() {
8080
</Link>
8181

8282
<div className="ml-4 flex h-16 space-x-2 sm:ml-6 sm:space-x-4 md:ml-10 md:space-x-6">
83-
<Link href="/albaList" className={getLinkClassName("/albaList")}>
83+
<Link href="/albalist" className={getLinkClassName("/albalist")}>
8484
์•Œ๋ฐ” ๋ชฉ๋ก
8585
</Link>
86-
<Link href="/albaTalk" className={getLinkClassName("/albaTalk")}>
86+
<Link href="/albatalk" className={getLinkClassName("/albatalk")}>
8787
์•Œ๋ฐ” ํ† ํฌ
8888
</Link>
8989
{user && (
90-
<Link href="/myAlbaform" className={getLinkClassName("/myAlbaform")}>
90+
<Link href="/myalbaform" className={getLinkClassName("/myalbaform")}>
9191
๋‚ด ์•Œ๋ฐ”ํผ
9292
</Link>
9393
)}

โ€Žsrc/app/stories/design-system/components/layout/Header.tsxโ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default function Header() {
3636
<Link href="/albaTalk" className={getLinkClassName("/albaTalk")}>
3737
์•Œ๋ฐ” ํ† ํฌ
3838
</Link>
39-
<Link href="/myAlbaform" className={getLinkClassName("/myAlbaform")}>
39+
<Link href="/myalbaform" className={getLinkClassName("/myalbaform")}>
4040
๋‚ด ์•Œ๋ฐ”ํผ
4141
</Link>
4242
</div>

0 commit comments

Comments
ย (0)