PageSourceSearch

https://ssonda.ai/assets/js/pages/site/signup.js;jsessionid=B2ACCAF172821ABB729E90E02C9B1EAB?v=1790900716734

js ssonda.ai collected 2026-10-02 00:27:14 UTC 19,329 bytes, 513 lines download raw bytes

1/**
2 * 회원가입 화면에서 사용하는 기능 정의
3 *
4 * @author h.kang
5 * @date 2024-08-21
6 */
7
8let salesConnectTime;
9
10document.addEventListener("DOMContentLoaded", function () {
11    // signUpComplete 페이지에서 salesCheckSection이 처음부터 보이는 경우
12    let salesCheckSection = document.querySelector("#salesCheckSection");
13    if (salesCheckSection && !document.querySelector("form[name=signup]")) {
14        showCrepiaRejectedBannerIfNeeded(salesCheckSection);
15    }
16
17    let form = document.querySelector("form[name=signup]");
18
19    if (form) {
20        // 추천인 정보가 있는 경우
21        let referCode = getCookie("salesOfficeUserCode");
22        let referName = getCookie("salesOfficeUserName");
23        if (referCode && referName) {
24            document.querySelector(".refer-name").innerText = `${referName} #${referCode}`;
25            document.querySelector("#referMessage").classList.remove("d-none");
26            form.insertAdjacentHTML("beforeend", `<input type="hidden" name="salesOfficeUserCode" value="${referCode}">`);
27        }
28    }
29    
30    let signupTerms = form?.querySelector("#signupTerms");
31    let signupVerify = form?.querySelector("#signupVerify");
32    let signupPassword = form?.querySelector("#signupPassword");
33
34    // 이용약관 화면에서 이용약관 다음 버튼 클릭 시
35    signupTerms?.querySelector(".btn-signup-terms-next")?.addEventListener("click", () => {
36        let step = form.dataset.step;
37        if (step != 1) {
38            // step 1이 아니면 무시
39            return;
40        }
41
42        let isRequireChecked = true;
43        form.querySelectorAll(".form-check-input[required]").forEach((checkbox) => {
44            isRequireChecked = isRequireChecked && checkbox.checked;
45        });
46
47        if (!isRequireChecked) {
48            toastr.error(i18n.t('signup.error.terms'));
49            return;
50        }
51
52        changeStep(2);
53    });
54
55    // 본인인증 화면에서 본인인증 버튼 클릭 시
56    signupVerify?.querySelector(".btn-signup-verify")?.addEventListener("click", async () => {
57        let step = form.dataset.step;
58        if (step != 2) {
59            // step 2이 아니면 무시
60            return;
61        }
62
63        await idVerify();
64    });
65
66    // 본인인증 화면에서 본인인증 버튼 클릭 시
67    signupPassword?.querySelector(".btn-signup-complete")?.addEventListener("click", async () => {
68        let step = form.dataset.step;
69        if (step != 3) {
70            // step 3이 아니면 무시
71            return;
72        }
73
74        if (!(await validateSingleField(form.querySelector("input[name=password]")))) {
75            return;
76        }
77
78        if (!(await validateSingleField(form.querySelector("input[name=passwordConfirm]")))) {
79            return;
80        }
81
82        JsLoadingOverlay.show();
83
84        // 약관 동의 이력 hidden 주입 (체크 → agree, 미체크 → disagree)
85        form.querySelectorAll(".terms-agree-hidden").forEach((el) => el.remove());
86        let terms = collectTermsAgreement(form);
87        terms.agree.forEach((id) => form.insertAdjacentHTML("beforeend",
88            `<input type='hidden' class='terms-agree-hidden' name='agreePostIdList' value='${id}'>`));
89        terms.disagree.forEach((id) => form.insertAdjacentHTML("beforeend",
90            `<input type='hidden' class='terms-agree-hidden' name='disagreePostIdList' value='${id}'>`));
91
92        submit(form, {
93            onComplete: (data) => {
94                JsLoadingOverlay.hide();
95
96                if (data.code == RESULT_CODE_SUCCESS || data.code == 0) {
97                    sendHttpReviewScrape(data.shopId);
98
99                    if (data.isAllAccountConnected == "Y") {
100                        window.location.replace("/user/signUpComplete?type=connected");
101                    } else {
102                        window.location.replace("/user/signUpComplete");
103                    }
104                } else {
105                    errorHandling(data.code, data.message);
106                }
107            },
108        });
109    });
110
111    // 매출 확인하기 화면으로 전환
112    document.querySelector(".btn-check-sales")?.addEventListener("click", () => {
113        document.querySelector("#signupResultSection").remove();
114        document.querySelector("#salesCheckSection").classList.remove("d-none");
115        showCrepiaRejectedBannerIfNeeded(document.querySelector('#salesCheckSection'));
116    });
117
118    document.querySelectorAll(".btn-home").forEach((el) => {
119        el.addEventListener("click", async () => {
120            let isChecked = false;
121            let isLogin = el.dataset.isLogin == "1";
122
123            document.querySelectorAll(".check-status").forEach((el) => {
124                isChecked = isChecked || el.dataset.status == "1";
125            });
126
127            if (isChecked) {
128                if (isLogin) {
129                    let modal = new DynamicModal(i18n.t('contract.service.title'), i18n.t('contract.service.needContract'));
130
131                    modal.setModalSize(MODAL_SIZE_SM);
132                    modal.setConfirmButton(i18n.t('contract.button'), () => {
133                        window.location.href = "/contract/preEval";
134                    });
135                    modal.setCancelButton(i18n.t('skip'), () => {
136                        window.location.href = "/home";
137                    });
138
139                    modal.show();
140                } else {
141                    let modal = new DynamicModal(i18n.t('contract.service.title'), i18n.t('contract.service.needSignUp'));
142
143                    modal.setModalSize(MODAL_SIZE_SM);
144                    modal.setConfirmButton(i18n.t('signup.label'), () => {
145                        window.location.href = "/signUp";
146                    });
147
148                    modal.show();
149                }
150            } else {
151                let sendHttp = new SendHttp("/sales/checkResultScrape");
152                sendHttp.method = "GET";
153                sendHttp.data = {'salesConnectTime': salesConnectTime};
154
155                // Show page loading
156                JsLoadingOverlay.show();
157                let retryResultMap = await sendHttp.send();
158                JsLoadingOverlay.hide();
159
160                switch (retryResultMap.code) {
161                    case 'S0237':
162                    case 'S0238':
163                    case 'S0239': {
164                        return showSalesCheckConnecting(retryResultMap);
165                    }
166                    case 'S0246': {
167                        return;
168                    }
169                    case 'S0256': {
170                        let landingEl = document.querySelector('#brandContainer[data-is-login]');
171                        let isLogin = landingEl == null ? true : landingEl.dataset.isLogin === '1';
172                        showCrepiaRequestModal(null, null, isLogin);
173                        return;
174                    }
175                    default:
176                        break;
177                }
178
179                toastr.error(i18n.t('signup.error.salesCheckRequired'));
180            }
181        });
182    });
183
184    document.querySelectorAll("input[type=text], input[type=password]").forEach((el) => {
185        el.addEventListener("keypress", (e) => {
186            if (e.key == "Enter") {
187                e.preventDefault();
188
189                // 매출 조회 화면 (.sales-check-item) 처리
190                const salesCheckItem = el.closest(".sales-check-item");
191                if (salesCheckItem) {
192                    if (el.name == "username") {
193                        salesCheckItem.querySelector("input[name=password]").focus();
194                    } else if (el.name == "password") {
195                        salesCheckItem.querySelector(".btn-sales-inquiry").click();
196                    }
197                } else {
198                    // 회원가입 비밀번호 화면 (#signupPassword) 처리
199                    if (el.name == "password") {
200                        document.querySelector("input[name=passwordConfirm]").focus();
201                    } else if (el.name == "passwordConfirm") {
202                        document.querySelector(".btn-signup-complete").click();
203                    }
204                }
205            }
206        });
207    });
208
209    // 화면 전체에 이벤트 부여
210    document.addEventListener("click", async (e) => {
211        let targetEl = e.target;
212        if (targetEl.classList.contains("btn-sales-inquiry")) {
213            let container = e.target.closest(".sales-check-item");
214            let type = container.dataset.type;
215            let userId = container.dataset.userId;
216            let usernameInput = container.querySelector("input[name=username]");
217            let passwordInput = container.querySelector("input[name=password]");
218
219            if (usernameInput?.value == "") {
220                toastr.error(i18n.t('error.required.messageWithTarget', { item: i18n.withJosa('username', '를') }));
221                usernameInput.focus();
222                return;
223            }
224
225            if (passwordInput?.value == "") {
226                toastr.error(i18n.t('error.required.messageWithTarget', { item: i18n.withJosa('password', '를') }));
227                passwordInput.focus();
228                return;
229            }
230
231            // 매출 조회 API 호출
232            let data = new FormData();
233            data.append("type", type);
234            data.append("userId", userId);
235            data.append("accountId", usernameInput.value);
236            data.append("accountPassword", passwordInput.value);
237            data.append("salesConnectTime", salesConnectTime);
238
239            // !! 수정필요시 js\pages\site\sales.js, js\pages\site\shop.js 에도 고쳐야함 !!
240            if (type == '0') {
241                data.append('scrapeCompany', 'infotech');
242            }
243
244            let sendHttp = new SendHttp(`/sales/scrapeByAccount3PartyInfo`);
245            sendHttp.data = data;
246            sendHttp.method = "POST";
247
248            let progressModal = showSalesCheckProgress(type);
249
250            let resultMap = await sendHttp.send();
251
252            // 조회 성공 시
253            let checkResult;
254
255            switch (resultMap.code) {
256                case 'S0237':
257                case 'S0238':
258                case 'S0239': {
259                    progressModal.setOnClose(() => {
260                        showSalesCheckConnecting(resultMap, type, data, container);
261                    });
262                    progressModal.hide();
263                    break;
264                }
265                case 'S0246': {
266                    progressModal.hide();
267                    return;
268                }
269                case 'S0248': {
270                    progressModal.setOnClose(() => {
271                        showSalesCheckMultiShop(resultMap, data, container);
272                    });
273                    progressModal.hide();
274                    return;
275                }
276                case 'S0256': {
277                    progressModal.setOnClose(() => {
278                        let landingEl = document.querySelector('#brandContainer[data-is-login]');
279                        let isLogin = landingEl == null ? true : landingEl.dataset.isLogin === '1';
280                        showCrepiaRequestModal(usernameInput.value, passwordInput.value, isLogin);
281                    });
282                    progressModal.hide();
283                    return;
284                }
285                default:
286                    checkResult = showSalesCheckResult(resultMap, type, null, progressModal);
287                    break;
288            }
289
290            // 성공이 아닌경우 아래 코드는 실행되지 않음
291            if (!checkResult) {
292                return;
293            }
294
295            container.querySelectorAll(".check-status").forEach((el) => {
296                el.dataset.status = "1";
297                el.classList.remove("text-gray-400");
298                el.classList.add("text-success");
299                if (el.tagName == "SPAN") {
300                    el.innerText = i18n.t('status.normal');
301                }
302            });
303
304            let totalPrice = resultMap.data?.salesSumForPrepay ?? 0;
305
306            let salesPreviews = document.querySelectorAll(".sales-preview");
307            salesPreviews.forEach((el) => {
308                const rect = el.getBoundingClientRect();
309                if (rect.width > 0 && rect.height > 0) {
310                    let scrollPosition = el.getBoundingClientRect().top + window.scrollY - 150;
311
312                    // 스크롤 이동
313                    window.scrollTo({ top: scrollPosition, behavior: "smooth" });
314
315                    // 숫자 올라가는 애니메이션
316                    animateNumber(el.querySelector(".number"), 0, totalPrice, 1000);
317                }
318            });
319        }
320    });
321
322    if (document.querySelector('.sale-check-section')) {
323        moment.locale("ko"); // 한국어 설정
324        salesConnectTime = moment().format("YYYYMMDDHHmmss");
325    }
326});
327
328function changeStep(step) {
329    document.querySelector("form[name=signup]").dataset.step = step;
330
331    let signupTerms = document.querySelector("#signupTerms");
332    let signupVerify = document.querySelector("#signupVerify");
333    let signupPassword = document.querySelector("#signupPassword");
334
335    if (step == 2) {
336        signupTerms?.classList.add("d-none");
337        signupVerify?.classList.remove("d-none");
338    } else if (step == 3) {
339        signupVerify?.classList.add("d-none");
340        signupPassword?.classList.remove("d-none");
341    }
342
343    document.querySelectorAll(".step-indicator .step-dot").forEach((el, index) => {
344        el.classList.remove("active", "done");
345
346        if (index + 1 < step) {
347            el.classList.add("done");
348        }
349
350        if (index + 1 == step) {
351            el.classList.add("active");
352        }
353    });
354}
355
356let idVerifyPopup;
357async function idVerify() {
358    let phoneInput = document.querySelector("input[name=phone]");
359
360    if (!(await validateSingleField(phoneInput))) {
361        return;
362    }
363
364    if (idVerifyPopup != null && !idVerifyPopup.closed) {
365        toastr.error(i18n.t('signup.error.idVerifyInProgress'));
366        return false;
367    }
368
369    // 전화번호 중복 확인
370    let chkUrl = "/validDuplicatePhone";
371    let sendHttp = new SendHttp(chkUrl);
372    sendHttp.data = {
373        phone: phoneInput.value,
374        role: 1,
375    };
376
377    JsLoadingOverlay.show();
378    let resultMap = await sendHttp.send();
379    JsLoadingOverlay.hide();
380
381    if (resultMap.code != RESULT_CODE_AVAILABLE) {
382        errorHandling(resultMap.code, resultMap.message);
383        return false;
384    }
385
386    idVerifyPopup = window.open(`/requestIdVerify?phone=${phoneInput.value}`, "_blank", "width=430,height=640,scrollbars=yes");
387
388    if (idVerifyPopup == null || typeof idVerifyPopup === "undefined") {
389        let message = "";
390
391        const userAgent = navigator.userAgent;
392        if (userAgent.includes("Chrome") && !userAgent.includes("Edg")) {
393            message = i18n.t('allowPopup.chrome');
394        } else if (userAgent.includes("Safari") && !userAgent.includes("Chrome")) {
395            if (userAgent.includes("iPhone") || userAgent.includes("iPad") || userAgent.includes("iPod")) {
396                // iOS Safari
397                message = i18n.t('allowPopup.safariIos');
398            } else {
399                // macOS Safari
400                message = i18n.t('allowPopup.safariMac');
401            }
402        } else if (userAgent.includes("Edg")) {
403            message = i18n.t('allowPopup.edge');
404        } else if (userAgent.includes("Firefox")) {
405            message = i18n.t('allowPopup.firefox');
406        } else {
407            message = i18n.t('allowPopup.default');
408        }
409
410        let modal = new DynamicModal(i18n.t('allowPopup.title'), message);
411        modal.setModalSize(MODAL_SIZE_SM);
412        modal.removeCancelButton();
413        modal.show();
414
415        return false;
416    }
417}
418
419async function onCompleteIdVerify(resultMap) {
420    let phoneInput = document.querySelector("input[name=phone]");
421    let isVerified = resultMap.phone == phoneInput.value.replaceAll('-', '');
422
423    // 잘못된 화면에서 function 호출 시 처리
424    if (!phoneInput || document.querySelector('#signupVerify').classList.contains('d-none')) {
425        console.warn('잘못된 접근');
426        return;
427    }
428
429    // 결과값이 없는 경우 처리
430    if (!resultMap) {
431        toastr.error(i18n.t('error.message'));
432        return false;
433    }
434
435    // 입력한 전화번호와 본인인증 결과가 일치하지 않으면 에러 처리
436    if (isVerified) {
437        toastr.success(i18n.t('signup.idVerifySuccess'));
438        changeStep(3);
439
440        let form = document.querySelector("form[name=signup]");
441        form.insertAdjacentHTML("beforeend", `<input type="hidden" name="fullName" value="${escapeHtml(resultMap.fullName)}">`);
442        form.insertAdjacentHTML("beforeend", `<input type="hidden" name="birthd" value="${escapeHtml(resultMap.birth)}">`);
443        form.insertAdjacentHTML("beforeend", `<input type="hidden" name="gender" value="${escapeHtml(resultMap.gender)}">`);
444        form.insertAdjacentHTML("beforeend", `<input type="hidden" name="national" value="${escapeHtml(resultMap.national)}">`);
445        form.insertAdjacentHTML("beforeend", `<input type="hidden" name="telecomProvider" value="${escapeHtml(resultMap.telecom)}">`);
446        form.querySelector("input[name=phone]").value = formatPhone(resultMap.phone);
447
448        return true;
449    } else {
450        toastr.error(i18n.t('signup.error.phoneMismatch'));
451        phoneInput.focus();
452        return false;
453    }
454}
455
456window.addEventListener("message", (event) => {
457    // 보안 검증: 메시지를 보낸 도메인이 일치하는지 확인
458    // if (event.origin !== "https://popup-domain.com") return;
459
460    // 받은 데이터 처리
461    const data = event.data;
462
463    // data가 비어있는 경우 처리
464    if (isNullOrEmpty(data)) {
465        return;
466    }
467
468    // 본인인증 결과 처리
469    if (data.phone && data.fullName) {
470        onCompleteIdVerify(data);
471    }
472
473});
474
475// 인증 결과화면이 opener 없이(새 탭 복귀 등) 열려 postMessage가 불가능할 때 localStorage로 남긴 결과 수신
476const ID_VERIFY_RESULT_KEY = "idVerifyResult";
477
478function consumeIdVerifyResult() {
479    if (idVerifyPopup == null) {
480        return; // 이 화면에서 본인인증을 시작한 적 없으면 무시 (다른 화면의 잔여 결과 오인 방지)
481    }
482
483    let raw = localStorage.getItem(ID_VERIFY_RESULT_KEY);
484    if (raw == null) {
485        return;
486    }
487    localStorage.removeItem(ID_VERIFY_RESULT_KEY); // 중복 처리 방지를 위해 읽는 즉시 제거
488
489    try {
490        let stored = JSON.parse(raw);
491        let data = stored?.data;
492
493        // 5분 이내 결과만 유효 처리
494        if (Date.now() - stored.time < 5 * 60 * 1000 && data?.phone && data?.fullName) {
495            onCompleteIdVerify(data);
496        }
497    } catch (e) {
498        // 파싱 불가한 결과는 무시
499    }
500}
501
502window.addEventListener("storage", (event) => {
503    if (event.key === ID_VERIFY_RESULT_KEY) {
504        consumeIdVerifyResult();
505    }
506});
507
508// 백그라운드 탭에는 storage 이벤트가 지연/누락될 수 있어(Safari 등) 탭 복귀 시에도 확인
509document.addEventListener("visibilitychange", () => {
510    if (!document.hidden) {
511        consumeIdVerifyResult();
512    }
513});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.