회원탈퇴 완료
This commit is contained in:
parent
97f0e70f4d
commit
2905c22f26
@ -667,6 +667,33 @@ class MemberAuthRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//회원 탈퇴 1차 비밀번호 검증
|
||||||
|
public function verifyLegacyPassword(int $memNo, string $pwPlain): bool
|
||||||
|
{
|
||||||
|
$pwPlain = (string) $pwPlain;
|
||||||
|
|
||||||
|
if ($memNo <= 0 || $pwPlain === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ 1차 비번은 mem_st_ring.str_0
|
||||||
|
$stored = (string) (DB::table('mem_st_ring')
|
||||||
|
->where('mem_no', $memNo)
|
||||||
|
->value('str_0') ?? '');
|
||||||
|
|
||||||
|
if ($stored === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ CI 방식(PASS_SET=0) - 기존 attemptLegacyLogin과 동일
|
||||||
|
$try = (string) CiPassword::make($pwPlain, 0);
|
||||||
|
if ($try === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash_equals($stored, $try);
|
||||||
|
}
|
||||||
|
|
||||||
// 2차 비밀번호 검증
|
// 2차 비밀번호 검증
|
||||||
public function verifyPin2(int $memNo, string $pin2Plain): bool
|
public function verifyPin2(int $memNo, string $pin2Plain): bool
|
||||||
{
|
{
|
||||||
|
|||||||
@ -572,7 +572,7 @@ class MemInfoService
|
|||||||
// ✅ 최근 7일 이내 구매내역(stat_pay p/t) 있으면 불가
|
// ✅ 최근 7일 이내 구매내역(stat_pay p/t) 있으면 불가
|
||||||
$from = Carbon::today()->subDays(7)->startOfDay();
|
$from = Carbon::today()->subDays(7)->startOfDay();
|
||||||
|
|
||||||
$cnt = (int) DB::table('giftcard_order') // ⚠️ 테이블명이 다르면 여기만 바꾸면 됨
|
$cnt = (int) DB::table('pin_order')
|
||||||
->where('mem_no', $memNo)
|
->where('mem_no', $memNo)
|
||||||
->whereIn('stat_pay', ['p','t'])
|
->whereIn('stat_pay', ['p','t'])
|
||||||
->where('dt_stat_pay', '>=', $from->toDateTimeString())
|
->where('dt_stat_pay', '>=', $from->toDateTimeString())
|
||||||
@ -607,13 +607,12 @@ class MemInfoService
|
|||||||
'name_first' => '',
|
'name_first' => '',
|
||||||
'name_mid' => '',
|
'name_mid' => '',
|
||||||
'name_last' => '',
|
'name_last' => '',
|
||||||
'birth' => '',
|
'birth' => '1900-01-01',
|
||||||
'gender' => '',
|
'gender' => '',
|
||||||
'native' => '',
|
'native' => '',
|
||||||
'cell_corp' => '',
|
'cell_corp' => '',
|
||||||
'cell_phone' => '',
|
'cell_phone' => '',
|
||||||
'ci' => '',
|
'ci' => '',
|
||||||
|
|
||||||
'bank_code' => '',
|
'bank_code' => '',
|
||||||
'bank_name' => '',
|
'bank_name' => '',
|
||||||
'bank_act_num' => '',
|
'bank_act_num' => '',
|
||||||
@ -622,7 +621,6 @@ class MemInfoService
|
|||||||
'dt_req_out' => $dtReqOut,
|
'dt_req_out' => $dtReqOut,
|
||||||
'dt_out' => $now->toDateTimeString(),
|
'dt_out' => $now->toDateTimeString(),
|
||||||
'stat_3' => '4',
|
'stat_3' => '4',
|
||||||
|
|
||||||
'dt_mod' => $now->toDateTimeString(),
|
'dt_mod' => $now->toDateTimeString(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -630,8 +628,6 @@ class MemInfoService
|
|||||||
DB::table('mem_account')
|
DB::table('mem_account')
|
||||||
->where('mem_no', $memNo)
|
->where('mem_no', $memNo)
|
||||||
->update([
|
->update([
|
||||||
'act_type' => '',
|
|
||||||
'act_state' => '',
|
|
||||||
'bank_code' => '',
|
'bank_code' => '',
|
||||||
'bank_name' => '',
|
'bank_name' => '',
|
||||||
'bank_act_name' => '',
|
'bank_act_name' => '',
|
||||||
@ -642,7 +638,6 @@ class MemInfoService
|
|||||||
DB::table('mem_address')
|
DB::table('mem_address')
|
||||||
->where('mem_no', $memNo)
|
->where('mem_no', $memNo)
|
||||||
->update([
|
->update([
|
||||||
'gubun' => '',
|
|
||||||
'shipping' => '',
|
'shipping' => '',
|
||||||
'zipNo' => '',
|
'zipNo' => '',
|
||||||
'roadAddrPart1' => '',
|
'roadAddrPart1' => '',
|
||||||
|
|||||||
@ -161,3 +161,184 @@
|
|||||||
font-size:13px;
|
font-size:13px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =========================================
|
||||||
|
Withdraw Dialog (mypage style)
|
||||||
|
========================================= */
|
||||||
|
|
||||||
|
/* dim */
|
||||||
|
.ui-dialog.ui-dialog--mypage .ui-dialog__backdrop{
|
||||||
|
background: rgba(16,24,40,.45);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* panel */
|
||||||
|
.ui-dialog__panel--mypage{
|
||||||
|
width: min(640px, calc(100vw - 32px));
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
box-shadow: 0 18px 50px rgba(16,24,40,.18);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* head */
|
||||||
|
.ui-dialog__head--mypage{
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
justify-content:space-between;
|
||||||
|
padding: 16px 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border-bottom: 1px solid rgba(0,0,0,.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-dialog__title--mypage{
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 900;
|
||||||
|
color: #101828;
|
||||||
|
letter-spacing: .2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-dialog__close--mypage{
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid rgba(0,0,0,.06);
|
||||||
|
background: #f7f8fb;
|
||||||
|
color: #101828;
|
||||||
|
font-weight: 900;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* body */
|
||||||
|
.ui-dialog__body--mypage{
|
||||||
|
padding: 16px 18px 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* card blocks */
|
||||||
|
.wd-card{
|
||||||
|
border-radius: 16px;
|
||||||
|
border: 1px solid rgba(0,0,0,.06);
|
||||||
|
background: #f7f8fb;
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-card + .wd-card{ margin-top: 12px; }
|
||||||
|
|
||||||
|
.wd-card--form{
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* guide list */
|
||||||
|
.wd-guide{
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 18px;
|
||||||
|
color: #475467;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-guide li + li{ margin-top: 6px; }
|
||||||
|
|
||||||
|
/* agree */
|
||||||
|
.wd-agree{
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
gap:10px;
|
||||||
|
margin-top: 12px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #101828;
|
||||||
|
}
|
||||||
|
.wd-agree input{
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
accent-color: #2563eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fields */
|
||||||
|
.wd-field + .wd-field{ margin-top: 12px; }
|
||||||
|
|
||||||
|
.wd-label{
|
||||||
|
display:block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #667085;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.wd-label small{
|
||||||
|
font-weight: 800;
|
||||||
|
color: #98a2b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-input{
|
||||||
|
width: 100%;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 14px;
|
||||||
|
border: 1px solid rgba(0,0,0,.10);
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 0 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #101828;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-input:focus{
|
||||||
|
border-color: rgba(37,99,235,.55);
|
||||||
|
box-shadow: 0 0 0 4px rgba(37,99,235,.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* error msg */
|
||||||
|
.wd-msg{
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: #fff1f2;
|
||||||
|
border: 1px solid rgba(225,29,72,.18);
|
||||||
|
color: #9f1239;
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* footer buttons */
|
||||||
|
.ui-dialog__foot--mypage{
|
||||||
|
display:flex;
|
||||||
|
gap:10px;
|
||||||
|
padding: 14px 18px 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border-top: 1px solid rgba(0,0,0,.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-btn{
|
||||||
|
flex: 1;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 14px;
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-btn--ghost{
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid rgba(0,0,0,.10);
|
||||||
|
color: #101828;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-btn--danger{
|
||||||
|
background: #f97316; /* 사이트 메인 오렌지 쓰면 여기 바꿔도 됨 */
|
||||||
|
border: 1px solid rgba(0,0,0,.06);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-btn:disabled{
|
||||||
|
opacity: .6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mobile */
|
||||||
|
@media (max-width: 480px){
|
||||||
|
.ui-dialog__panel--mypage{ border-radius: 16px; }
|
||||||
|
.ui-dialog__body--mypage{ padding: 14px; }
|
||||||
|
.ui-dialog__foot--mypage{ padding: 12px 14px 14px; }
|
||||||
|
}
|
||||||
|
|||||||
@ -1202,26 +1202,104 @@
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
const dlg = document.getElementById('withdrawDialog');
|
||||||
|
if (!dlg) return;
|
||||||
|
|
||||||
|
const openBtn = document.getElementById('btnOpenWithdraw'); // 아래에서 버튼 추가할 거임
|
||||||
|
const closeEls = dlg.querySelectorAll('[data-close="1"]');
|
||||||
|
const submitBtn = document.getElementById('withdrawSubmitBtn');
|
||||||
|
|
||||||
|
const agreeEl = document.getElementById('withdrawAgree');
|
||||||
|
const pwEl = document.getElementById('withdrawPw');
|
||||||
|
const pin2El = document.getElementById('withdrawPin2');
|
||||||
|
const msgEl = document.getElementById('withdrawMsg');
|
||||||
|
|
||||||
|
function openDialog() {
|
||||||
|
dlg.classList.add('is-open');
|
||||||
|
dlg.setAttribute('aria-hidden', 'false');
|
||||||
|
msgEl.style.display = 'none';
|
||||||
|
msgEl.textContent = '';
|
||||||
|
// reset
|
||||||
|
agreeEl.checked = false;
|
||||||
|
pwEl.value = '';
|
||||||
|
pin2El.value = '';
|
||||||
|
setTimeout(() => pwEl.focus(), 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDialog() {
|
||||||
|
dlg.classList.remove('is-open');
|
||||||
|
dlg.setAttribute('aria-hidden', 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showError(text) {
|
||||||
|
msgEl.style.display = 'block';
|
||||||
|
msgEl.textContent = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeEls.forEach(el => el.addEventListener('click', closeDialog));
|
||||||
|
if (openBtn) openBtn.addEventListener('click', openDialog);
|
||||||
|
|
||||||
|
// 숫자만
|
||||||
|
pin2El.addEventListener('input', function () {
|
||||||
|
this.value = (this.value || '').replace(/[^\d]/g, '').slice(0, 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
submitBtn.addEventListener('click', async function () {
|
||||||
|
if (!agreeEl.checked) return showError('안내사항 동의가 필요합니다.');
|
||||||
|
const password = (pwEl.value || '').trim();
|
||||||
|
const pin2 = (pin2El.value || '').trim();
|
||||||
|
if (!password) return showError('비밀번호를 입력해 주세요.');
|
||||||
|
if (!/^\d{4}$/.test(pin2)) return showError('2차 비밀번호는 숫자 4자리여야 합니다.');
|
||||||
|
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(dlg.dataset.action, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
|
'X-CSRF-TOKEN': dlg.dataset.csrf,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
agree: '1',
|
||||||
|
password,
|
||||||
|
pin2
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const json = await res.json().catch(() => ({}));
|
||||||
|
|
||||||
|
if (!res.ok || !json.ok) {
|
||||||
|
showError(json.message || '회원탈퇴에 실패했습니다.');
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 성공
|
||||||
|
if (typeof showMsg === 'function') {
|
||||||
|
await showMsg(json.message || '회원탈퇴가 완료되었습니다.', { type: 'alert', title: '완료' });
|
||||||
|
} else {
|
||||||
|
alert(json.message || '회원탈퇴가 완료되었습니다.');
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.href = json.redirect || '/';
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
showError('처리 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.');
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
// 5) 기타 버튼들(준비중)
|
// 5) 기타 버튼들(준비중)
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
(function others() {
|
|
||||||
|
|
||||||
$('[data-action="withdraw-member"]')?.addEventListener('click', async () => {
|
|
||||||
const ok = await showMsg(
|
|
||||||
`회원탈퇴를 진행하시겠습니까?
|
|
||||||
|
|
||||||
• 탈퇴 시 계정 복구가 어려울 수 있습니다.
|
|
||||||
• 진행 전 보유 내역/정산/환불 정책을 확인해 주세요.`,
|
|
||||||
{ type: 'confirm', title: '회원탈퇴' }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!ok) return;
|
|
||||||
|
|
||||||
await showMsg('준비중입니다.', { type: 'alert', title: '회원탈퇴' });
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
48
resources/views/web/mypage/info/_withdraw_dialog.blade.php
Normal file
48
resources/views/web/mypage/info/_withdraw_dialog.blade.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<div id="withdrawDialog" class="ui-dialog ui-dialog--mypage" aria-hidden="true">
|
||||||
|
<div class="ui-dialog__backdrop" data-close="1"></div>
|
||||||
|
|
||||||
|
<div class="ui-dialog__panel ui-dialog__panel--mypage" role="dialog" aria-modal="true" aria-labelledby="withdrawTitle">
|
||||||
|
<div class="ui-dialog__head ui-dialog__head--mypage">
|
||||||
|
<div class="ui-dialog__title ui-dialog__title--mypage" id="withdrawTitle">회원탈퇴안내</div>
|
||||||
|
|
||||||
|
<button type="button" class="ui-dialog__close ui-dialog__close--mypage" data-close="1" aria-label="닫기">
|
||||||
|
✕
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ui-dialog__body ui-dialog__body--mypage">
|
||||||
|
<div class="wd-card wd-card--guide">
|
||||||
|
<ul class="wd-guide">
|
||||||
|
<li>회원 탈퇴 시 회원님께서 보유하셨던 포인트, 구매상품권, 쿠폰은 모두 삭제 됩니다.</li>
|
||||||
|
<li>회원 탈퇴 후 재가입시에는 신규 회원으로 가입이 처리되며, 탈퇴 전의 회원정보, 구매정보, 포인트정보 등 모든 정보는 복구되지 않습니다.</li>
|
||||||
|
<li>회원님이 사용하신 아이디(이메일)는 탈퇴완료 90일(3개월) 이후 재가입이 가능합니다.</li>
|
||||||
|
<li>회원탈퇴 후 모든정보는 즉시 삭제됩니다.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<label class="wd-agree">
|
||||||
|
<input type="checkbox" id="withdrawAgree" value="1">
|
||||||
|
<span>위 내용에 동의 합니다.</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wd-card wd-card--form">
|
||||||
|
<div class="wd-field">
|
||||||
|
<label class="wd-label" for="withdrawPw">비밀번호</label>
|
||||||
|
<input type="password" id="withdrawPw" class="wd-input" autocomplete="current-password" placeholder="비밀번호를 입력해 주세요" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wd-field">
|
||||||
|
<label class="wd-label" for="withdrawPin2">2차 비밀번호 <small>(숫자 4자리)</small></label>
|
||||||
|
<input type="password" id="withdrawPin2" class="wd-input" inputmode="numeric" maxlength="4" placeholder="숫자 4자리" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wd-msg" id="withdrawMsg" style="display:none;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ui-dialog__foot ui-dialog__foot--mypage">
|
||||||
|
<button type="button" class="wd-btn wd-btn--ghost" data-close="1">취소</button>
|
||||||
|
<button type="button" class="wd-btn wd-btn--danger" id="withdrawSubmitBtn">탈퇴하기</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<div class="mypage-card__arrow">›</div>
|
<div class="mypage-card__arrow">›</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button type="button" class="mypage-card mypage-card--btn mypage-card--danger" data-action="withdraw-member">
|
<button type="button" id="btnOpenWithdraw" class="mypage-card mypage-card--btn mypage-card--danger" data-action="withdraw-member">
|
||||||
<div class="mypage-card__icon">⚠️</div>
|
<div class="mypage-card__icon">⚠️</div>
|
||||||
<div class="mypage-card__body">
|
<div class="mypage-card__body">
|
||||||
<div class="mypage-card__title">회원탈퇴</div>
|
<div class="mypage-card__title">회원탈퇴</div>
|
||||||
@ -176,6 +176,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mypage-card__arrow">›</div>
|
<div class="mypage-card__arrow">›</div>
|
||||||
</button>
|
</button>
|
||||||
|
@include('web.mypage.info._withdraw_dialog')
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- ✅ 안내/주의사항 --}}
|
{{-- ✅ 안내/주의사항 --}}
|
||||||
@ -229,6 +231,14 @@
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// dialog에 action/csrf 주입
|
||||||
|
(function(){
|
||||||
|
var dlg = document.getElementById('withdrawDialog');
|
||||||
|
if(!dlg) return;
|
||||||
|
dlg.dataset.action = "{{ route('web.mypage.info.withdraw') }}";
|
||||||
|
dlg.dataset.csrf = "{{ csrf_token() }}";
|
||||||
|
})();
|
||||||
</script>
|
</script>
|
||||||
<script src="{{ asset('assets/js/mypage_renew.js') }}" defer></script>
|
<script src="{{ asset('assets/js/mypage_renew.js') }}" defer></script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user