129 lines
3.2 KiB
TypeScript
129 lines
3.2 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useCallback, useEffect, useState } from 'react';
|
||
|
|
|
||
|
|
// Daum Postcode 타입 정의
|
||
|
|
interface DaumPostcodeData {
|
||
|
|
zonecode: string; // 우편번호
|
||
|
|
address: string; // 기본 주소
|
||
|
|
addressEnglish: string; // 영문 주소
|
||
|
|
addressType: 'R' | 'J'; // R: 도로명, J: 지번
|
||
|
|
userSelectedType: 'R' | 'J';
|
||
|
|
roadAddress: string; // 도로명 주소
|
||
|
|
roadAddressEnglish: string;
|
||
|
|
jibunAddress: string; // 지번 주소
|
||
|
|
jibunAddressEnglish: string;
|
||
|
|
buildingCode: string;
|
||
|
|
buildingName: string; // 건물명
|
||
|
|
apartment: 'Y' | 'N'; // 아파트 여부
|
||
|
|
sido: string; // 시/도
|
||
|
|
sigungu: string; // 시/군/구
|
||
|
|
sigunguCode: string;
|
||
|
|
bname: string; // 법정동/법정리
|
||
|
|
bname1: string;
|
||
|
|
bname2: string;
|
||
|
|
hname: string; // 행정동
|
||
|
|
query: string; // 검색어
|
||
|
|
}
|
||
|
|
|
||
|
|
interface DaumPostcode {
|
||
|
|
open: () => void;
|
||
|
|
}
|
||
|
|
|
||
|
|
interface DaumPostcodeConstructor {
|
||
|
|
new (options: {
|
||
|
|
oncomplete: (data: DaumPostcodeData) => void;
|
||
|
|
onclose?: () => void;
|
||
|
|
width?: string | number;
|
||
|
|
height?: string | number;
|
||
|
|
}): DaumPostcode;
|
||
|
|
}
|
||
|
|
|
||
|
|
interface DaumNamespace {
|
||
|
|
Postcode: DaumPostcodeConstructor;
|
||
|
|
}
|
||
|
|
|
||
|
|
declare global {
|
||
|
|
interface Window {
|
||
|
|
daum?: DaumNamespace;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface PostcodeResult {
|
||
|
|
zonecode: string; // 우편번호
|
||
|
|
address: string; // 기본 주소 (도로명)
|
||
|
|
buildingName: string; // 건물명
|
||
|
|
jibunAddress: string; // 지번 주소
|
||
|
|
}
|
||
|
|
|
||
|
|
interface UseDaumPostcodeOptions {
|
||
|
|
onComplete?: (result: PostcodeResult) => void;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useDaumPostcode(options?: UseDaumPostcodeOptions) {
|
||
|
|
const [isScriptLoaded, setIsScriptLoaded] = useState(false);
|
||
|
|
const [isLoading, setIsLoading] = useState(false);
|
||
|
|
|
||
|
|
// 스크립트 로드
|
||
|
|
useEffect(() => {
|
||
|
|
// 이미 로드된 경우
|
||
|
|
if (window.daum?.Postcode) {
|
||
|
|
setIsScriptLoaded(true);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 이미 스크립트가 추가된 경우
|
||
|
|
const existingScript = document.querySelector(
|
||
|
|
'script[src*="postcode.v2.js"]'
|
||
|
|
);
|
||
|
|
if (existingScript) {
|
||
|
|
existingScript.addEventListener('load', () => setIsScriptLoaded(true));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 스크립트 추가
|
||
|
|
const script = document.createElement('script');
|
||
|
|
script.src =
|
||
|
|
'//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js';
|
||
|
|
script.async = true;
|
||
|
|
script.onload = () => setIsScriptLoaded(true);
|
||
|
|
document.head.appendChild(script);
|
||
|
|
|
||
|
|
return () => {
|
||
|
|
// cleanup: 스크립트는 유지 (다른 컴포넌트에서 사용할 수 있음)
|
||
|
|
};
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
// 우편번호 검색 팝업 열기
|
||
|
|
const openPostcode = useCallback(() => {
|
||
|
|
if (!isScriptLoaded || !window.daum?.Postcode) {
|
||
|
|
console.warn('Daum Postcode script not loaded yet');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
setIsLoading(true);
|
||
|
|
|
||
|
|
new window.daum.Postcode({
|
||
|
|
oncomplete: (data: DaumPostcodeData) => {
|
||
|
|
const result: PostcodeResult = {
|
||
|
|
zonecode: data.zonecode,
|
||
|
|
address: data.roadAddress || data.jibunAddress,
|
||
|
|
buildingName: data.buildingName,
|
||
|
|
jibunAddress: data.jibunAddress,
|
||
|
|
};
|
||
|
|
|
||
|
|
options?.onComplete?.(result);
|
||
|
|
setIsLoading(false);
|
||
|
|
},
|
||
|
|
onclose: () => {
|
||
|
|
setIsLoading(false);
|
||
|
|
},
|
||
|
|
}).open();
|
||
|
|
}, [isScriptLoaded, options]);
|
||
|
|
|
||
|
|
return {
|
||
|
|
openPostcode,
|
||
|
|
isScriptLoaded,
|
||
|
|
isLoading,
|
||
|
|
};
|
||
|
|
}
|