(() => {
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);
})();