광고 수신동의 및 출금계좌 작업
This commit is contained in:
parent
9db798dee8
commit
97f0e70f4d
@ -9,6 +9,7 @@ use App\Services\Dozn\DoznAccountAuthService;
|
||||
use App\Repositories\Member\MemberAuthRepository;
|
||||
use App\Support\LegacyCrypto\CiSeedCrypto;
|
||||
use App\Support\LegacyCrypto\CiPassword;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
@ -31,6 +32,7 @@ final class InfoGateController extends Controller
|
||||
$at = (int) ($gate['at'] ?? 0);
|
||||
$ttlSeconds = 5 * 60;
|
||||
$isValid = $ok && $at > 0 && (time() - $at) <= $ttlSeconds;
|
||||
|
||||
if ($isValid) {
|
||||
return redirect()->to('/mypage/info_renew');
|
||||
}
|
||||
@ -39,7 +41,7 @@ final class InfoGateController extends Controller
|
||||
}
|
||||
|
||||
|
||||
public function info_renew(Request $request)
|
||||
public function info_renew(Request $request, MemInfoService $memInfoService)
|
||||
{
|
||||
// gate (기존 그대로)
|
||||
$gate = (array) $request->session()->get('mypage_gate', []);
|
||||
@ -58,17 +60,23 @@ final class InfoGateController extends Controller
|
||||
$memberName = (string) Arr::get($sess, '_mname', '');
|
||||
$memberEmail = (string) Arr::get($sess, '_mid', '');
|
||||
$dtReg = (string) Arr::get($sess, '_dt_reg', '');
|
||||
$memNo = (int) Arr::get($sess, '_mno', 0);
|
||||
$rawPhone = (string) Arr::get($sess, '_mcell', '');
|
||||
|
||||
// 전화번호 복호 (인증 완료 상태라 마스킹 제외)
|
||||
$rawPhone = (string) Arr::get($sess, '_mcell', '');
|
||||
$memberPhone = (string) $this->seed->decrypt($rawPhone);
|
||||
$user = $request->user();
|
||||
$withdrawBankName = (string)($user->withdraw_bank_name ?? $user->bank_name ?? '');
|
||||
$withdrawAccount = (string)($user->withdraw_account ?? $user->bank_account ?? '');
|
||||
$hasWithdrawAccount = ($withdrawBankName !== '' && $withdrawAccount !== '');
|
||||
|
||||
$agreeEmail = (string)($user->agree_marketing_email ?? $user->agree_email ?? 'n');
|
||||
$agreeSms = (string)($user->agree_marketing_sms ?? $user->agree_sms ?? 'n');
|
||||
$recv = $memNo > 0
|
||||
? $memInfoService->getReceive($memNo)
|
||||
: ['rcv_email' => 'n', 'rcv_sms' => 'n', 'out_account' => null];
|
||||
|
||||
$agreeEmail = $recv['rcv_email'];
|
||||
$agreeSms = $recv['rcv_sms'];
|
||||
$outAccount = $recv['out_account'] ?? null;
|
||||
|
||||
return view('web.mypage.info.renew', [
|
||||
// gate
|
||||
@ -87,6 +95,7 @@ final class InfoGateController extends Controller
|
||||
'hasWithdrawAccount' => (bool) $hasWithdrawAccount,
|
||||
'agreeEmail' => $agreeEmail,
|
||||
'agreeSms' => $agreeSms,
|
||||
'outAccount' => $outAccount,
|
||||
]);
|
||||
}
|
||||
|
||||
@ -252,14 +261,6 @@ final class InfoGateController extends Controller
|
||||
) {
|
||||
$payload = $request->all();
|
||||
|
||||
if (config('app.debug')) {
|
||||
Log::info('[MYPAGE][DANAL][RESULT] keys', [
|
||||
'method' => $request->method(),
|
||||
'url' => $request->fullUrl(),
|
||||
'keys' => array_keys($payload),
|
||||
]);
|
||||
}
|
||||
|
||||
$tid = (string)($payload['TID'] ?? '');
|
||||
if ($tid === '') {
|
||||
return response()->view('web.auth.danal_finish_top', [
|
||||
@ -329,7 +330,7 @@ final class InfoGateController extends Controller
|
||||
}else{
|
||||
return response()->view('web.auth.danal_finish_top', [
|
||||
'ok' => false,
|
||||
'message' => $check['message'] ?? '연락처 변경에 실패했습니다.\n\n관리자에게 문의하세요!',
|
||||
'message' => '요청이 올바르지 않습니다. 다시 시도해 주세요.',
|
||||
'redirect' => route('web.mypage.info.index'),
|
||||
]);
|
||||
}
|
||||
@ -594,6 +595,69 @@ final class InfoGateController extends Controller
|
||||
return response()->json($res, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* 마케팅 수신 동의 저장 (email/sms 각각 변경 시 해당 dt만 업데이트)
|
||||
* - gate(5분) 유효해야 함
|
||||
* - mem_info: rcv_email, rcv_sms, dt_rcv_email, dt_rcv_sms
|
||||
*/
|
||||
public function marketingUpdate(Request $request, MemInfoService $memInfoService)
|
||||
{
|
||||
if (!$this->isGateOk($request)) {
|
||||
return $this->gateFailJson($request, '인증 시간이 만료되었습니다. 다시 인증해 주세요.');
|
||||
}
|
||||
|
||||
// 레거시 세션 기준
|
||||
$sess = (array) $request->session()->get('_sess', []);
|
||||
$isLogin = (bool) ($sess['_login_'] ?? false);
|
||||
$memNo = (int) ($sess['_mno'] ?? 0);
|
||||
|
||||
if (!$isLogin || $memNo <= 0) {
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => '로그인 정보가 확인되지 않습니다. 다시 로그인해 주세요.',
|
||||
'redirect' => route('web.auth.login'),
|
||||
], 401);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'rcv_email' => ['required', Rule::in(['y','n'])],
|
||||
'rcv_sms' => ['required', Rule::in(['y','n'])],
|
||||
], [
|
||||
'rcv_email.required' => '이메일 수신 동의 값을 선택해 주세요.',
|
||||
'rcv_sms.required' => 'SMS 수신 동의 값을 선택해 주세요.',
|
||||
'rcv_email.in' => '이메일 수신 동의 값이 올바르지 않습니다.',
|
||||
'rcv_sms.in' => 'SMS 수신 동의 값이 올바르지 않습니다.',
|
||||
]);
|
||||
|
||||
$rcvEmail = (string) $request->input('rcv_email', 'n');
|
||||
$rcvSms = (string) $request->input('rcv_sms', 'n');
|
||||
|
||||
try {
|
||||
$result = $memInfoService->setReceiveSelective($memNo, $rcvEmail, $rcvSms);
|
||||
|
||||
// 세션/표시용 값이 따로 있으면 여기서 같이 갱신해도 됨(선택)
|
||||
// 예: $request->session()->put('_sess.rcv_email', $rcvEmail);
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'message' => $result['message'] ?? '수신 동의 설정이 저장되었습니다.',
|
||||
'changed' => $result['changed'] ?? [],
|
||||
], 200);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('[mypage] marketing consent update failed', [
|
||||
'mem_no' => $memNo,
|
||||
'err' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => '수신 동의 저장에 실패했습니다. 잠시 후 다시 시도해 주세요.',
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gate 유효성 체크 (mypage_gate.at만 사용, TTL=5분)
|
||||
*/
|
||||
@ -620,5 +684,96 @@ final class InfoGateController extends Controller
|
||||
], 401);
|
||||
}
|
||||
|
||||
//회원탈퇴
|
||||
public function withdraw(
|
||||
Request $request,
|
||||
MemInfoService $memInfoService,
|
||||
MemberAuthRepository $repo
|
||||
) {
|
||||
// gate(5분) 유효해야 함 (지금 페이지가 info_renew니까 정책 그대로)
|
||||
if (!$this->isGateOk($request)) {
|
||||
return $this->gateFailJson($request, '인증 시간이 만료되었습니다. 다시 인증해 주세요.');
|
||||
}
|
||||
|
||||
// 입력 검증
|
||||
$request->validate([
|
||||
'agree' => ['required', 'in:1'],
|
||||
'password' => ['required', 'string'],
|
||||
'pin2' => ['required', 'digits:4'],
|
||||
], [
|
||||
'agree.required' => '안내사항 동의가 필요합니다.',
|
||||
'agree.in' => '안내사항 동의가 필요합니다.',
|
||||
'password.required' => '비밀번호를 입력해 주세요.',
|
||||
'pin2.required' => '2차 비밀번호(숫자 4자리)를 입력해 주세요.',
|
||||
'pin2.digits' => '2차 비밀번호는 숫자 4자리여야 합니다.',
|
||||
]);
|
||||
|
||||
$sess = (array) $request->session()->get('_sess', []);
|
||||
$memNo = (int) Arr::get($sess, '_mno', 0);
|
||||
|
||||
if ($memNo <= 0) {
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => '로그인 정보가 확인되지 않습니다. 다시 로그인해 주세요.',
|
||||
'redirect' => route('web.auth.login'),
|
||||
], 401);
|
||||
}
|
||||
|
||||
$pw = (string) $request->input('password');
|
||||
$pin2 = (string) $request->input('pin2');
|
||||
|
||||
// ✅ 1차 비밀번호 검증(Repo)
|
||||
if (!$repo->verifyLegacyPassword($memNo, $pw)) {
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => '비밀번호가 일치하지 않습니다.',
|
||||
'errors' => ['password' => ['비밀번호가 일치하지 않습니다.']],
|
||||
], 422);
|
||||
}
|
||||
|
||||
// ✅ 2차 비밀번호 검증(Repo)
|
||||
if (!$repo->verifyPin2($memNo, $pin2)) {
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => '2차 비밀번호가 일치하지 않습니다.',
|
||||
'errors' => ['pin2' => ['2차 비밀번호가 일치하지 않습니다.']],
|
||||
], 422);
|
||||
}
|
||||
|
||||
// ✅ 탈퇴 가능 조건 검증 + 처리(Service)
|
||||
try {
|
||||
$res = $memInfoService->withdrawMember($memNo);
|
||||
|
||||
if (!($res['ok'] ?? false)) {
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => $res['message'] ?? '회원탈퇴가 불가합니다.',
|
||||
], 422);
|
||||
}
|
||||
|
||||
// 세션 종료 (레거시 세션 포함)
|
||||
$request->session()->flush();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'message' => $res['message'] ?? '회원탈퇴가 완료되었습니다.',
|
||||
'redirect' => route('web.auth.login'),
|
||||
]);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('[mypage] withdraw failed', [
|
||||
'mem_no' => $memNo,
|
||||
'err' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => '회원탈퇴 처리 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.',
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -9,13 +9,28 @@ class LegacyAuth
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
// 레거시 세션: 로그인 플래그 + memNo 둘 다 확인
|
||||
$loggedIn = (bool) $request->session()->get('_sess._login_', false);
|
||||
$memNo = (int) $request->session()->get('_sess._mno', 0);
|
||||
|
||||
if (!$loggedIn) {
|
||||
// 로그인 성공 후 원래 가려던 곳으로 보내기 위해 intended 저장
|
||||
// (Laravel auth 안 쓰더라도 이 키는 redirect()->intended()가 알아서 씀)
|
||||
if (!$loggedIn || $memNo <= 0) {
|
||||
|
||||
// GET만 intended 저장
|
||||
if ($request->isMethod('get')) {
|
||||
$request->session()->put('url.intended', $request->fullUrl());
|
||||
}
|
||||
|
||||
// JSON을 기대하는 요청이면 JSON 401
|
||||
// (fetch/axios는 Accept: application/json 넣으면 expectsJson()이 안정적으로 동작)
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => '로그인 정보가 확인되지 않습니다. 다시 로그인해 주세요.',
|
||||
'redirect' => route('web.auth.login'),
|
||||
], 401);
|
||||
}
|
||||
|
||||
// 일반 웹 요청: 로그인 페이지로
|
||||
return redirect()->route('web.auth.login')
|
||||
->with('ui_dialog', [
|
||||
'type' => 'alert',
|
||||
|
||||
@ -13,33 +13,6 @@ use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class MemInfoService
|
||||
{
|
||||
/**
|
||||
* CI: set_receive()
|
||||
* 프로모션 수신 동의 변경 (행 잠금)
|
||||
*/
|
||||
public function setReceive(int $memNo, string $rcvEmail, string $rcvSms, ?string $rcvPush = null): void
|
||||
{
|
||||
DB::transaction(function () use ($memNo, $rcvEmail, $rcvSms, $rcvPush) {
|
||||
/** @var MemInfo $mem */
|
||||
$mem = MemInfo::query()->whereKey($memNo)->lockForUpdate()->firstOrFail();
|
||||
|
||||
$now = Carbon::now()->format('Y-m-d H:i:s');
|
||||
|
||||
$mem->rcv_email = $rcvEmail;
|
||||
$mem->rcv_sms = $rcvSms;
|
||||
$mem->dt_rcv_email = $now;
|
||||
$mem->dt_rcv_sms = $now;
|
||||
|
||||
if ($rcvPush !== null) {
|
||||
$mem->rcv_push = $rcvPush;
|
||||
$mem->dt_rcv_push = $now;
|
||||
}
|
||||
|
||||
$mem->dt_mod = $now;
|
||||
$mem->save();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* CI: mem_email_vali()
|
||||
*/
|
||||
@ -491,4 +464,213 @@ class MemInfoService
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function getReceive(int $memNo): array
|
||||
{
|
||||
$mem = MemInfo::query()->whereKey($memNo)->first();
|
||||
|
||||
// ✅ 출금계좌 인증정보 (있으면 1건)
|
||||
$outAccount = DB::table('mem_account')
|
||||
->select(['bank_name', 'bank_act_num', 'bank_act_name', 'act_date'])
|
||||
->where('mem_no', $memNo)
|
||||
->where('act_type', 'out')
|
||||
->where('act_state', '3')
|
||||
->orderByDesc('act_date')
|
||||
->first();
|
||||
|
||||
if (!$mem) {
|
||||
return [
|
||||
'rcv_email' => 'n',
|
||||
'rcv_sms' => 'n',
|
||||
'rcv_push' => null,
|
||||
'out_account' => $outAccount ? [
|
||||
'bank_name' => (string)($outAccount->bank_name ?? ''),
|
||||
'bank_act_num' => (string)($outAccount->bank_act_num ?? ''),
|
||||
'bank_act_name'=> (string)($outAccount->bank_act_name ?? ''),
|
||||
'act_date' => (string)($outAccount->act_date ?? ''),
|
||||
] : null,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'rcv_email' => (string)($mem->rcv_email ?? 'n'),
|
||||
'rcv_sms' => (string)($mem->rcv_sms ?? 'n'),
|
||||
'rcv_push' => $mem->rcv_push !== null ? (string)$mem->rcv_push : null,
|
||||
|
||||
// ✅ 추가
|
||||
'out_account' => $outAccount ? [
|
||||
'bank_name' => (string)($outAccount->bank_name ?? ''),
|
||||
'bank_act_num' => (string)($outAccount->bank_act_num ?? ''),
|
||||
'bank_act_name'=> (string)($outAccount->bank_act_name ?? ''),
|
||||
'act_date' => (string)($outAccount->act_date ?? ''),
|
||||
] : null,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/*회원정보 수신동의 정보 저장*/
|
||||
public function setReceiveSelective(int $memNo, string $rcvEmail, string $rcvSms): array
|
||||
{
|
||||
$rcvEmail = ($rcvEmail === 'y') ? 'y' : 'n';
|
||||
$rcvSms = ($rcvSms === 'y') ? 'y' : 'n';
|
||||
|
||||
return DB::transaction(function () use ($memNo, $rcvEmail, $rcvSms) {
|
||||
/** @var MemInfo $mem */
|
||||
$mem = MemInfo::query()->whereKey($memNo)->lockForUpdate()->firstOrFail();
|
||||
|
||||
$beforeEmail = (string) ($mem->rcv_email ?? 'n');
|
||||
$beforeSms = (string) ($mem->rcv_sms ?? 'n');
|
||||
|
||||
$changedEmail = ($beforeEmail !== $rcvEmail);
|
||||
$changedSms = ($beforeSms !== $rcvSms);
|
||||
|
||||
if (!$changedEmail && !$changedSms) {
|
||||
return [
|
||||
'changed' => [],
|
||||
'message' => '변경된 내용이 없습니다.',
|
||||
];
|
||||
}
|
||||
|
||||
$now = Carbon::now()->format('Y-m-d H:i:s');
|
||||
|
||||
if ($changedEmail) {
|
||||
$mem->rcv_email = $rcvEmail;
|
||||
$mem->dt_rcv_email = $now;
|
||||
}
|
||||
|
||||
if ($changedSms) {
|
||||
$mem->rcv_sms = $rcvSms;
|
||||
$mem->dt_rcv_sms = $now;
|
||||
}
|
||||
|
||||
// 공통 수정일은 변경이 있을 때만
|
||||
$mem->dt_mod = $now;
|
||||
$mem->save();
|
||||
|
||||
$changed = [];
|
||||
if ($changedEmail) $changed[] = 'email';
|
||||
if ($changedSms) $changed[] = 'sms';
|
||||
|
||||
$label = [];
|
||||
if ($changedEmail) $label[] = '이메일';
|
||||
if ($changedSms) $label[] = 'SMS';
|
||||
|
||||
return [
|
||||
'changed' => $changed,
|
||||
'message' => implode('·', $label) . ' 수신 동의 설정이 저장되었습니다.',
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
//회원 탈퇴 최근 구매내역 확인
|
||||
public function validateWithdraw(int $memNo): array
|
||||
{
|
||||
if ($memNo <= 0) {
|
||||
return ['ok' => false, 'message' => '로그인 정보가 올바르지 않습니다.'];
|
||||
}
|
||||
|
||||
// ✅ 최근 7일 이내 구매내역(stat_pay p/t) 있으면 불가
|
||||
$from = Carbon::today()->subDays(7)->startOfDay();
|
||||
|
||||
$cnt = (int) DB::table('giftcard_order') // ⚠️ 테이블명이 다르면 여기만 바꾸면 됨
|
||||
->where('mem_no', $memNo)
|
||||
->whereIn('stat_pay', ['p','t'])
|
||||
->where('dt_stat_pay', '>=', $from->toDateTimeString())
|
||||
->count();
|
||||
|
||||
if ($cnt > 0) {
|
||||
return [
|
||||
'ok' => false,
|
||||
'message' => '죄송합니다. 최근 7일 이내 구매내역이 있는 경우 즉시 탈퇴가 불가합니다. 고객센터로 탈퇴 접수를 해주시기 바랍니다',
|
||||
];
|
||||
}
|
||||
|
||||
return ['ok' => true];
|
||||
}
|
||||
|
||||
//회원탈퇴 진행
|
||||
public function withdrawMember(int $memNo): array
|
||||
{
|
||||
$v = $this->validateWithdraw($memNo);
|
||||
if (!($v['ok'] ?? false)) return $v;
|
||||
|
||||
$now = Carbon::now();
|
||||
$dtReqOut = $now->copy()->addDays(90)->toDateString(); // Y-m-d
|
||||
|
||||
DB::transaction(function () use ($memNo, $now, $dtReqOut) {
|
||||
|
||||
// 1) mem_info 비식별/초기화 + 탈퇴 처리
|
||||
DB::table('mem_info')
|
||||
->where('mem_no', $memNo)
|
||||
->update([
|
||||
'name' => '',
|
||||
'name_first' => '',
|
||||
'name_mid' => '',
|
||||
'name_last' => '',
|
||||
'birth' => '',
|
||||
'gender' => '',
|
||||
'native' => '',
|
||||
'cell_corp' => '',
|
||||
'cell_phone' => '',
|
||||
'ci' => '',
|
||||
|
||||
'bank_code' => '',
|
||||
'bank_name' => '',
|
||||
'bank_act_num' => '',
|
||||
'bank_vact_num' => '',
|
||||
|
||||
'dt_req_out' => $dtReqOut,
|
||||
'dt_out' => $now->toDateTimeString(),
|
||||
'stat_3' => '4',
|
||||
|
||||
'dt_mod' => $now->toDateTimeString(),
|
||||
]);
|
||||
|
||||
// 2) mem_account 초기화
|
||||
DB::table('mem_account')
|
||||
->where('mem_no', $memNo)
|
||||
->update([
|
||||
'act_type' => '',
|
||||
'act_state' => '',
|
||||
'bank_code' => '',
|
||||
'bank_name' => '',
|
||||
'bank_act_name' => '',
|
||||
'bank_act_num' => '',
|
||||
]);
|
||||
|
||||
// 3) mem_address 초기화
|
||||
DB::table('mem_address')
|
||||
->where('mem_no', $memNo)
|
||||
->update([
|
||||
'gubun' => '',
|
||||
'shipping' => '',
|
||||
'zipNo' => '',
|
||||
'roadAddrPart1' => '',
|
||||
'jibunAddr' => '',
|
||||
'addrDetail' => '',
|
||||
]);
|
||||
|
||||
// 4) mem_auth 인증 해제
|
||||
DB::table('mem_auth')
|
||||
->where('mem_no', $memNo)
|
||||
->update([
|
||||
'auth_state' => 'N',
|
||||
]);
|
||||
|
||||
// 5) mem_st_ring 비번/2차 비번 제거
|
||||
DB::table('mem_st_ring')
|
||||
->where('mem_no', $memNo)
|
||||
->update([
|
||||
'str_0' => '',
|
||||
'str_1' => '',
|
||||
'str_2' => '',
|
||||
'dt_reg' => $now->toDateTimeString(),
|
||||
|
||||
'passwd2' => '',
|
||||
'passwd2_reg' => $now->toDateTimeString(),
|
||||
]);
|
||||
});
|
||||
|
||||
return ['ok' => true, 'message' => '회원탈퇴가 완료되었습니다.'];
|
||||
}
|
||||
}
|
||||
|
||||
163
public/assets/css/mypage_renew.css
Normal file
163
public/assets/css/mypage_renew.css
Normal file
@ -0,0 +1,163 @@
|
||||
/* =========================================================
|
||||
mypage_renew.css
|
||||
- 마이페이지 내정보(renew) 상단 히어로(좌/우) + 카드 UI
|
||||
- 범위: .mypage-info-page 내부만 적용
|
||||
========================================================= */
|
||||
|
||||
/* countdown row */
|
||||
.mypage-info-page .mypage-reauth__one{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:space-between;
|
||||
gap:10px;
|
||||
}
|
||||
|
||||
.mypage-info-page #reauthCountdown{
|
||||
font-size:14px;
|
||||
letter-spacing:0.5px;
|
||||
}
|
||||
|
||||
/* ---------------------------
|
||||
레이아웃: 타이틀 100% + 아래 좌/우
|
||||
--------------------------- */
|
||||
|
||||
/* 기존 테마가 flex를 써도 강제로 stack 구조로 */
|
||||
.mypage-info-page .mypage-hero .mypage-hero__inner.mypage-hero__inner--stack{
|
||||
display:block;
|
||||
}
|
||||
|
||||
/* 헤더(ACCOUNT SETTINGS / 내 정보 관리) */
|
||||
.mypage-info-page .mypage-hero .mypage-hero__head{
|
||||
width:100%;
|
||||
margin-bottom:12px;
|
||||
}
|
||||
|
||||
/* 본문(좌/우 2컬럼) */
|
||||
.mypage-info-page .mypage-hero .mypage-hero__body{
|
||||
display:grid;
|
||||
grid-template-columns: 1fr 360px; /* 오른쪽 카드 폭 */
|
||||
gap:24px;
|
||||
align-items:start;
|
||||
}
|
||||
|
||||
/* 반응형: 모바일은 1컬럼 */
|
||||
@media (max-width: 980px){
|
||||
.mypage-info-page .mypage-hero .mypage-hero__body{
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------
|
||||
왼쪽 정보 카드(성명/이메일/휴대폰/출금계좌 등)
|
||||
--------------------------- */
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me{
|
||||
margin-top:0px;
|
||||
padding:14px;
|
||||
border-radius:14px;
|
||||
background:#f7f8fb;
|
||||
border:1px solid #e5e7eb;
|
||||
box-shadow: 0 10px 24px rgba(16,24,40,.08);
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:space-between;
|
||||
gap:12px;
|
||||
padding:10px 12px;
|
||||
border-radius:12px;
|
||||
background:#ffffff;
|
||||
border:1px solid rgba(0,0,0,.04);
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row + .mypage-hero__me-row{
|
||||
margin-top:8px;
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row:hover{
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 6px 16px rgba(16,24,40,.06);
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row .k{
|
||||
display:inline-flex;
|
||||
align-items:center;
|
||||
gap:8px;
|
||||
font-size:12px;
|
||||
font-weight:800;
|
||||
color:#667085;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row .k::before{
|
||||
content:'';
|
||||
width:8px;
|
||||
height:8px;
|
||||
border-radius:999px;
|
||||
background:#2563eb;
|
||||
box-shadow: 0 0 0 4px rgba(37,99,235,.12);
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row .v{
|
||||
font-size:14px;
|
||||
font-weight:900;
|
||||
color:#101828;
|
||||
letter-spacing:.2px;
|
||||
text-align:right;
|
||||
word-break:break-all;
|
||||
}
|
||||
|
||||
/* ---------------------------
|
||||
오른쪽 카드(설명 + 잔여시간 + 버튼)
|
||||
--------------------------- */
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__right{
|
||||
height:auto;
|
||||
min-height:0;
|
||||
align-self:flex-start;
|
||||
|
||||
background:#ffffff;
|
||||
border:1px solid #e5e7eb;
|
||||
border-radius:16px;
|
||||
padding:18px;
|
||||
box-shadow: 0 10px 24px rgba(16,24,40,.08);
|
||||
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
gap:14px;
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__desc{
|
||||
margin:0;
|
||||
color:#475467;
|
||||
font-size:13px;
|
||||
line-height:1.55;
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-reauth{
|
||||
background:#f7f8fb;
|
||||
border:1px solid rgba(0,0,0,.06);
|
||||
border-radius:14px;
|
||||
padding:14px;
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__actions .btn{
|
||||
width:100%;
|
||||
border-radius:14px;
|
||||
padding:12px 14px;
|
||||
}
|
||||
|
||||
/* 모바일 미세 조정 */
|
||||
@media (max-width: 480px){
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me{
|
||||
padding:12px;
|
||||
border-radius:12px;
|
||||
}
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row{
|
||||
padding:10px 10px;
|
||||
}
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row .v{
|
||||
font-size:13px;
|
||||
}
|
||||
}
|
||||
@ -934,6 +934,274 @@
|
||||
|
||||
})();
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const CFG = window.mypageRenew || {};
|
||||
const URLS = CFG.urls || {};
|
||||
|
||||
const $ = (sel, root = document) => root.querySelector(sel);
|
||||
|
||||
function csrfToken() {
|
||||
return document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '';
|
||||
}
|
||||
|
||||
function ensureStyle(styleId, cssText) {
|
||||
if (document.getElementById(styleId)) return;
|
||||
const st = document.createElement('style');
|
||||
st.id = styleId;
|
||||
st.textContent = cssText;
|
||||
document.head.appendChild(st);
|
||||
}
|
||||
|
||||
function makeErrorSetter(wrap, sel) {
|
||||
const box = $(sel, wrap);
|
||||
return function setError(msg) {
|
||||
if (!box) return;
|
||||
const v = String(msg || '').trim();
|
||||
if (!v) {
|
||||
box.style.display = 'none';
|
||||
box.textContent = '';
|
||||
return;
|
||||
}
|
||||
box.textContent = v;
|
||||
box.style.display = 'block';
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeYn(v) {
|
||||
v = String(v || '').toLowerCase().trim();
|
||||
if (v === 'y' || v === '1' || v === 'true' || v === 'yes' || v === 'on') return 'y';
|
||||
return 'n';
|
||||
}
|
||||
|
||||
function badgeText(yn) {
|
||||
return (yn === 'y') ? '동의' : '미동의';
|
||||
}
|
||||
|
||||
function replaceWithClone(el) {
|
||||
// ✅ 기존 mypage_renew.js에서 "준비중" 리스너가 이미 붙어있으므로
|
||||
// 버튼을 clone으로 교체해서 리스너를 모두 제거한다.
|
||||
const clone = el.cloneNode(true);
|
||||
el.parentNode.replaceChild(clone, el);
|
||||
return clone;
|
||||
}
|
||||
|
||||
function openConsentModal(currentEmail, currentSms) {
|
||||
ensureStyle('mypageConsentModalStyle', `
|
||||
.mypage-consentmodal{position:fixed;inset:0;z-index:220000;display:flex;align-items:center;justify-content:center}
|
||||
.mypage-consentmodal__dim{position:absolute;inset:0;background:#000;opacity:.55}
|
||||
.mypage-consentmodal__box{position:relative;width:min(460px,calc(100% - 28px));background:#fff;border-radius:14px;overflow:hidden;box-shadow:0 18px 60px rgba(0,0,0,.35)}
|
||||
.mypage-consentmodal__hd{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;background:rgba(0,0,0,.04);border-bottom:1px solid rgba(0,0,0,.08)}
|
||||
.mypage-consentmodal__ttl{font-weight:900;font-size:14px;color:#111}
|
||||
.mypage-consentmodal__close{width:34px;height:34px;border-radius:10px;border:1px solid rgba(0,0,0,.12);background:#fff;cursor:pointer;font-size:18px;line-height:1;color:#111}
|
||||
.mypage-consentmodal__bd{padding:14px}
|
||||
.mypage-consentmodal__kicker{font-size:12px;font-weight:900;color:#2563eb;margin-bottom:6px}
|
||||
.mypage-consentmodal__desc{font-size:12px;color:#667085;line-height:1.5;margin-bottom:12px;white-space:pre-line}
|
||||
.mypage-consentmodal__grid{display:grid;grid-template-columns:1fr;gap:10px}
|
||||
.mypage-consentmodal__item{border:1px solid #e5e7eb;border-radius:14px;padding:12px;background:#fff}
|
||||
.mypage-consentmodal__row{display:flex;align-items:center;justify-content:space-between;gap:10px}
|
||||
.mypage-consentmodal__label{font-weight:900;color:#111;font-size:13px}
|
||||
.mypage-consentmodal__sub{font-size:12px;color:#667085;margin-top:6px;line-height:1.4}
|
||||
.mypage-consentmodal__seg{display:inline-flex;border:1px solid rgba(0,0,0,.12);border-radius:999px;overflow:hidden;background:#fff}
|
||||
.mypage-consentmodal__seg button{height:32px;min-width:64px;padding:0 12px;border:0;background:#fff;cursor:pointer;font-weight:900;font-size:12px;color:#111}
|
||||
.mypage-consentmodal__seg button.is-on{background:#111;color:#fff}
|
||||
.mypage-consentmodal__error{margin-top:12px;padding:10px 12px;border-radius:12px;background:rgba(220,38,38,.08);border:1px solid rgba(220,38,38,.25);color:#b91c1c;font-weight:800;font-size:12px;display:none;white-space:pre-line}
|
||||
.mypage-consentmodal__ft{display:flex;gap:10px;padding:12px 14px;border-top:1px solid rgba(0,0,0,.08);background:#fff}
|
||||
.mypage-consentmodal__btn{flex:1;height:42px;border-radius:12px;border:1px solid rgba(0,0,0,.12);background:#fff;font-weight:900;cursor:pointer}
|
||||
.mypage-consentmodal__btn--primary{border:none;background:#111;color:#fff}
|
||||
.mypage-consentmodal__btn[disabled]{opacity:.6;cursor:not-allowed}
|
||||
.mypage-consentmodal__badge{font-size:11px;font-weight:900;padding:4px 10px;border-radius:999px;background:rgba(37,99,235,.10);color:#2563eb}
|
||||
`);
|
||||
|
||||
const old = document.getElementById('mypageConsentModal');
|
||||
if (old) old.remove();
|
||||
|
||||
const wrap = document.createElement('div');
|
||||
wrap.className = 'mypage-consentmodal';
|
||||
wrap.id = 'mypageConsentModal';
|
||||
|
||||
let emailYn = normalizeYn(currentEmail);
|
||||
let smsYn = normalizeYn(currentSms);
|
||||
|
||||
wrap.innerHTML = `
|
||||
<div class="mypage-consentmodal__dim"></div>
|
||||
<div class="mypage-consentmodal__box" role="dialog" aria-modal="true" aria-labelledby="mypageConsentModalTitle">
|
||||
<div class="mypage-consentmodal__hd">
|
||||
<div class="mypage-consentmodal__ttl" id="mypageConsentModalTitle">마케팅 정보 수신 동의</div>
|
||||
<button type="button" class="mypage-consentmodal__close" aria-label="닫기">×</button>
|
||||
</div>
|
||||
|
||||
<div class="mypage-consentmodal__bd">
|
||||
<div class="mypage-consentmodal__kicker">CONSENT SETTINGS</div>
|
||||
<div class="mypage-consentmodal__desc">이벤트, 혜택, 프로모션 안내 등 마케팅 정보 수신 여부를 설정합니다.\n동의/미동의는 언제든지 변경할 수 있습니다.</div>
|
||||
|
||||
<div class="mypage-consentmodal__grid">
|
||||
<div class="mypage-consentmodal__item">
|
||||
<div class="mypage-consentmodal__row">
|
||||
<div>
|
||||
<div class="mypage-consentmodal__label">이메일 수신</div>
|
||||
<div class="mypage-consentmodal__sub">혜택/이벤트 안내 메일을 받아볼 수 있어요.</div>
|
||||
</div>
|
||||
<div class="mypage-consentmodal__seg" data-kind="email">
|
||||
<button type="button" data-val="y">동의</button>
|
||||
<button type="button" data-val="n">미동의</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mypage-consentmodal__item">
|
||||
<div class="mypage-consentmodal__row">
|
||||
<div>
|
||||
<div class="mypage-consentmodal__label">SMS 수신</div>
|
||||
<div class="mypage-consentmodal__sub">문자메시지로 주요 프로모션을 받아볼 수 있어요.</div>
|
||||
</div>
|
||||
<div class="mypage-consentmodal__seg" data-kind="sms">
|
||||
<button type="button" data-val="y">동의</button>
|
||||
<button type="button" data-val="n">미동의</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mypage-consentmodal__error" id="consent_error"></div>
|
||||
</div>
|
||||
|
||||
<div class="mypage-consentmodal__ft">
|
||||
<button type="button" class="mypage-consentmodal__btn" data-act="cancel">취소</button>
|
||||
<button type="button" class="mypage-consentmodal__btn mypage-consentmodal__btn--primary" data-act="submit">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(wrap);
|
||||
|
||||
const setError = makeErrorSetter(wrap, '#consent_error');
|
||||
|
||||
function close() { wrap.remove(); }
|
||||
|
||||
// 닫기: X / 취소만
|
||||
wrap.querySelector('.mypage-consentmodal__close')?.addEventListener('click', close);
|
||||
wrap.querySelector('[data-act="cancel"]')?.addEventListener('click', close);
|
||||
|
||||
function syncSeg(kind, yn) {
|
||||
const seg = wrap.querySelector(`.mypage-consentmodal__seg[data-kind="${kind}"]`);
|
||||
if (!seg) return;
|
||||
seg.querySelectorAll('button').forEach(btn => {
|
||||
const v = btn.getAttribute('data-val');
|
||||
btn.classList.toggle('is-on', v === yn);
|
||||
});
|
||||
}
|
||||
|
||||
function bindSeg(kind) {
|
||||
const seg = wrap.querySelector(`.mypage-consentmodal__seg[data-kind="${kind}"]`);
|
||||
if (!seg) return;
|
||||
seg.addEventListener('click', (e) => {
|
||||
const btn = e.target?.closest?.('button[data-val]');
|
||||
if (!btn) return;
|
||||
const yn = btn.getAttribute('data-val') === 'y' ? 'y' : 'n';
|
||||
if (kind === 'email') emailYn = yn;
|
||||
if (kind === 'sms') smsYn = yn;
|
||||
syncSeg(kind, yn);
|
||||
});
|
||||
}
|
||||
|
||||
syncSeg('email', emailYn);
|
||||
syncSeg('sms', smsYn);
|
||||
bindSeg('email');
|
||||
bindSeg('sms');
|
||||
|
||||
async function submit() {
|
||||
setError('');
|
||||
|
||||
if (!URLS.marketingConsentUpdate) {
|
||||
setError('저장 URL이 설정되지 않았습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
const ok = await showMsg(
|
||||
`수신 동의 설정을 저장하시겠습니까?\n\n• 이메일: ${badgeText(emailYn)}\n• SMS: ${badgeText(smsYn)}`,
|
||||
{ type: 'confirm', title: '수신 동의 저장' }
|
||||
);
|
||||
if (!ok) return;
|
||||
|
||||
const btn = wrap.querySelector('[data-act="submit"]');
|
||||
if (btn) btn.disabled = true;
|
||||
|
||||
try {
|
||||
const res = await fetch(URLS.marketingConsentUpdate, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': csrfToken(),
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
rcv_email: emailYn,
|
||||
rcv_sms: smsYn,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await res.json().catch(() => ({}));
|
||||
|
||||
if (res.status === 401 && data.redirect) {
|
||||
await showMsg(data.message || '인증이 필요합니다.', { type: 'alert', title: '인증 필요' });
|
||||
window.location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!res.ok || data.ok === false) {
|
||||
const msg =
|
||||
(data && data.message) ||
|
||||
(data && data.errors && (data.errors.rcv_email?.[0] || data.errors.rcv_sms?.[0])) ||
|
||||
'수신 동의 저장에 실패했습니다.';
|
||||
setError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
await showMsg(data.message || '수신 동의 설정이 저장되었습니다.', { type: 'alert', title: '완료' });
|
||||
close();
|
||||
window.location.reload();
|
||||
} catch (e) {
|
||||
setError('네트워크 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.');
|
||||
} finally {
|
||||
if (btn) btn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
wrap.querySelector('[data-act="submit"]')?.addEventListener('click', submit);
|
||||
|
||||
wrap.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
submit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function boot() {
|
||||
const btn0 = document.querySelector('[data-action="consent-edit"]');
|
||||
if (!btn0) return;
|
||||
|
||||
// ✅ 기존 “준비중” 클릭 리스너 제거
|
||||
const btn = replaceWithClone(btn0);
|
||||
|
||||
btn.addEventListener('click', () => {
|
||||
const currentEmail = normalizeYn(CFG?.consent?.email ?? 'n');
|
||||
const currentSms = normalizeYn(CFG?.consent?.sms ?? 'n');
|
||||
openConsentModal(currentEmail, currentSms);
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', boot);
|
||||
} else {
|
||||
boot();
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------
|
||||
@ -941,10 +1209,6 @@
|
||||
// -------------------------------------------
|
||||
(function others() {
|
||||
|
||||
$('[data-action="consent-edit"]')?.addEventListener('click', async () => {
|
||||
await showMsg('준비중입니다.', { type: 'alert', title: '수신 동의' });
|
||||
});
|
||||
|
||||
$('[data-action="withdraw-member"]')?.addEventListener('click', async () => {
|
||||
const ok = await showMsg(
|
||||
`회원탈퇴를 진행하시겠습니까?
|
||||
|
||||
@ -26,11 +26,18 @@
|
||||
|
||||
{{-- ✅ 상단 상태 카드 --}}
|
||||
<div class="mypage-hero mt-3">
|
||||
<div class="mypage-hero__inner">
|
||||
<div class="mypage-hero__left">
|
||||
<div class="mypage-hero__inner mypage-hero__inner--stack">
|
||||
|
||||
<!-- ✅ 헤더: 100% -->
|
||||
<div class="mypage-hero__head">
|
||||
<div class="mypage-hero__kicker">ACCOUNT SETTINGS</div>
|
||||
<div class="mypage-hero__title">내 정보 관리</div>
|
||||
<div class="mypage-hero__me mt-2">
|
||||
</div>
|
||||
|
||||
<!-- ✅ 바디: 좌/우 2컬럼 -->
|
||||
<div class="mypage-hero__body">
|
||||
<div class="mypage-hero__left">
|
||||
<div class="mypage-hero__me">
|
||||
<div class="mypage-hero__me-row">
|
||||
<span class="k">성명</span>
|
||||
<span class="v">{{ $memberName ?: '-' }}</span>
|
||||
@ -43,6 +50,20 @@
|
||||
<span class="k">휴대폰</span>
|
||||
<span class="v">{{ $memberPhone ?: '-' }}</span>
|
||||
</div>
|
||||
@if(!empty($outAccount))
|
||||
<div class="mypage-hero__me-row">
|
||||
<span class="k">출금계좌</span>
|
||||
<span class="v">
|
||||
{{ $outAccount['bank_name'] ?? '' }}
|
||||
{{ $outAccount['bank_act_num'] ?? '' }}
|
||||
({{ $outAccount['bank_act_name'] ?? '' }})
|
||||
</span>
|
||||
</div>
|
||||
<div class="mypage-hero__me-row">
|
||||
<span class="k">계좌인증일</span>
|
||||
<span class="v">{{ $outAccount['act_date'] ?? '' }}</span>
|
||||
</div>
|
||||
@endif
|
||||
<div class="mypage-hero__me-row">
|
||||
<span class="k">가입일</span>
|
||||
<span class="v">{{ $memberDtReg ?: '-' }}</span>
|
||||
@ -51,6 +72,7 @@
|
||||
</div>
|
||||
|
||||
<div class="mypage-hero__right">
|
||||
<div class="mypage-hero__spacer" aria-hidden="true"></div>
|
||||
<div class="mypage-hero__desc">
|
||||
연락처·비밀번호·보안 설정을 한 곳에서 관리합니다.
|
||||
변경 작업은 보안을 위해 제한된 시간 동안만 가능합니다.
|
||||
@ -76,6 +98,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ✅ 설정 카드 그리드 --}}
|
||||
<div class="mypage-grid mt-3">
|
||||
@ -114,19 +137,18 @@
|
||||
</div>
|
||||
<div class="mypage-card__arrow">›</div>
|
||||
</button>
|
||||
|
||||
<button type="button"
|
||||
class="mypage-card mypage-card--btn"
|
||||
aria-label="출금계좌번호 {{ $hasWithdrawAccount ? '수정' : '등록' }}"
|
||||
aria-label="출금계좌번호 {{ $outAccount ? '수정' : '등록' }}"
|
||||
data-action="withdraw-account">
|
||||
<div class="mypage-card__icon">🏦</div>
|
||||
<div class="mypage-card__body">
|
||||
<div class="mypage-card__title">출금계좌번호</div>
|
||||
<div class="mypage-card__desc">
|
||||
{{ $hasWithdrawAccount ? '등록된 출금계좌 정보를 수정합니다.' : '출금계좌를 등록해 주세요.' }}
|
||||
{{ $outAccount ? '등록된 출금계좌 정보를 수정합니다.' : '출금계좌를 등록해 주세요.' }}
|
||||
</div>
|
||||
<div class="mypage-card__meta">
|
||||
{{ $hasWithdrawAccount ? '수정' : '등록' }}
|
||||
{{ $outAccount ? '수정' : '등록' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mypage-card__arrow">›</div>
|
||||
@ -174,90 +196,7 @@
|
||||
</form>
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
.mypage-reauth__one{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:space-between;
|
||||
gap:10px;
|
||||
}
|
||||
#reauthCountdown{
|
||||
font-size:14px;
|
||||
letter-spacing:0.5px;
|
||||
}
|
||||
/* 더 강한 특이도(덮임 방지) + 흰 배경에서도 확실히 보이게 */
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me{
|
||||
margin-top:12px;
|
||||
padding:14px;
|
||||
border-radius:14px;
|
||||
background:#f7f8fb; /* ✅ 흰배경에서도 티 나게 */
|
||||
border:1px solid #e5e7eb;
|
||||
box-shadow: 0 10px 24px rgba(16,24,40,.08);
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:space-between;
|
||||
gap:12px;
|
||||
padding:10px 12px;
|
||||
border-radius:12px;
|
||||
background:#ffffff;
|
||||
border:1px solid rgba(0,0,0,.04);
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row + .mypage-hero__me-row{
|
||||
margin-top:8px;
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row:hover{
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 6px 16px rgba(16,24,40,.06);
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row .k{
|
||||
display:inline-flex;
|
||||
align-items:center;
|
||||
gap:8px;
|
||||
font-size:12px;
|
||||
font-weight:800;
|
||||
color:#667085;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row .k::before{
|
||||
content:'';
|
||||
width:8px;
|
||||
height:8px;
|
||||
border-radius:999px;
|
||||
background:#2563eb; /* 포인트 컬러 */
|
||||
box-shadow: 0 0 0 4px rgba(37,99,235,.12);
|
||||
}
|
||||
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row .v{
|
||||
font-size:14px;
|
||||
font-weight:900;
|
||||
color:#101828;
|
||||
letter-spacing:.2px;
|
||||
text-align:right;
|
||||
word-break:break-all;
|
||||
}
|
||||
|
||||
/* 모바일 */
|
||||
@media (max-width: 480px){
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me{
|
||||
padding:12px;
|
||||
border-radius:12px;
|
||||
}
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row{
|
||||
padding:10px 10px;
|
||||
}
|
||||
.mypage-info-page .mypage-hero .mypage-hero__me-row .v{
|
||||
font-size:13px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/mypage_renew.css') }}?v={{ config('app.version', time()) }}">
|
||||
@endpush
|
||||
@push('scripts')
|
||||
<script>
|
||||
@ -282,7 +221,12 @@
|
||||
passwordUpdate: @json(route('web.mypage.info.password.update')),
|
||||
pin2Update: @json(route('web.mypage.info.pin2.update')),
|
||||
withdrawVerifyOut: @json(route('web.mypage.info.withdraw.verify_out')),
|
||||
})
|
||||
marketingConsentUpdate: @json(route('web.mypage.info.marketing.update')),
|
||||
}),
|
||||
consent: {
|
||||
email: @json(($agreeEmail === '1') ? 'y' : $agreeEmail),
|
||||
sms: @json(($agreeSms === '1') ? 'y' : $agreeSms),
|
||||
},
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
@ -47,6 +47,8 @@ Route::prefix('mypage')->name('web.mypage.')
|
||||
Route::post('info/danal/result', [InfoGateController::class, 'danalResult'])->name('info.danal.result');
|
||||
Route::get('info/gate-reset', [InfoGateController::class, 'gateReset'])->name('info.gate_reset');
|
||||
Route::post('info/withdraw/verify-out', [InfoGateController::class, 'verifyOut'])->name('info.withdraw.verify_out');
|
||||
Route::post('info/marketing/update', [InfoGateController::class, 'marketingUpdate'])->name('info.marketing.update');
|
||||
Route::post('info/withdraw', [InfoGateController::class, 'withdraw'])->name('info.withdraw');
|
||||
|
||||
Route::view('usage', 'web.mypage.usage.index')->name('usage.index');
|
||||
Route::view('exchange', 'web.mypage.exchange.index')->name('exchange.index');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user