(() => { const { pageHelper, EventManager, utils: { changeProfileFormVerifyMap, handleFocusEvent, getLocalStorage, setLocalStorage, removeLocalStorage }, } = ShopbySkin; const modifyMemberFormHelper = pageHelper.modifyMemberFormHelper(); const containerEl = document.querySelector( `[shopby-helper-key="modify-member-form"]` ); const profileExtraInformationEl = document.querySelector( "profile-extra-information" ); modifyMemberFormHelper.initialize({ helperKey: "modify-member-form", }); const initializeSubTerms = () => { const onSubTermsCheckbox = containerEl.querySelector('input[type="checkbox"][name="onSubTerms"]'); const directMailCheckbox = containerEl.querySelector('input[type="checkbox"][value="directMailAgreed"]'); const smsAgreedCheckbox = containerEl.querySelector('input[type="checkbox"][value="smsAgreed"]'); // DOM이 아직 없으면 다시 시도 if (!onSubTermsCheckbox) { setTimeout(initializeSubTerms, 50); return; } const { profileEmailInformation } = modifyMemberFormHelper.getState(); const { profileSmsInformation } = modifyMemberFormHelper.getState(); // 원본 값 저장 const subTerms = { ...(profileEmailInformation ?? {}), ...(profileSmsInformation ?? {}) }; setLocalStorage("ORIGINAL_SUB_TERMS", JSON.stringify(subTerms)); const { smsAgreed } = profileSmsInformation || {}; const { directMailAgreed } = profileEmailInformation || {}; // sms & email 수신 동의가 둘 다 true라면 전체 선택 박스 체크 됨. if (smsAgreed?.value && directMailAgreed?.value) { onSubTermsCheckbox.checked = true; } const customTerms = modifyMemberFormHelper.getState()?.termsInformation?.customTerms; const is157Term = customTerms.find(term => term.id === '157'); if(!is157Term.checked){ onSubTermsCheckbox.disabled = true; directMailCheckbox.disabled = true; smsAgreedCheckbox.disabled = true; } }; // shopby의 내장 동기화 함수가 값을 정상적으로 업데이트하지 않아, // 지금은 localStorage를 통해 직접 상태를 저장·불러오는 방식으로 동기화하고 있음. initializeSubTerms(); window.addEventListener('beforeunload', () => { removeLocalStorage("ORIGINAL_SUB_TERMS"); }); window.addEventListener("message", (event) => { if (!event.data || event.data.action !== "SELECT_SCHOOL") return; const { schoolName, schoolCode } = event.data.data; // 입력 필드에 값 바인딩 const schoolInputField = document.querySelector( '.school-input-box input[placeholder="ex) -고등학교, -학원 "]' ); const schoolCodeField = document.querySelector( ".school-input-box-code-field input" ); if (schoolInputField) { schoolInputField.value = schoolName; } if (schoolCodeField) { schoolCodeField.value = schoolCode; } // 헬퍼 상태 업데이트 const state = modifyMemberFormHelper.getState(); // 현재 상태 가져오기 const { profileExtraInformation } = state; if (profileExtraInformation?.extraInfoContents) { profileExtraInformation.extraInfoContents.forEach((info) => { if (info.extraInfoName === "소속학교(학원)") { info.extraInfoOptionTextContent = schoolName; // 소속학교 값 저장 setLocalStorage("SCHOOL_NAME", JSON.stringify(schoolName)); } else if (info.extraInfoName === "소속코드") { info.extraInfoOptionTextContent = schoolCode; // 소속코드 값 저장 setLocalStorage("SCHOOL_CODE", JSON.stringify(schoolCode)); } }); } }); const flattenRequest = (helper) => { const { profileBasicInformation, profileNicknameInformation, profileEmailInformation, profileSmsInformation, profileCertification, profileOptionalInformation, termsInformation, profileExtraInformation, } = helper.getState(); const selectedCustomTerms = termsInformation?.customTerms .filter(({ checked }) => !!checked) .map((term) => term.id); // 20250729 황성무 비밀번호 체크해서 비번변경모드 세팅 // password가 null, undefined, 공백 문자열이면 false 그 외 값이 있으면 true // --> !! 는 문자열이 존재하면 true, 없으면 false로 변환 profileBasicInformation.isPasswordEditMode = !!profileBasicInformation?.password?.value.trim(); if(!profileSmsInformation?.mobileNo?.value){ profileSmsInformation.mobileNo.value = profileExtraInformation?.profile?.mobileNo; } if(['@', ''].includes(profileEmailInformation?.email?.value)){ profileEmailInformation.email.value = profileExtraInformation?.profile?.email; } if(!['@', ''].includes(profileEmailInformation?.email?.value)){ profileEmailInformation.emailCertificationStatus = 'NONE'; } return { memberName: profileBasicInformation?.memberName, password: profileBasicInformation?.password, // 20250729 황성무 키값 변경 --> 아마 이건 샵바이에서 처음부터 잘못된 키값으르 개발한거 같다 passwordConfirm: profileBasicInformation?.passwordConfirm, isPasswordEditMode: profileBasicInformation?.isPasswordEditMode, ...profileEmailInformation, ...profileSmsInformation, ...profileCertification, ...profileOptionalInformation, extraInfo: profileExtraInformation?.extraInfoContents, nickname: profileNicknameInformation?.nickname, joinTermsAgreements: termsInformation?.terms, customTermsNos: selectedCustomTerms, }; }; // 비밀번호만 샵바이 기본 규칙과 다르게 적용 (영문/숫자/특수문자 모두 조합 8~20자), D.up과 통일 const PASSWORD_COMPOSITION_MESSAGE = "비밀번호는 영문, 숫자, 특수문자를 포함한 8~20자리로 입력해 주세요."; changeProfileFormVerifyMap.password = ({ value = "" }) => { const isLengthValid = value.length >= 8 && value.length <= 20; const isCompositionValid = /[a-zA-Z]/.test(value) && /[0-9]/.test(value) && /[^a-zA-Z0-9]/.test(value); const isValid = isLengthValid && isCompositionValid; return { isValid, message: isValid ? "" : PASSWORD_COMPOSITION_MESSAGE, }; }; const checkInvalidProfileForm = (request) => { // eslint-disable-next-line complexity const errors = Object.keys(changeProfileFormVerifyMap)?.map((key) => { if (!request[key]) { return { isValid: true, field: key }; } const value = request?.[key]?.value ?? ""; switch (key) { case "passwordConfirm": return { ...changeProfileFormVerifyMap?.[key]({ value, comparisonValue: request?.password?.value, }), field: key, }; case "nickname": return { ...changeProfileFormVerifyMap?.[key]({ value, isDuplicated: request?.nickname?.isDuplicate, isRequired: request?.nickname?.isRequired, }), field: key, }; case "email": return { ...changeProfileFormVerifyMap?.[key]({ value, isDuplicated: request?.email?.isDuplicate, isRequired: request?.email?.isRequired, }), field: key, }; case "mobileNo": case "telephoneNo": return { ...changeProfileFormVerifyMap?.[key]({ value, isRequired: request?.[key]?.isRequired, }), field: key, }; case "detailAddress": return { ...changeProfileFormVerifyMap?.[key]({ value, zipCode: request?.zipCd, isRequired: request?.detailAddress?.isRequired, }), field: key, }; case "birthday": case "sex": return { ...changeProfileFormVerifyMap?.[key]({ value, isRequired: request?.[key]?.isRequired, }), field: key, }; case "extraInfo": return { ...changeProfileFormVerifyMap?.[key](request.extraInfo), field: key, }; case "joinTermsAgreements": return { ...changeProfileFormVerifyMap?.[key](request.joinTermsAgreements), field: key, }; default: return { ...changeProfileFormVerifyMap?.[key]({ value, isRequired: request?.[key]?.isRequired, }), field: key, }; } }); const omittedErrors = errors.filter((error) => { if ( ["password", "passwordConfirm"].includes(error.field) && !request?.isPasswordEditMode ) { return false; } return !error.isValid; }); return omittedErrors; }; // eslint-disable-next-line complexity const checkCertificatedValidation = (request) => { const invalidEmail = request?.emailCertificationStatus === "INITIAL"; const invalidSmsInternalCertification = request?.smsCertificationStatus === "INITIAL"; const invalidSmsExternalAuthentication = request?.smsCertificationStatus === "SMS_AUTHENTICATION" && !request?.ci; if ( invalidEmail || invalidSmsInternalCertification || invalidSmsExternalAuthentication ) { EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "CAUTION", message: `${ invalidEmail ? "이메일 인증을 진행해 주세요." : "휴대폰 인증을 진행해 주세요." }`, onClose: () => { handleFocusEvent({ containerEl, fields: invalidEmail ? "email" : "mobileNo", }); }, }); return false; } const message = request.certificatedNumber?.length ? "인증을 진행해주세요." : "인증번호를 입력해주세요."; if ( request.certificated && (!request.certificated.value || !request.certificated.isValid) ) { EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "CAUTION", message: `${request.certificated.message ?? message}`, onClose: () => { handleFocusEvent({ containerEl, fields: "certificatedNumber" }); }, }); return false; } return true; }; const checkPasswordAuthentication = (helper) => { const { helperState, profileInformation: { openIdProvider }, } = helper.getState(); const { isAuthenticated } = helperState ?? {}; const isInValidOpenIdAuthentication = openIdProvider && !isAuthenticated; if (isInValidOpenIdAuthentication) { EventManager.fire("MODAL_ALERT_OPEN", { message: "계정 재인증 후 회원정보 수정이 가능합니다.", noticeType: "CAUTION", }); return false; } return true; }; const CLICK_EVENT_HANDLER_MAP = { // eslint-disable-next-line complexity EMAIL_CERTIFICATION: async (helper) => { const { profileEmailInformation } = helper.getState(); const isInvalidEmail = profileEmailInformation?.email.value === "@" || !profileEmailInformation?.email.isValid; if (isInvalidEmail) { EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "CAUTION", message: `${ profileEmailInformation?.email.message ?? "이메일을 입력해주세요." }`, }); return; } if (profileEmailInformation?.emailCertificationStatus === "INITIAL") { await helper.sendCertificationCode( profileEmailInformation.email.value, "EMAIL" ); EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "SUCCESS", message: "인증번호가 발송되었습니다.", }); } else { EventManager.fire("MODAL_CONFIRM_OPEN", { noticeType: "WARNING", message: "인증번호를 재발송하시겠습니까?", onConfirm: async () => { await helper.sendCertificationCode( profileEmailInformation.email.value, "EMAIL" ); EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "SUCCESS", message: "인증번호가 발송되었습니다.", }); }, }); } }, // eslint-disable-next-line complexity SMS_CERTIFICATION: async (helper) => { const { profileSmsInformation } = helper.getState(); const isInvalidMobileNo = !profileSmsInformation?.mobileNo.value || !profileSmsInformation?.mobileNo.isValid; if (isInvalidMobileNo) { EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "CAUTION", message: `${ profileSmsInformation?.mobileNo.message ?? "휴대폰 번호를 입력해주세요." }`, }); return; } if (profileSmsInformation?.smsCertificationStatus === "INITIAL") { await helper.sendCertificationCode( profileSmsInformation.mobileNo.value, "SMS" ); EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "SUCCESS", message: "인증번호가 발송되었습니다.", }); } else { EventManager.fire("MODAL_CONFIRM_OPEN", { noticeType: "WARNING", message: "인증번호를 재발송하시겠습니까?", onConfirm: async () => { await helper.sendCertificationCode( profileSmsInformation.mobileNo.value, "SMS" ); EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "SUCCESS", message: "인증번호가 발송되었습니다.", }); }, }); } }, AUTHENTICATION_BY_PHONE: async (helper) => { const { profileBasicInformation, profileOptionalInformation } = helper.getState(); const genderInfo = { M: "01", F: "02", }; EventManager.fire("OPEN_LAYER_MODAL", { name: "kcp-sms-authentication", data: { type: "JOIN_TIME" }, onClose: ({ reason, state }) => { if (reason === "DID_SUBMIT") { // 현재 사용자의 정보와 인증 결과의 정보가 동일한지 확인 const isValid = state.name === profileBasicInformation.memberName.value && genderInfo[profileOptionalInformation.sex.value] === state.sexCode && state.birthday === profileOptionalInformation.birthday.value.replace( /[^\d//.]+/g, "" ); if(!profileOptionalInformation.sex.value || !profileOptionalInformation.birthday.value) { // 사용자 정보에 생년월일/성별이 없을 때 ShopbySkin.EventManager.fire("SUCCESS_AUTHENTICATION_SMS", state); return; } else if (!isValid) { // 사용자 정보와 인증 결과 정보가 다를 시 EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "CAUTION", message: "본인 명의가 아닌 번호로는 변경할 수 없습니다. \ 개명이나 주민등록 변경 등으로 정보가 변경된 경우 \ 1:1 문의로 개인정보 변경을 요청해 주세요.", }); } else { ShopbySkin.EventManager.fire("SUCCESS_AUTHENTICATION_SMS", state); return; } } ShopbySkin.EventManager.fire("SUCCESS_CERTIFICATION_SMS"); }, }); }, SEARCH_ZIP_CODE: () => { EventManager.fire("OPEN_LAYER_MODAL", { isFull: false, modalAddClass: "search-zip-code", name: "page-zip-code", onClose: ({ reason, state }) => { if (reason === "DID_SUBMIT") { ShopbySkin.EventManager.fire("SELECT_ZIP_CODE", { moduleKey: "profile-optional-information", state, }); } }, }); }, SHOW_TERM_DETAIL: ({ elTarget, helper }) => { const { termsInformation } = helper.getState(); if (!termsInformation) { return; } const mergedTerms = [ ...termsInformation.terms, ...termsInformation.customTerms, ]; const selectedTerm = mergedTerms.find( (term) => elTarget.getAttribute("shopby-term-id") === term.id.toString() ); EventManager.fire("OPEN_LAYER_MODAL", { name: "term-detail", data: selectedTerm, }); }, SEARH_CLASS_MODAL: () => { EventManager.fire("OPEN_LAYER_MODAL", { isFull: false, name: "search-class-modal", onClose: ({ reason, state }) => { console.log("TEST", reason, state); }, }); }, MODIFY: async (helper) => { await profileExtraInformationEl?.refetchConfigMemberExtraInfo(); const flattedRequest = flattenRequest(helper); flattedRequest.extraInfo.forEach((item) => { if (item.extraInfoName === "소속코드") { item.extraInfoOptionTextContent = JSON.parse( getLocalStorage("SCHOOL_CODE") ); } else if (item.extraInfoName === "소속학교(학원)") { item.extraInfoOptionTextContent = JSON.parse( getLocalStorage("SCHOOL_NAME") ); } }); const subTerms = getSubTerms(); const is157Term = flattedRequest?.customTermsNos?.find(term => term === '157'); const subTermsState = !subTerms?.smsAgreed?.value && !subTerms?.directMailAgreed?.value; if (is157Term && subTermsState) { return EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "CAUTION", message : "수신 방법을 최소 1개 이상 선택해 주세요.", }); } flattedRequest.smsAgreed.value = subTerms.smsAgreed.value; flattedRequest.directMailAgreed.value = subTerms.directMailAgreed.value; const invalidRequest = checkInvalidProfileForm(flattedRequest); if (invalidRequest?.length) { const [error] = invalidRequest; EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "CAUTION", message: `${error.message}`, onClose: () => { handleFocusEvent({ containerEl, fields: error.field }); EventManager.fire("INVALID_PROFILE_FORM", { data: invalidRequest, }); }, }); return; } if (!checkCertificatedValidation(flattedRequest)) { return; } if (!checkPasswordAuthentication(helper)) { return; } await helper.modify({ ...flattedRequest }); EventManager.fire("MODAL_ALERT_OPEN", { noticeType: "SUCCESS", message: "회원정보가 수정되었습니다.", onClose: () => location.replace(`${location.origin}/pages/my/my-page.html`), }); }, CANCEL_MODIFY: () => { location.replace("/pages/my/my-page.html"); }, HANDLE_DELETE_IMAGE_BTN_CLICK: (_, event) => { event.preventDefault(); EventManager.fire("MODAL_CONFIRM_OPEN", { noticeType: "WARNING", message: "첨부파일을 삭제하시겠습니까?", onConfirm: () => { const extraInfoNo = event.target .closest("[shopby-extra-info-no]") .getAttribute("shopby-extra-info-no"); profileExtraInformationEl.deleteImage(extraInfoNo); }, }); }, }; const getSubTerms = () => { const subTerms = getLocalStorage('ORIGINAL_SUB_TERMS'); return subTerms ? JSON.parse(subTerms) : {}; } const setSubTerms = (subTerms) => { setLocalStorage( "ORIGINAL_SUB_TERMS", JSON.stringify(subTerms)); }; const getCheckboxes = () => ({ sms: containerEl.querySelector('input[type="checkbox"][value="smsAgreed"]'), email: containerEl.querySelector('input[type="checkbox"][value="directMailAgreed"]'), onSubTerms: containerEl.querySelector('input[type="checkbox"][value="onSubTerms"]') }); const updateCheckboxStateByTerms = (subTerms) => { const { sms, email, onSubTerms } = getCheckboxes(); sms.checked = subTerms.smsAgreed.value; email.checked = subTerms.directMailAgreed.value; onSubTerms.checked = sms.checked && email.checked; }; const updateDisabledBy157Term = (terms) => { const { sms, email, onSubTerms } = getCheckboxes(); const customTerms = modifyMemberFormHelper.getState()?.termsInformation?.customTerms || []; const term157 = customTerms.find(term => term.id === '157'); const shouldDisable = !term157?.checked; sms.disabled = shouldDisable; email.disabled = shouldDisable; onSubTerms.disabled = shouldDisable; }; const toggleSubTerm = (termId, checked) => { const subTerms = getSubTerms(); if (termId === "onSubTerms"){ subTerms.directMailAgreed.value = checked; subTerms.smsAgreed.value = checked; } if (["smsAgreed", "directMailAgreed"].includes(termId)) { subTerms[termId].value = checked; } setSubTerms(subTerms); updateCheckboxStateByTerms(subTerms); }; const toggleCustomTerm = (termId, checked) => { const subTerms = getSubTerms(); if (termId === "157" && !checked) { // 광고성 정보 수신 동의 subTerms.directMailAgreed.value = checked; subTerms.smsAgreed.value = checked; } updateCheckboxStateByTerms(subTerms); updateDisabledBy157Term(subTerms); setSubTerms(subTerms); } const clickEventListener = (event) => { const { target } = event; const { type, value: termId, checked } = target; const action = target.getAttribute("shopby-action"); const customTerms = modifyMemberFormHelper.getState()?.termsInformation?.customTerms || []; const isCustomTerm = customTerms.find(term => term.id === termId); if (type === "checkbox") { if(isCustomTerm) { toggleCustomTerm(termId, checked); return; } toggleSubTerm(termId, checked); } if (action === "SHOW_TERM_DETAIL") { CLICK_EVENT_HANDLER_MAP[action]?.({ helper: modifyMemberFormHelper, elTarget: target, }); } else { CLICK_EVENT_HANDLER_MAP[action]?.(modifyMemberFormHelper, event); } }; containerEl.addEventListener("click", clickEventListener); })();