1// DOM ë¡ë í ì¤í 2document.addEventListener("DOMContentLoaded", () => { 3 // let searchInput = document.querySelector('input[name=search]'); 4 5 // ë¹ë°ë²í¸ ë³ê²½ ì ì´ë²¤í¸ ì²ë¦¬ 6 document.querySelector("form#updatePassword")?.addEventListener("submit", async (e) => { 7 e.preventDefault(); 8 e.stopImmediatePropagation(); 9 10 updatePassword(e.target); 11 }); 12 13 // ê³µì§ì¬í íë©´ í¸ì¶ ì ì´ë²¤í¸ ì²ë¦¬ 14 if (document.querySelector("#noticeList")) { 15 let noticeType = "notice"; 16 17 getNoticeList(); 18 19 document.querySelector("#searchFormAjax")?.addEventListener("submit", async (e) => { 20 e.preventDefault(); 21 e.stopImmediatePropagation(); 22 23 // if (searchInput?.value != '' && searchInput?.value.length < 2) { 24 // searchInput?.focus(); 25 // toastr.error('ê²ìì´ë 2ê¸ì ì´ì ì ë ¥í´ ì£¼ì¸ì.'); 26 // return; 27 // } 28 29 // getNoticeList(noticeType, 1, searchInput?.value); 30 getNoticeList(noticeType, 1); 31 }); 32 33 document.querySelector("#noticeType")?.addEventListener("click", (e) => { 34 e.preventDefault(); 35 e.stopImmediatePropagation(); 36 37 let targetEl = e.target.closest(".nav-link"); 38 if (targetEl.classList.contains("active")) { 39 return; 40 } 41 42 targetEl.closest(".nav").querySelector(".nav-link.active").classList.remove("active"); 43 targetEl.classList.add("active"); 44 45 noticeType = targetEl.dataset.type; 46 47 // searchInput.value = ''; 48 49 getNoticeList(noticeType); 50 }); 51 } 52 53 // FAQ íë©´ í¸ì¶ ì ì´ë²¤í¸ ì²ë¦¬ 54 if (document.querySelector("#faqList")) { 55 let faqType = document.querySelector("#faqType")?.dataset?.selectedType ?? "faq"; 56 57 if (faqType == "faq") { 58 getFaqList(); 59 } else { 60 getQnaList(); 61 } 62 63 document.querySelector("#searchFormAjax")?.addEventListener("submit", async (e) => { 64 e.preventDefault(); 65 e.stopImmediatePropagation(); 66 67 if (searchInput.value != "" && searchInput.value.length < 2) { 68 searchInput.focus(); 69 toastr.error("ê²ìì´ë 2ê¸ì ì´ì ì ë ¥í´ ì£¼ì¸ì."); 70 return; 71 } 72 73 getFaqList(faqType, 1, searchInput.value); 74 }); 75 } 76 77 // ì ì± ë° ì½ê´ íë©´ í¸ì¶ ì ì´ë²¤í¸ ì²ë¦¬ 78 if (document.querySelector("#termsList")) { 79 let termsType = "terms"; 80 81 getTermsList(); 82 83 document.querySelector("#searchFormAjax")?.addEventListener("submit", async (e) => { 84 e.preventDefault(); 85 e.stopImmediatePropagation(); 86 87 if (searchInput.value != "" && searchInput.value.length < 2) { 88 searchInput.focus(); 89 toastr.error("ê²ìì´ë 2ê¸ì ì´ì ì ë ¥í´ ì£¼ì¸ì."); 90 return; 91 } 92 93 getTermsList(termsType, 1, searchInput.value); 94 }); 95 } 96 97 // ì ì± ë° ì½ê´ íë©´ í¸ì¶ ì ì´ë²¤í¸ ì²ë¦¬ 98 if (document.querySelector("#qnaList")) { 99 getQnaList(); 100 101 document.querySelector("#searchFormAjax")?.addEventListener("submit", async (e) => { 102 e.preventDefault(); 103 e.stopImmediatePropagation(); 104 105 if (searchInput.value != "" && searchInput.value.length < 2) { 106 searchInput.focus(); 107 toastr.error("ê²ìì´ë 2ê¸ì ì´ì ì ë ¥í´ ì£¼ì¸ì."); 108 return; 109 } 110 111 getTermsList(1, searchInput.value); 112 }); 113 } 114 115 if (document.querySelector("form[name=qna_add]")) { 116 let form = document.querySelector("form[name=qna_add]"); 117 118 form.addEventListener("submit", async (e) => { 119 e.preventDefault(); 120 e.stopImmediatePropagation(); 121 122 onSubmitQna(form); 123 }); 124 } 125 126 let userEditForm = document.querySelector("form[name=user_edit]"); 127 if (userEditForm) { 128 userEditForm.querySelector(".id-verify")?.addEventListener("click", async (e) => { 129 e.preventDefault(); 130 e.stopImmediatePropagation(); 131 132 idVerify(); 133 }); 134 135 // ë´ ì ë³´ ë³ê²½ ì ì´ë²¤í¸ ì²ë¦¬ 136 userEditForm?.addEventListener("submit", async (e) => { 137 e.preventDefault(); 138 139 let emailInput = userEditForm.querySelector("input[name=email]"); 140 if (!(await validateSingleField(emailInput))) { 141 return; 142 } 143 144 let phoneInput = userEditForm.querySelector("input[name=phone_number]"); 145 if (phoneInput.dataset.original != phoneInput.value) { 146 if (!(await validateSingleField(phoneInput))) { 147 return; 148 } 149 150 if (!window.idVerifyResult) { 151 toastr.error("í´ëì íë²í¸ ë³ê²½ì ìí 본ì¸ì¸ì¦ì´ íìí©ëë¤."); 152 return; 153 } 154 } 155 156 submit(userEditForm, { 157 onComplete: (data) => { 158 // ìì ì ì¥ë í´ëì íë²í¸ íë ìì ë° ë³¸ì¸ì¸ì¦ ê²°ê³¼ ì´ê¸°í 159 userEditForm.querySelector("input[name=phone]")?.remove(); 160 window.idVerifyResult = false;
161 162 if (data.code == RESULT_CODE_SUCCESS || data.code == 0) { 163 toastr.success(i18n.t('msg.saveSuccess')); 164 } else { 165 errorHandling(data.code); 166 return; 167 } 168 169 setTimeout(() => { 170 history.back(); 171 }, 1000); 172 }, 173 }); 174 }); 175 } 176 177 if (document.querySelector("#qnaDetailSection")) { 178 getQnaDetail(); 179 } 180 181 if (document.querySelector("#noticeDetailSection")) { 182 postNoticeDetail(); 183 } 184}); 185 186// ê³µì§ì¬í ì¡°í 187async function getNoticeList(type, page, search, lang) { 188 let sendHttp = new SendHttp("/post/listJson"); 189 let formData = new FormData(); 190 formData.append("type", type ?? "notice"); 191 formData.append("page", page ?? 1); 192 formData.append("search", search ?? ""); 193 formData.append("lang", lang ?? "ko"); 194 formData.append("targetList", "all"); 195 formData.append("targetList", "ceo"); 196 formData.append("allItem", "1"); 197 198 sendHttp.data = Array.from(formData.entries()); 199 200 JsLoadingOverlay.setOptions({ containerID: "noticeListSection", overlayOpacity: 0.0 }); 201 JsLoadingOverlay.show(); 202 let resultMap = await sendHttp.send(); 203 JsLoadingOverlay.hide(); 204 205 if (resultMap != null) { 206 // 리ì¤í¸ 207 let list = resultMap.list; 208 let listContainer = document.querySelector("#noticeList"); 209 210 // document.querySelector('.total-count').innerText = numberWithCommas(list.length); 211 212 listContainer.innerHTML = ""; 213 if (list.length == 0) { 214 listContainer.innerHTML = ` 215 <div class="my-6 text-center text-gray-400 fs-base min-h-300px d-flex align-items-center justify-content-center">ë±ë¡ë ê³µì§ì¬íì´ ììµëë¤.</div> 216 `; 217 } else { 218 listContainer.classList.remove("d-none"); 219 list.forEach((item) => { 220 let listEl = document.createElement("div"); 221 listEl.classList.add("list-group-item", "list-group-item-action", "w-auto", "d-flex", "justify-content-between", "align-items-center", "rounded-4", "border-0", "cursor-pointer", "mx-n3"); 222 listEl.dataset.id = item.id; 223 224 listEl.innerHTML = ` 225 <div class="d-flex flex-column py-2"> 226 <div class="fs-base fw-semibold">${item.title ?? "-"}</div> 227 <div class="fs-7 text-gray-600">${formatDateTime(item.created, "dayTimeMin")}</div> 228 </div> 229 `; 230 231 listEl.addEventListener("click", async (e) => { 232 e.preventDefault(); 233 e.stopImmediatePropagation(); 234 235 const id = e.currentTarget.dataset.id; 236 location.href = `/post/detail?id=${id}`; 237 }); 238 239 listContainer.append(listEl); 240 }); 241 } 242 } 243} 244 245// FAQ ì¡°í 246async function getFaqList(type, page, search, lang) { 247 let sendHttp = new SendHttp("/post/listJson"); 248 249 let formData = new FormData(); 250 formData.append("type", type ?? "faq"); 251 formData.append("page", page ?? 1); 252 formData.append("search", search ?? ""); 253 formData.append("lang", lang ?? "ko"); 254 formData.append("targetList", "all"); 255 formData.append("targetList", "ceo"); 256 formData.append("allItem", "1"); 257 258 sendHttp.data = Array.from(formData.entries()); 259 260 JsLoadingOverlay.setOptions({ containerID: "faqListSection", overlayOpacity: 0.0 }); 261 JsLoadingOverlay.show(); 262 let resultMap = await sendHttp.send(); 263 JsLoadingOverlay.hide(); 264 265 if (document.querySelector('#supportBanner')) { 266 document.querySelector('#supportBanner').classList.remove('d-none'); 267 } 268 269 if (resultMap != null) { 270 // 리ì¤í¸ 271 let list = resultMap.list; 272 let listContainer = document.querySelector("#faqList"); 273 274 // document.querySelector('.total-count').innerText = numberWithCommas(list.length); 275 276 listContainer.innerHTML = ""; 277 if (list.length == 0) { 278 listContainer.innerHTML = ` 279 <div class="my-6 text-center text-gray-400 fs-base min-h-300px d-flex align-items-center justify-content-center">ë±ë¡ë FAQê° ììµëë¤.</div> 280 `; 281 } else { 282 listContainer.classList.remove("d-none"); 283 list.forEach((item) => { 284 let listEl = document.createElement("div"); 285 listEl.dataset.id = item.id; 286 listEl.classList.add('mx-n3'); 287 288 let fileList = item.fileList; 289 let fileHtml = ''; 290 if (fileList.length > 0) { 291 fileList.forEach((file) => { 292 fileHtml += `<img src="${resultMap.filePath}/${file.name}" alt="${file.name}" class="img-fluid">`; 293 }); 294 } 295 296 listEl.innerHTML = ` 297 <div class="faq-list-item bg-hover-light-dark text-hover-primary curs
297or-pointer d-flex align-items-baseline gap-3 p-4 rounded-4 w-100 rotate collapsible collapsed" data-bs-toggle="collapse" href="#faq${item.id}"> 298 <div class="d-flex align-items-baseline gap-3"> 299 <span class="fs-4 fw-bold text-brand-1-dark">Q</span> 300 <div class="flex-fill"> 301 <span class="fw-semibold">${item.title}</span> 302 <div id="faq${item.id}" class="collapse mt-5"> 303 <div class="d-flex flex-column gap-3"> 304 <div class="img-list ${fileList.length > 0 ? 'd-flex' : 'd-none'} flex-column gap-3">${fileHtml}</div> 305 <div class="text-dark contents">${item.contents}</div> 306 </div> 307 </div> 308 </div> 309 </div> 310 <i class="fa-solid fa-chevron-down rotate-n180 ms-auto"></i> 311 </div> 312 `; 313 314 listContainer.append(listEl); 315 }); 316 } 317 } 318} 319 320// FAQ ìì¸ ì¡°í 321async function getFaqDetail(id) { 322 let sendHttp = new SendHttp("/post/get"); 323 sendHttp.isStoreData = true; 324 sendHttp.data = { 325 id: id, 326 bGetDetail: true, 327 }; 328 329 let resultMap = await sendHttp.send(); 330 331 if (resultMap == null || resultMap.code != RESULT_CODE_SUCCESS) { 332 return; 333 } 334 335 let filePath = resultMap.filePath; 336 337 let faqItem = document.querySelector(`#faq${id}`); 338 let imgListEl = faqItem.querySelector(".img-list"); 339 let imgList = resultMap.item.fileList; 340 341 if (imgList.length > 0) { 342 imgListEl.classList.remove("d-none"); 343 imgListEl.classList.add("d-flex"); 344 imgListEl.innerHTML = ""; 345 imgList.forEach((img) => { 346 imgListEl.insertAdjacentHTML("beforeend", `<img src="${filePath}/${img.name}" alt="${img.name}" class="img-fluid">`); 347 }); 348 } 349} 350 351// ì ì± ë° ì½ê´ ì¡°í 352async function getTermsList(type, page, search, lang) { 353 let sendHttp = new SendHttp("/post/listJson"); 354 sendHttp.data = { 355 type: type ?? "terms", 356 page: page ?? 1, 357 search: search ?? "", 358 lang: lang ?? "ko", 359 allItem: "1", 360 }; 361 362 JsLoadingOverlay.show(); 363 let resultMap = await sendHttp.send(); 364 JsLoadingOverlay.hide(); 365 366 if (resultMap != null) { 367 // 리ì¤í¸ 368 let list = resultMap.list; 369 let listContainer = document.querySelector("#termsList"); 370 371 // document.querySelector('.total-count').innerText = numberWithCommas(list.length); 372 373 listContainer.innerHTML = ""; 374 if (list.length == 0) { 375 listContainer.innerHTML = ` 376 <div class="my-6 text-center text-gray-400 fs-base min-h-300px d-flex align-items-center justify-content-center">ë±ë¡ë ì½ê´ ë° ì ì± ì´ ììµëë¤.</div> 377 `; 378 } else { 379 listContainer.classList.remove("d-none"); 380 list.forEach((item) => { 381 let listEl = document.createElement("div"); 382 listEl.classList.add("list-group-item", "list-group-item-action", "w-auto", "d-flex", "justify-content-between", "align-items-center", "rounded-4", "border-0", "cursor-pointer", "mx-n3"); 383 listEl.dataset.id = item.id; 384 385 listEl.innerHTML = ` 386 <div class="d-flex flex-column py-2"> 387 <div class="fs-base fw-semibold">${item.title ?? "-"}</div> 388 </div> 389 `; 390 391 listEl.addEventListener("click", async (e) => { 392 e.preventDefault(); 393 e.stopImmediatePropagation(); 394 395 postDetail(e.currentTarget.dataset.id); 396 }); 397 398 listContainer.append(listEl); 399 }); 400 } 401 } 402} 403 404// 1:1문ì ì¡°í 405async function getQnaList(page, search, lang) { 406 let sendHttp = new SendHttp("/qna/listJson"); 407 sendHttp.data = { 408 page: page ?? 1, 409 search: search ?? "", 410 lang: lang ?? "ko", 411 allItem: "1", 412 }; 413 414 JsLoadingOverlay.setOptions({ containerID: "qnaListSection", overlayOpacity: 0.0 }); 415 JsLoadingOverlay.show(); 416 let resultMap = await sendHttp.send(); 417 JsLoadingOverlay.hide(); 418 419 if (resultMap != null) { 420 // 리ì¤í¸ 421 let list = resultMap.list; 422 let listContainer = document.querySelector("#qnaList"); 423 424 // document.querySelector('.total-count').innerText = numberWithCommas(list.length); 425 426 listContainer.innerHTML = ""; 427 if (list.length == 0) { 428 listContainer.innerHTML = ` 429 <div class="my-6 text-center text-gray-400 fs-base min-h-300px d-flex align-items-center justify-content-center">ë±ë¡ë 문ìê° ììµëë¤.</div> 430 `; 431 } else { 432 listContainer.classList.remove("d-none"); 433 list.forEach((item) => { 434 let listEl = document.createElement("div"); 435 listEl.classList.add("list-group-item", "list-group-item-action", "w-auto", "d-flex", "justify-content-between", "align-items-center", "rounded-4", "border-0", "cursor-pointer", "mx-n3"); 436 listEl.dataset.id = item.id; 437 438 const badge = qnaStatusBadge(item.status, "sm"); 439 440 listEl.innerHTML = ` 441 <div id="qnaListItem" class="d-flex flex-column py-2"> 442 <div>${badge}</div> 443 <div class="fs-base fw-semibold mt-1 line-clamp-1 ignore-line-break">${item.contents ?? "-"}</div> 444 <div class="fs-7 text-gray-600">${formatDateTime(item.created, "dayTimeMin")}</div> 445 </div> 446 `; 447 448 listEl.addEventListener("click", async (e) => { 449 e.preventDefault(); 450 e.stopImmediatePropagation(); 451 452 const id = e.currentTarget.dataset.id;
453 location.href = `/qna/detail?id=${id}`; 454 }); 455 456 listContainer.append(listEl); 457 }); 458 } 459 } 460} 461 462async function postDetail(id) { 463 let sendHttp = new SendHttp("/post/get"); 464 sendHttp.data = { 465 id: id, 466 }; 467 468 JsLoadingOverlay.show(); 469 let resultMap = await sendHttp.send(); 470 JsLoadingOverlay.hide(); 471 472 if (resultMap != null) { 473 let modal = new DynamicModal(); 474 modal.setTitle(resultMap.item.title); 475 modal.setOptions({ scrollBody: true }); // ë³¸ë¬¸ì´ ê¸¸ë©´ ëª¨ë¬ ë´ë¶ìì ì¤í¬ë¡¤ 476 modal.removeConfirmButton(); 477 modal.setCancelButton("ë«ê¸°"); 478 479 let imageList = ""; 480 let filePath = resultMap.filePath; 481 if (resultMap.item.fileList != null && resultMap.item.fileList.length > 0) { 482 resultMap.item.fileList.forEach((file) => { 483 imageList += ` 484 <div class="text-center mb-3 mx-n6"> 485 <img src="${filePath}/${file.name}" class="img-fluid" onerror="this.src='/assets/images/image-error.png'"> 486 </div> 487 `; 488 }); 489 } 490 491 // ì½ê´ ê°ì ì´ë ¥ ì¹ì (BE ìì ì½ê´ì¼ ëë§ ëë´) 492 let historyList = resultMap.historyList || []; 493 let historyHtml = ''; 494 if (historyList.length > 0) { 495 let rows = historyList.map((h) => ` 496 <div> 497 <a href="javascript:void(0)" class="term-history-item text-decoration-underline fs-7 text-gray-600" data-history-id="${h.id}"> 498 ${i18n.t('terms.history.title')} v${h.version} ${h.title} : ${formatDateTime(h.created, "yyyy. MM. dd")} 499 </a> 500 </div> 501 `).join(''); 502 503 historyHtml = ` 504 <div class="mt-5 pt-3 border-top">${rows}</div> 505 `; 506 } 507 508 modal.setContents(` 509 ${imageList} 510 <div class="fs-base contents">${resultMap.item.contents}</div> 511 ${historyHtml} 512 `); 513 514 // ê°ì ì´ë ¥ í í´ë¦ â í´ë¹ ë²ì 본문ì ì¤í 모ë¬ë¡ íì 515 if (historyList.length > 0) { 516 let baseTitle = resultMap.item.title; 517 modal.container.addEventListener('click', (e) => { 518 let btn = e.target.closest('.term-history-item'); 519 if (!btn) return; 520 let historyId = parseInt(btn.dataset.historyId); 521 let history = historyList.find((h) => h.id === historyId); 522 if (!history) return; 523 524 let stackedModal = new DynamicModal(`${baseTitle} (v${history.version})`, ''); 525 stackedModal.setOptions({ isStack: true }); 526 stackedModal.container.querySelector('.modal-dialog').classList.add('modal-dialog-scrollable'); 527 stackedModal.removeConfirmButton(); 528 stackedModal.setCancelButton("ë«ê¸°"); 529 stackedModal.setContents(` 530 <div class="w-100"> 531 <div style="white-space: pre-line">${(history.contents || '').trim()}</div> 532 </div> 533 `); 534 stackedModal.show(); 535 }); 536 } 537 538 modal.show(); 539 } 540} 541 542// ê³µì§ì¬í ìì¸ë³´ê¸° 543async function postNoticeDetail() { 544 // íì¬ íì´ì§ì URLìì 쿼리 문ìì´ ê°ì ¸ì¤ê¸° 545 const params = new URLSearchParams(window.location.search); 546 const id = params.get("id"); 547 548 let sendHttp = new SendHttp("/post/get"); 549 sendHttp.data = { 550 id: id, 551 }; 552 553 let noticeDetailSection = document.querySelector("#noticeDetailSection .content-section"); 554 let noticeDetailCard = document.getElementById("noticeDetailSection").closest(".card-body"); 555 noticeDetailCard.id = "noticeDetailCard"; 556 557 JsLoadingOverlay.show({ containerID: "noticeDetailCard", overlayOpacity: 0.0 }); 558 let resultMap = await sendHttp.send(); 559 JsLoadingOverlay.hide(); 560 561 if (resultMap != null) { 562 let imageList = ""; 563 let filePath = resultMap.filePath; 564 565 if (resultMap.item.fileList != null && resultMap.item.fileList.length > 0) { 566 resultMap.item.fileList.forEach((file) => { 567 imageList += ` 568 <div class="text-center mt-6 mx-n6"> 569 <img src="${filePath}/${file.name}" class="img-fluid" onerror="this.src='/assets/images/image-error.png'"> 570 </div> 571 `; 572 }); 573 } 574 575 const noticeDetails = ` 576 <h3 id="detailTitle" class="mb-0 fw-semibold">${resultMap.item.title}</h3> 577 <div class="mt-2 d-flex align-items-center">
578 <span class="text-gray-600 fs-base">${formatDateTime(resultMap.item.created, "dayTimeMin")}</span> 579 </div> 580 ${imageList} 581 <div class="mt-6 fs-base contents">${convertUrlToLink(resultMap.item.contents)}</div> 582 `; 583 584 noticeDetailSection.insertAdjacentHTML("afterbegin", noticeDetails); 585 } 586} 587 588// 1:1문ì ìì¸ë³´ê¸° 589async function getQnaDetail() { 590 // íì¬ íì´ì§ì URLìì 쿼리 문ìì´ ê°ì ¸ì¤ê¸° 591 const params = new URLSearchParams(window.location.search); 592 const id = params.get("id"); 593 594 let sendHttp = new SendHttp("/qna/get"); 595 sendHttp.data = { 596 id: id, 597 }; 598 599 let loaderContainer = document.getElementById("qnaDetailSection").closest(".card-body"); 600 loaderContainer.id = "qnaDetailCard"; 601 602 JsLoadingOverlay.show({ containerID: "qnaDetailCard", overlayOpacity: 0.0 }); 603 let resultMap = await sendHttp.send(); 604 JsLoadingOverlay.hide(); 605 606 if (resultMap == null) { 607 return; 608 } 609 610 const recentItem = resultMap.recentItem; // ìµì 문ì 611 const filePath = resultMap.filePath; 612 // BEë ìµì ì(DESC)ì¼ë¡ ë´ë ¤ì¤ â ëí íë¦ëë¡ ìê°ì(ASC)ì¼ë¡ ë³í 613 const list = (resultMap.list || []).slice().reverse(); 614 if (list.length === 0) { 615 return; 616 } 617 const origin = list[0]; // ì문 (ì²¨ë¶ ì ë³´ê° ì±ìì§ list í목) 618 619 const detailContainer = document.querySelector("#qnaDetailSection"); 620 621 // 문ì ì í(ì¤ë ë ê³µíµ) + íì¬ ìí ë±ì§ 622 detailContainer.querySelector("#detailInfo").classList.remove("d-none"); 623 detailContainer.querySelector("#detailStatus").textContent = getQnaTypeStr(origin.type); 624 document.getElementById("detailInfo").insertAdjacentHTML("afterbegin", qnaStatusBadge(origin.status, "xl")); 625 626 const thread = detailContainer.querySelector("#qnaReplyList"); 627 thread.innerHTML = ""; 628 629 // ââ ì문 문ì 본문 (ë°ì¤ ìì´ ìë¨) ââ 630 const originBody = document.createElement("div"); 631 originBody.classList.add("mt-4"); 632 const originContents = document.createElement("div"); 633 originContents.classList.add("contents"); 634 originContents.textContent = origin.contents; 635 originBody.append(originContents); 636 originBody.insertAdjacentHTML("beforeend", buildQnaImages(origin.askFileList, filePath)); 637 thread.append(originBody); 638 639 // ââ ëí ì¤ë ë (ì¬ë¬¸ì/ëµë³, bg-light ë°ì¤) ââ 640 const convo = document.createElement("div"); 641 convo.classList.add("d-flex", "flex-column", "gap-4", "mt-6"); 642 643 // ì¤ë ë ìµì ìíê° ëµë³ë기면 ìµì ë¼ì´ë ëµë³ì ì¨ê¹(ì´ì ë¼ì´ë ëµë³ì ì ì§). 644 // ì¬ë¬¸ìë¡ ì문 statusê° 0ì¼ë¡ 리ì ë ì ìì´, ìµì ë¼ì´ëë§ status 기ì¤ì¼ë¡ ê°ë¦°ë¤. 645 const threadAnswered = origin.status === "1"; // 1: ëµë³ìë£ 646 const lastIdx = list.length - 1; 647 // ì¤ì ë¡ ë ¸ì¶ë ëµë³ì´ íëë¼ë ìì ëë§ ìë´ ë¬¸êµ¬ íì 648 const hasVisibleAnswer = list.some((it, i) => it.answer && (threadAnswered || i !== lastIdx)); 649 if (hasVisibleAnswer) { 650 convo.insertAdjacentHTML("beforeend", `<h3 class="fw-semibold mt-8 mb-1">문ìì ëí ëµë³ì ëë¤</h3>`); 651 } 652 653 list.forEach((item, idx) => { 654 const isReinquiry = idx > 0; // ì문 ì§ë¬¸ì ìì ì´ë¯¸ íì 655 const isLatest = idx === list.length - 1; 656 657 // ì¬ë¬¸ì ì§ë¬¸ ë©ìì§ 658 if (isReinquiry) { 659 const q = document.createElement("div"); 660 // ì¬ì©ì(ì¬ë¬¸ì) ë©ìì§ë 배경·í¨ë© ìì´ í문 + ms-6 ë¤ì¬ì°ê¸° (ë°ë¡ìë¤ ëµë³ë§ ë°ì¤) 661 q.classList.add("ms-6"); 662 q.innerHTML = ` 663 <div class="d-flex align-items-center gap-2"> 664 <span class="fw-semibold">${item.fullName ?? "-"}</span> 665 <span class="text-gray-500 fs-8">${formatDateTime(item.created, "dayTimeMin")}</span> 666 </div> 667 `; 668 const qc = document.createElement("div"); 669 qc.classList.add("mt-2", "contents"); 670 qc.textContent = item.contents; 671 q.append(qc); 672 q.insertAdjacentHTML("beforeend", buildQnaThumbnails(item.askFileList, filePath)); 673 convo.append(q); 674 } 675 676 // ìµì ë¼ì´ëê° ëµë³ë기면 ê·¸ ë¼ì´ë ëµë³ì ì¨ê¸°ê³ , ëµë³ìë£ë ë¼ì´ëë§ ë ¸ì¶ 677 const isPendingLatest = isLatest && !threadAnswered; 678 if (item.answer && !isPendingLatest) { 679 const a = document.createElement("div"); 680 a.classList.add("bg-light", "rounded-4", "p-4"); 681 a.innerHTML = ` 682 <div class="d-flex align-items-center gap-2"> 683 <div class="symbol symbol-25px"> 684 <img src="/assets/images/app-icon.png" alt="ë°ë¡ìë¤" /> 685 </div>
686 <span class="fw-semibold">ë°ë¡ìë¤</span> 687 <span class="text-gray-500 fs-8">${formatDateTime(item.answerd, "dayTimeMin")}</span> 688 </div> 689 `; 690 const ac = document.createElement("div"); 691 ac.classList.add("mt-2", "contents"); 692 ac.innerHTML = convertUrlToLink(item.answer ?? ""); 693 a.append(ac); 694 a.insertAdjacentHTML("beforeend", buildQnaThumbnails(item.answerFileList, filePath)); 695 convo.append(a); 696 } else if (isPendingLatest) { 697 // ìµì 문ìê° ëµë³ë기면 ìë´ ë¬¸êµ¬ 698 convo.insertAdjacentHTML( 699 "beforeend", 700 ` 701 <div class="fs-8 text-gray-600 mt-5"> 702 <p class="mb-0">ì 무ìê° ë´ ìì°¨ì ì¼ë¡ ëµë³ëë ¤ì. 1~3ì¼ ì ë ê±¸ë ¤ì</p> 703 </div> 704 ` 705 ); 706 } 707 }); 708 709 thread.append(convo); 710 711 // ì¬ë¬¸ì ë²í¼: ì¤ë ë ìµì ìíê° ëµë³ìë£ì¼ ëë§ ë ¸ì¶ (BE ê°ëì ëì¼) 712 if (recentItem && threadAnswered) { 713 const retryBtn = document.getElementById("retryQnaBtn");
714 retryBtn.querySelector("a").href = `/qna/add?parentId=${origin.id}&type=${origin.type}`; 715 retryBtn.classList.remove("d-none"); 716 } 717 718 window.refreshFsLightbox(); 719} 720 721// 문ì/ëµë³ ì²¨ë¶ ì´ë¯¸ì§ HTML ìì± (ì문 ë³¸ë¬¸ì© â íí íì, fslightbox 그룹ì íì¼ë³) 722function buildQnaImages(fileList, filePath) { 723 if (fileList == null || fileList.length === 0) { 724 return ""; 725 } 726 727 return fileList 728 .map( 729 (file) => ` 730 <div class="text-center mt-6 mx-n6"> 731 <a href="${filePath}/${file.name}" data-fslightbox="image_${file.name}"> 732 <img src="${filePath}/${file.name}" class="img-fluid" onerror="this.src='/assets/images/image-error.png'"> 733 </a> 734 </div> 735 ` 736 ) 737 .join(""); 738} 739 740// ëí ë°ì¤ ì ì²¨ë¶ ì´ë¯¸ì§ (ì¸ë¤ì¼ â ë°ì¤ íì ë§ê²) 741function buildQnaThumbnails(fileList, filePath) { 742 if (fileList == null || fileList.length === 0) { 743 return ""; 744 } 745 746 return ( 747 `<div class="d-flex gap-2 flex-wrap mt-3">` + 748 fileList 749 .map( 750 (file) => ` 751 <a href="${filePath}/${file.name}" data-fslightbox="image_${file.name}"> 752 <img class="thumbnail thumbnail-lg rounded-4" src="${filePath}/${file.name}" onerror="this.src='/assets/images/image-error.png'"> 753 </a> 754 ` 755 ) 756 .join("") + 757 `</div>` 758 ); 759} 760 761async function onSubmitQna(form) { 762 // let titleInput = form.querySelector("input[name=title]"); 763 let contentsInput = form.querySelector("textarea[name=contents]"); 764 765 // if (!(await validateSingleField(titleInput))) { 766 // titleInput.focus(); 767 // return; 768 // } 769 770 if (!(await validateSingleField(contentsInput))) { 771 contentsInput.focus(); 772 return; 773 } 774 775 // ì ì¶ ì ìë¬ ì²ë¦¬: ì¼ì¼ íë ì´ê³¼(W2158)ë ëª¨ë¬ ìë´, ê·¸ ì¸ë 기존 ì²ë¦¬ 776 await submit(form, { 777 onError: (data) => { 778 if (data.code === 'W2158') { 779 showQnaLimitModal(data.data?.limitCount); 780 return; 781 } 782 errorHandling(data.code, data.message); 783 }, 784 }); 785} 786 787async function idVerify() { 788 let phoneInput = document.querySelector("input[name=phone_number]"); 789 790 if (!(await validateSingleField(phoneInput))) { 791 return; 792 } 793 794 // ì íë²í¸ ì¤ë³µ íì¸ 795 let chkUrl = "/validDuplicatePhone"; 796 let sendHttp = new SendHttp(chkUrl); 797 sendHttp.data = { 798 phone: phoneInput.value, 799 role: 1, 800 }; 801 802 JsLoadingOverlay.show(); 803 let resultMap = await sendHttp.send(); 804 JsLoadingOverlay.hide(); 805 806 if (resultMap.code != RESULT_CODE_AVAILABLE) { 807 errorHandling(resultMap.code) 808 return false; 809 } 810 811 let popup = window.open(`/requestIdVerify?phone=${phoneInput.value}`, "_blank", "width=430,height=640,scrollbars=yes"); 812 idVerifyRequested = true; 813} 814 815async function onCompleteIdVerify(resultMap) { 816 let phoneInput = document.querySelector("input[name=phone_number]"); 817 let isVerified = true; // for test 818 // let isVerified = resultMap.phone == phoneInput.value.replaceAll('-', ''); 819 820 if (isVerified) { 821 toastr.success("본ì¸ì¸ì¦ì´ ìë£ëììµëë¤."); 822 document.querySelector(".phone-message").innerHTML = '<span class="text-success fs-8">본ì¸ì¸ì¦ì´ ìë£ëììµëë¤.</span>'; 823 let form = document.querySelector("form[name=user_edit]"); 824 form.querySelector("input[name=phone]")?.remove(); 825 form.insertAdjacentHTML("beforeend", `<input type="hidden" name="phone" value="${escapeHtml(phoneInput.value)}">`); 826 if (resultMap.telecom) { 827 form.querySelector("input[name=telecomProvider]")?.remove(); 828 form.insertAdjacentHTML("beforeend", `<input type="hidden" name="telecomProvider" value="${escapeHtml(resultMap.telecom)}">`); 829 } 830 window.idVerifyResult = true; 831 } else { 832 toastr.error("ì ë ¥íì ì íë²í¸ì 본ì¸ì¸ì¦ ì ì ë ¥í ì íë²í¸ê° ì¼ì¹íì§ ììµëë¤."); 833 phoneInput.focus(); 834 return false;
835 } 836} 837 838window.addEventListener("message", (event) => { 839 // ë³´ì ê²ì¦: ë©ìì§ë¥¼ ë³´ë¸ ëë©ì¸ì´ ì¼ì¹íëì§ íì¸ 840 // if (event.origin !== "https://popup-domain.com") return; 841 842 // ë°ì ë°ì´í° ì²ë¦¬ 843 const data = event.data; 844 onCompleteIdVerify(data); 845}); 846 847// ì¸ì¦ ê²°ê³¼íë©´ì´ opener ìì´(ì í ë³µê· ë±) ì´ë ¤ postMessageê° ë¶ê°ë¥í ë localStorageë¡ ë¨ê¸´ ê²°ê³¼ ìì 848const ID_VERIFY_RESULT_KEY = "idVerifyResult"; 849let idVerifyRequested = false; 850 851function consumeIdVerifyResult() { 852 if (!idVerifyRequested) { 853 return; // ì´ íë©´ìì 본ì¸ì¸ì¦ì ììí ì ìì¼ë©´ 무ì (ë¤ë¥¸ íë©´ì ìì¬ ê²°ê³¼ ì¤ì¸ ë°©ì§) 854 } 855 856 let raw = localStorage.getItem(ID_VERIFY_RESULT_KEY); 857 if (raw == null) { 858 return; 859 } 860 localStorage.removeItem(ID_VERIFY_RESULT_KEY); // ì¤ë³µ ì²ë¦¬ ë°©ì§ë¥¼ ìí´ ì½ë ì¦ì ì ê±° 861 862 try { 863 let stored = JSON.parse(raw); 864 let data = stored?.data; 865 866 // 5ë¶ ì´ë´ ê²°ê³¼ë§ ì í¨ ì²ë¦¬ 867 if (Date.now() - stored.time < 5 * 60 * 1000 && data != null) { 868 onCompleteIdVerify(data); 869 } 870 } catch (e) { 871 // íì± ë¶ê°í ê²°ê³¼ë 무ì 872 } 873} 874 875window.addEventListener("storage", (event) => { 876 if (event.key === ID_VERIFY_RESULT_KEY) { 877 consumeIdVerifyResult(); 878 } 879}); 880 881// 백그ë¼ì´ë íìë storage ì´ë²¤í¸ê° ì§ì°/ëë½ë ì ìì´(Safari ë±) í ë³µê· ììë íì¸ 882document.addEventListener("visibilitychange", () => { 883 if (!document.hidden) { 884 consumeIdVerifyResult(); 885 } 886}); 887 888// ë¹ë°ë²í¸ ë³ê²½ 889async function updatePassword(form) { 890 let currentPasswordInput = form.querySelector("input[name=password]"); 891 let passwordInput = form.querySelector("input[name=newPassword]"); 892 let passwordConfirmInput = form.querySelector("input[name=passwordConfirm]"); 893 894 if (validator == null || validator.form.name != form.name) { 895 validInit(form); 896 } 897 898 if (!(await validateSingleField(currentPasswordInput))) { 899 currentPasswordInput.focus(); 900 return; 901 } 902 903 if (!(await validateSingleField(passwordInput))) { 904 passwordInput.focus(); 905 return; 906 } 907 908 if (!(await validateSingleField(passwordConfirmInput))) { 909 passwordConfirmInput.focus(); 910 return; 911 } 912 913 if (passwordInput.value != passwordConfirmInput.value) { 914 toastr.error("ë¹ë°ë²í¸ê° ì¼ì¹íì§ ììµëë¤."); 915 passwordConfirmInput.focus(); 916 return; 917 } 918 919 submit(form, { 920 onComplete: (data) => { 921 if (data.code == RESULT_CODE_SUCCESS || data.code == 0) { 922 toastr.success(i18n.t('msg.updateSuccess')); 923 setTimeout(() => { 924 history.back(); 925 }, 1000); 926 } else { 927 errorHandling(data.code); 928 } 929 }, 930 }); 931}
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.