(() => {
const {
pageHelper,
EventManager,
constants,
utils: { changeProfileFormVerifyMap, handleFocusEvent, moveTo },
} = ShopbySkin;
const modifyMemberFormHelper = pageHelper.modifyMemberFormHelper();
const passwordAuthenticationLayerModalHelper = pageHelper.passwordAuthenticationLayerModalHelper();
const containerEl = document.querySelector(`[shopby-helper-key="modify-member-form"]`);
const profileExtraInformationEl = document.querySelector('profile-extra-information');
const termsInformationModule = document.querySelector('terms-information');
modifyMemberFormHelper.initialize({
helperKey: 'modify-member-form',
profileNonMasking: true,
});
EventManager.on('PROCESS_AUTHENTICATION', ({ status }) => {
if (status === 'success') {
const modifyMember = document.querySelector('.member-modification');
modifyMember?.classList.remove('unauthentication');
}
const buttonEl = document.querySelector("[shopby-btn='authentication']");
if (!buttonEl) return;
if (status === 'pending') {
buttonEl.disabled = true;
}
if (status === 'finish') {
buttonEl.disabled = false;
}
});
const extractTermsAgreements = (termsInformation) => {
// 광고성 수신 동의 항목은 subTerms 내부에 있는 필드를 사용하기 때문에 joinTermsAgreements 필드에 사용할 동의 항목 리스트에서는 제거
const filteredMarketingTerms =
termsInformation?.marketingTerms?.filter(({ termsType }) => termsType !== constants.MARKETING_RECEIVE) || [];
return [...(termsInformation?.terms || []), ...filteredMarketingTerms];
};
const flattenRequest = (helper) => {
const {
profileBasicInformation,
profileNicknameInformation,
profileEmailInformation,
profileSmsInformation,
profileCertification,
profileOptionalInformation,
termsInformation,
profileExtraInformation,
checkMyAuthentication,
} = helper.getState();
const { directMailAgreed, smsAgreed } = (
termsInformation.marketingTerms?.find(({ termsType }) => termsType === constants.MARKETING_RECEIVE)?.subTerms ||
[]
).reduce(
(acc, term) => {
acc[term.id] = { value: term.checked ?? false };
return acc;
},
{ directMailAgreed: {}, smsAgreed: {} }
);
const joinTermsAgreements = extractTermsAgreements(termsInformation);
return {
memberName: profileBasicInformation?.memberName,
password: profileBasicInformation?.password,
profileConfirm: profileBasicInformation?.passwordConfirm,
isPasswordEditMode: profileBasicInformation?.isPasswordEditMode,
...profileEmailInformation,
...profileSmsInformation,
...profileCertification,
...profileOptionalInformation,
extraInfo: profileExtraInformation?.extraInfoContents,
nickname: profileNicknameInformation?.nickname,
joinTermsAgreements,
customTerms: termsInformation?.customTerms,
currentPassword: !checkMyAuthentication?.openIdProvider ? checkMyAuthentication.currentPassword : null,
directMailAgreed,
smsAgreed,
};
};
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': {
// 광고성 수신 동의 항목 중 동의 된 항목이 있을 경우 + 마케팅 목적의 수신동의가 없을 경우
const isMarketingReceiveAgreed = [request.smsAgreed, request.directMailAgreed]
.map(({ value }) => value)
.some((agreed) => agreed);
const isMarketingInfoUsageAgreed = request.joinTermsAgreements.find(
({ termsType }) => termsType === constants.MARKETING_INFO_USAGE
)?.checked;
if (
typeof isMarketingInfoUsageAgreed === 'boolean' &&
isMarketingReceiveAgreed &&
!isMarketingInfoUsageAgreed
) {
return {
isValid: false,
message: '이메일 및 SMS 수신을 위해 마케팅 목적의 개인정보 수집·이용에 동의해 주세요.',
};
}
return { ...changeProfileFormVerifyMap?.[key](request.joinTermsAgreements), field: key };
}
case 'customTerms':
return { ...changeProfileFormVerifyMap?.[key](request.customTerms), 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 },
checkMyAuthentication,
} = helper.getState();
const { isAuthenticated } = helperState ?? {};
const { isAuthenticated: openIdAuthenticated } = checkMyAuthentication ?? {};
const isInValidOpenIdAuthentication = openIdProvider && !(isAuthenticated || openIdAuthenticated);
if (isInValidOpenIdAuthentication) {
EventManager.fire('MODAL_ALERT_OPEN', {
message: '계정 재인증 후 회원정보 수정이 가능합니다.',
noticeType: 'CAUTION',
});
return false;
}
return true;
};
/* 마케팅 약관 체크 이벤트 핸들러 */
/**
* 하위 약관 체크 처리 (이메일/SMS 수신 동의 시)
* - 하위 약관을 체크하면 해당 부모 약관과 다른 모든 마케팅 약관도 체크
*/
const handleCheckSubTerm = (marketingTerms, parentTermType, targetId, checked) =>
marketingTerms.map((term) => {
const isParentTerm = term.termsType === parentTermType;
if (isParentTerm) {
return {
...term,
checked,
subTerms: term.subTerms?.map((subTerm) => (subTerm.id === targetId ? { ...subTerm, checked } : subTerm)),
};
}
// 하위 약관 체크 시 모든 마케팅 약관 체크
return { ...term, checked };
});
/**
* 하위 약관 체크 해제 처리
* - 이메일 수신 동의(directMailAgreed) 해제: 부모 약관만 해제
* - 기타 약관 해제 + 다른 하위 약관이 모두 체크된 경우: 해당 약관만 해제
* - 기타 약관 해제 + 다른 하위 약관이 체크 안된 경우: 모든 마케팅 약관 해제
*/
const handleUncheckSubTerm = (marketingTerms, parentTermType, targetId, checked) => {
const parentTerm = marketingTerms.find(({ termsType }) => termsType === parentTermType);
const subTerms = parentTerm?.subTerms;
if (!subTerms) {
return marketingTerms;
}
// 다른 하위 약관들이 모두 체크되어 있는지 확인
const otherSubTerms = subTerms.filter(({ id }) => id !== targetId);
const isOtherSubTermsAllChecked =
otherSubTerms.length > 0 ? otherSubTerms.every((subTerm) => subTerm.checked) : false;
const nextSubTerms = subTerms.map((subTerm) => (subTerm.id === targetId ? { ...subTerm, checked } : subTerm));
return marketingTerms.map((term) => {
const isParentTerm = term.termsType === parentTermType;
// 다른 하위 약관이 모두 체크된 경우: 해당 약관만 해제
if (isOtherSubTermsAllChecked) {
return isParentTerm ? { ...term, subTerms: nextSubTerms } : term;
}
// 이메일 수신 동의 해제: 부모 약관만 해제
if (targetId === 'directMailAgreed') {
return isParentTerm ? { ...term, checked, subTerms: nextSubTerms } : term;
}
// 기타 약관 해제: 모든 마케팅 약관 해제
if (isParentTerm) {
return { ...term, checked, subTerms: nextSubTerms };
}
return { ...term, checked };
});
};
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: '인증번호가 발송되었습니다.',
});
},
});
}
},
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: () => {
EventManager.fire('OPEN_LAYER_MODAL', {
name: 'kcp-sms-authentication',
data: { type: 'JOIN_TIME' },
onClose: ({ reason, state }) => {
if (reason === 'DID_SUBMIT') {
ShopbySkin.EventManager.fire('SUCCESS_AUTHENTICATION_SMS', state);
}
},
});
},
SEARCH_ZIP_CODE: () => {
EventManager.fire('OPEN_LAYER_MODAL', {
modalAddClass: 'search-zip-code full-modal',
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,
...termsInformation.marketingTerms,
];
const selectedTerm = mergedTerms.find((term) => elTarget.getAttribute('shopby-term-id') === term.id.toString());
EventManager.fire('OPEN_LAYER_MODAL', {
name: 'term-detail',
data: selectedTerm,
});
},
MODIFY: async (helper) => {
await profileExtraInformationEl?.refetchConfigMemberExtraInfo();
const flattedRequest = flattenRequest(helper);
const invalidRequest = flattedRequest.openIdProvider
? checkInvalidProfileForm(flattedRequest).filter(
(error) => !['memberId', 'password', 'passwordConfirm'].includes(error.field)
)
: 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: () =>
moveTo({
url: constants.PAGE.MY_PAGE,
replace: true,
}),
});
},
CANCEL_MODIFY: () => {
moveTo({
url: constants.PAGE.MY_PAGE,
replace: true,
});
},
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);
},
});
},
OPEN_ID_CLICK: (_, { target }) => {
const provider = target.getAttribute('shopby-provider');
if (provider === 'app-card') {
EventManager.fire('OPEN_LAYER_MODAL', {
name: 'app-card-authenticate',
modalAddClass: 'app-card-authenticate-modal',
isFull: true,
data: {
nextPath: location.href,
previousPath: location.href,
provider,
redirectUri: `${location.origin}/callback/auth-callback.html`,
},
});
return;
}
passwordAuthenticationLayerModalHelper.openIdSignIn({
nextPath: location.href,
previousPath: location.href,
provider,
redirectUri: `${location.origin}/callback/auth-callback.html`,
});
},
CHECK_MARKETING_TERMS: (helper, event) => {
const { termsInformation } = helper.getState();
const nextMarketingTerms = termsInformationModule.setMarketingTermsAllCheck(
termsInformation.marketingTerms,
event.target.checked
);
const isAllCheckedTerms = termsInformationModule.getAllCheckedTerms();
const isAllChecked = isAllCheckedTerms && nextMarketingTerms.every((term) => term.checked);
termsInformationModule.store.setState({
marketingTerms: nextMarketingTerms,
isAllChecked,
});
},
CHECK_MARKETING_SUB_TERMS: (helper, event) => {
const { termsInformation } = helper.getState();
const { marketingTerms } = termsInformation;
const { target } = event;
const { checked, value } = target;
const parentTermType = target.getAttribute('shopby-parent-term-type');
const nextMarketingTerms = checked
? handleCheckSubTerm(marketingTerms, parentTermType, value, checked)
: handleUncheckSubTerm(marketingTerms, parentTermType, value, checked);
const flattedMarketingTerms = termsInformationModule.flattenMarketingTerms(nextMarketingTerms);
const isAllChecked =
termsInformationModule.getAllCheckedTerms() && flattedMarketingTerms.every((term) => term.checked);
termsInformationModule.store.setState({
marketingTerms: nextMarketingTerms,
isAllChecked,
});
},
};
const clickEventListener = (event) => {
const { target } = event;
const action = target.getAttribute('shopby-action');
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);
EventManager.fire('MYAPP:PROXY_REGISTER', {
proxyFnKey: 'openIdUrlProxy',
applyProxy: (proxyFn) => {
passwordAuthenticationLayerModalHelper.openIdSignIn = proxyFn(
passwordAuthenticationLayerModalHelper.openIdSignIn
);
},
});
EventManager.fire('MYAPP:PROXY_REGISTER', {
proxyFnKey: 'modifyMemberProxy',
applyProxy: (proxyFn) => {
modifyMemberFormHelper.modify = proxyFn(modifyMemberFormHelper.modify);
},
});
})();