All files postcode.js

0% Statements 0/18
0% Branches 0/4
0% Functions 0/6
0% Lines 0/17

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62                                                                                                                           
/**
 * 이 파일이 하는 일:
 * 다음(카카오) 우편번호 서비스를 불러와 주소 검색 UI를 띄운다.
 * 회원가입·내 정보의 [주소찾기] 버튼이 이걸 쓴다.
 *
 * 학습 포인트 ① — 왜 직접 입력 대신 주소 검색인가?
 * 주소는 "형식이 정해진 데이터"다. 손으로 치게 하면 시/군/구 누락, 오타, 옛 지번주소가
 * 뒤섞여 들어온다(실제로 그랬다). 검색으로 받으면 항상 표준 도로명주소 + 우편번호가 들어온다.
 * — 사용자의 실수는 사용자를 탓할 게 아니라 실수할 수 없는 UI로 막는 것이다.
 *
 * 학습 포인트 ② — 외부 스크립트 지연 로딩(lazy loading).
 * 이 스크립트는 주소찾기를 누르는 순간에만 필요하다. 앱 시작 때 미리 받으면
 * 모든 페이지가 그만큼 느려진다. 그래서 버튼을 눌렀을 때 <script>를 만들어 붙이고,
 * 한 번 받았으면 Promise를 재사용한다(두 번 다운로드하지 않는다).
 *
 * 학습 포인트 ③ — 팝업이 아닌 embed 방식.
 * window.open 팝업은 모바일 브라우저가 차단하기도 한다. embed는 우리가 준 div 안에
 * 검색 화면을 그려 넣는 방식이라 차단당할 게 없고, 모바일에서도 자연스럽다.
 */
 
const SCRIPT_SRC = 'https://t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js';
 
let scriptPromise = null;
 
function loadScript() {
  if (!scriptPromise) {
    scriptPromise = new Promise((resolve, reject) => {
      const script = document.createElement('script');
      script.src = SCRIPT_SRC;
      script.onload = () => resolve(window.daum);
      script.onerror = () => {
        scriptPromise = null; // 실패하면 다음 클릭 때 다시 시도할 수 있게 초기화
        reject(new Error('우편번호 서비스 로딩 실패'));
      };
      document.head.appendChild(script);
    });
  }
  return scriptPromise;
}
 
/**
 * 주소 검색 화면을 container(div) 안에 펼친다.
 *
 * @param {HTMLElement} container 검색 UI를 그릴 div
 * @param {(address: string) => void} onSelect 사용자가 주소를 고르면 완성된 주소 문자열을 받는다
 * @returns {Promise<void>} 스크립트 로딩 실패 시 reject — 호출한 쪽에서 안내를 띄운다
 */
export async function embedPostcode(container, onSelect) {
  const daum = await loadScript();
  container.innerHTML = ''; // 두 번째 열 때 이전 화면이 겹치지 않게 비운다
  new daum.Postcode({
    oncomplete: (data) => {
      // 도로명주소를 기본으로, 건물명이 있으면 괄호로 붙인다. 우편번호는 맨 앞에.
      // 예: "[06978] 서울 동작구 상도로17길 14-2 (OO빌딩)"
      const building = data.buildingName ? ` (${data.buildingName})` : '';
      onSelect(`[${data.zonecode}] ${data.roadAddress}${building}`);
    },
    width: '100%',
    height: '100%',
  }).embed(container);
}