1232 lines
51 KiB
PHP
1232 lines
51 KiB
PHP
@extends('web.layouts.subpage')
|
||
|
||
@php
|
||
$mypageActive = $mypageActive ?? 'usage';
|
||
$attempt = $attempt ?? [];
|
||
$order = $order ?? [];
|
||
$items = $items ?? [];
|
||
$pins = $pins ?? [];
|
||
$pinsOpened = (bool)($pinsOpened ?? false); // 기존 핀 오픈 상태
|
||
$pinsRevealed = (bool)($pinsRevealed ?? false); // 이번 요청에서 실핀 표시 여부
|
||
$pinsRevealLocked = (bool)($pinsRevealLocked ?? false); // 실핀 확인 이력(취소 잠금)
|
||
$canCancel = (bool)($canCancel ?? false);
|
||
|
||
$backToListQuery = request()->only(['q', 'method', 'status', 'from', 'to', 'page']);
|
||
$backToListQuery = array_filter($backToListQuery, fn($v) => $v !== null && $v !== '');
|
||
|
||
$methodLabel = function ($m) {
|
||
$m = (string)$m;
|
||
return match ($m) {
|
||
'card' => '카드',
|
||
'phone' => '휴대폰',
|
||
'wire' => '계좌이체',
|
||
'vact' => '가상계좌',
|
||
default => $m ?: '-',
|
||
};
|
||
};
|
||
|
||
$statusLabel = function () use ($attempt, $order) {
|
||
$aCancel = (string)($attempt['cancel_status'] ?? 'none');
|
||
$oCancel = (string)($order['cancel_status'] ?? 'none');
|
||
|
||
if ($aCancel === 'success' || $oCancel === 'success') return '결제취소';
|
||
|
||
$aStatus = (string)($attempt['status'] ?? '');
|
||
$oPay = (string)($order['stat_pay'] ?? '');
|
||
|
||
if ($aStatus === 'paid' || $oPay === 'p') return '결제완료';
|
||
if ($aStatus === 'issued' || $oPay === 'w') return '입금대기';
|
||
if ($aStatus === 'failed' || $oPay === 'f') return '결제실패';
|
||
return '진행중';
|
||
};
|
||
|
||
$st = $statusLabel();
|
||
$isCancelledAfterPaid = ($st === '결제취소');
|
||
|
||
$statusClass = function ($label) {
|
||
return match ($label) {
|
||
'결제취소' => 'pill--danger',
|
||
'결제완료' => 'pill--ok',
|
||
'입금대기' => 'pill--wait',
|
||
'결제실패' => 'pill--danger',
|
||
default => 'pill--muted',
|
||
};
|
||
};
|
||
|
||
$attemptId = (int)($attempt['id'] ?? 0);
|
||
$oid = (string)($order['oid'] ?? '');
|
||
$method = (string)($order['pay_method'] ?? ($attempt['pay_method'] ?? ''));
|
||
$methodKor = $methodLabel($method);
|
||
|
||
$amounts = (array)($order['amounts'] ?? []);
|
||
$subtotal = (int)($amounts['subtotal'] ?? 0);
|
||
$fee = (int)($amounts['fee'] ?? 0);
|
||
$payMoney = (int)($amounts['pay_money'] ?? 0);
|
||
|
||
$productName = (string)($productname ?? '');
|
||
if ($productName === '') $productName = '-';
|
||
|
||
$itemName = (string)($items[0]['name'] ?? '');
|
||
if ($itemName === '') $itemName = '-';
|
||
|
||
$totalQty = 0;
|
||
foreach ($items as $it) $totalQty += (int)($it['qty'] ?? 0);
|
||
|
||
$createdAt = (string)($order['created_at'] ?? ($attempt['created_at'] ?? ''));
|
||
$dateStr = $createdAt ? \Carbon\Carbon::parse($createdAt)->format('Y-m-d H:i') : '-';
|
||
|
||
$showPinsNow = true;
|
||
$isPinIssuedCompleted = (bool)($pinsIssuedCompleted ?? !empty($pins));
|
||
$useRightBannerMode = $isCancelledAfterPaid || $isPinIssuedCompleted;
|
||
|
||
$issueMethods = $issueMethods ?? ['PIN_INSTANT','SMS','BUYBACK'];
|
||
if (is_string($issueMethods)) $issueMethods = json_decode($issueMethods, true) ?: [];
|
||
if (!is_array($issueMethods) || empty($issueMethods)) $issueMethods = ['PIN_INSTANT','SMS','BUYBACK'];
|
||
$issueAllowed = array_fill_keys($issueMethods, true);
|
||
|
||
$issueMissing = $issueMissing ?? [];
|
||
if (is_string($issueMissing)) $issueMissing = json_decode($issueMissing, true) ?: [];
|
||
if (!is_array($issueMissing)) $issueMissing = [];
|
||
|
||
$issueMap = [
|
||
'PIN_INSTANT' => '핀번호 바로 확인',
|
||
'SMS' => 'SMS 발송',
|
||
'BUYBACK' => '구매상품권 판매',
|
||
];
|
||
$issueMissingLabels = [];
|
||
foreach ($issueMissing as $k) {
|
||
if (isset($issueMap[$k])) $issueMissingLabels[] = $issueMap[$k];
|
||
}
|
||
|
||
$issueOpenKey = (count($issueMethods) === 1) ? ($issueMethods[0] ?? null) : null;
|
||
@endphp
|
||
|
||
@section('title', '구매내역 상세')
|
||
|
||
@section('subcontent')
|
||
<div class="mypage-usage">
|
||
|
||
<div class="topbar">
|
||
@if(session('success')) <div class="flash ok">{{ session('success') }}</div> @endif
|
||
@if(session('error')) <div class="flash err">{{ session('error') }}</div> @endif
|
||
<div class="sp"></div>
|
||
<a class="btn btn--back" href="{{ route('web.mypage.usage.index', $backToListQuery) }}">← 목록</a>
|
||
</div>
|
||
|
||
<div class="detail-hero-grid">
|
||
<div class="receipt-card receipt-card--paper">
|
||
<div class="receipt-head">
|
||
<div>
|
||
<div class="receipt-title">결제 영수증</div>
|
||
<div class="receipt-sub">
|
||
{{ $dateStr }} · {{ $methodKor }}
|
||
</div>
|
||
</div>
|
||
<span class="pill {{ $statusClass($st) }}">{{ $st }}</span>
|
||
</div>
|
||
|
||
<div class="receipt-divider"></div>
|
||
|
||
<div class="receipt-main">
|
||
<div class="receipt-product">
|
||
{{ $productName }}
|
||
<span class="receipt-item">[ {{ $itemName }} ]</span>
|
||
</div>
|
||
|
||
<div class="receipt-grid">
|
||
<div class="row">
|
||
<span class="k">결제번호</span>
|
||
<span class="v">#{{ $attemptId ?: '-' }}</span>
|
||
</div>
|
||
<div class="row">
|
||
<span class="k">주문번호</span>
|
||
<span class="v mono">{{ $oid ?: '-' }}</span>
|
||
</div>
|
||
<div class="row">
|
||
<span class="k">결제수단</span>
|
||
<span class="v">{{ $methodKor }}</span>
|
||
</div>
|
||
<div class="row">
|
||
<span class="k">수량</span>
|
||
<span class="v">{{ $totalQty }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="receipt-divider receipt-divider--dashed"></div>
|
||
|
||
<div class="receipt-amount">
|
||
<div class="amt-row">
|
||
<span class="k">상품금액</span>
|
||
<span class="v">{{ number_format($subtotal) }}원</span>
|
||
</div>
|
||
<div class="amt-row">
|
||
<span class="k">고객수수료</span>
|
||
<span class="v">{{ number_format($fee) }}원</span>
|
||
</div>
|
||
<div class="amt-row total">
|
||
<span class="k">결제금액</span>
|
||
<span class="v">{{ number_format($payMoney) }}원</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<aside class="right-panel {{ $useRightBannerMode ? 'right-panel--banner right-panel--mobile-hide' : '' }}">
|
||
@if($useRightBannerMode)
|
||
<div class="banner-stack">
|
||
@if($isCancelledAfterPaid)
|
||
<div class="promo-vertical-banner promo-vertical-banner--cancel">
|
||
<div class="promo-vertical-banner__inner">
|
||
<div class="promo-vertical-banner__badge">PROMO</div>
|
||
<div class="promo-vertical-banner__eyebrow">PIN FOR YOU</div>
|
||
|
||
<div class="promo-vertical-banner__title">
|
||
다음 구매는<br>
|
||
더 빠르고 간편하게
|
||
</div>
|
||
|
||
<div class="promo-vertical-banner__desc">
|
||
자주 찾는 상품권을 빠르게 확인하고,<br>
|
||
구매 내역/상태를 한 번에 관리해보세요.
|
||
</div>
|
||
|
||
<div class="promo-vertical-banner__chips">
|
||
<span class="chip">빠른 재구매</span>
|
||
<span class="chip">구매내역 관리</span>
|
||
<span class="chip">안전한 결제</span>
|
||
</div>
|
||
|
||
<div class="promo-vertical-banner__footer">
|
||
<div class="promo-vertical-banner__footer-title">추천 안내</div>
|
||
<div class="promo-vertical-banner__footer-desc">
|
||
진행 중인 이벤트 및 혜택은 메인/상품 페이지에서 확인할 수 있습니다.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
@if($isPinIssuedCompleted && !$isCancelledAfterPaid)
|
||
<div class="info-banner info-banner--ok">
|
||
<div class="info-banner__title">핀 발행이 완료되었습니다</div>
|
||
<div class="info-banner__desc">
|
||
핀 발행이 완료된 주문은 우측 발행 선택 영역 대신 안내 배너를 표시합니다.
|
||
핀 목록 영역에서 발행된 핀 정보를 확인해 주세요.
|
||
</div>
|
||
</div>
|
||
|
||
<div class="info-banner {{ $pinsRevealLocked ? 'info-banner--danger' : 'info-banner--warn' }}">
|
||
<div class="info-banner__title">
|
||
{{ $pinsRevealLocked ? '핀번호 확인 완료' : '핀번호 확인 안내' }}
|
||
</div>
|
||
<div class="info-banner__desc">
|
||
@if($pinsRevealLocked)
|
||
핀번호를 확인한 주문은 회원이 직접 취소할 수 없습니다.
|
||
취소가 꼭 필요한 경우 관리자에게 문의해 주세요.
|
||
@else
|
||
핀 오픈 후에도 기본은 마스킹 상태로 유지됩니다.
|
||
“핀번호 확인” 버튼에서 2차 비밀번호 인증 후 전체 핀번호를 확인할 수 있습니다.
|
||
@endif
|
||
</div>
|
||
</div>
|
||
@endif
|
||
</div>
|
||
@else
|
||
<div class="issue-panel">
|
||
<div class="issue-panel__head">
|
||
<h3 class="issue-panel__title">핀 발행 선택</h3>
|
||
|
||
@if(!empty($issueMissingLabels))
|
||
<div class="muted" style="font-size:12px;margin-top:6px;">
|
||
이 상품은 {{ implode(', ', $issueMissingLabels) }} 기능을 지원하지 않습니다.
|
||
</div>
|
||
@endif
|
||
</div>
|
||
|
||
<div class="issue-picker" id="issuePicker">
|
||
@if(isset($issueAllowed['PIN_INSTANT']))
|
||
<div class="issue-option {{ $issueOpenKey==='PIN_INSTANT' ? 'is-active' : '' }}" data-issue-card="view">
|
||
<button type="button" class="issue-option__toggle" data-issue-toggle>
|
||
<div class="issue-option__kicker">즉시 확인</div>
|
||
<div class="issue-option__title">핀번호 바로 확인</div>
|
||
<div class="issue-option__subtitle">안전하게 핀번호를 직접 확인합니다.</div>
|
||
<span class="issue-option__chev" aria-hidden="true">⌄</span>
|
||
</button>
|
||
<div class="issue-option__detail">
|
||
<div class="issue-option__detail-inner">
|
||
<p class="issue-option__detail-text">
|
||
핀번호를 개인 암호화하여 발행합니다. 핀번호 유출에 주의하세요.
|
||
</p>
|
||
<form method="post" action="{{ route('web.mypage.usage.issue.pin_instant', ['attemptId' => $attemptId]) }}">
|
||
@csrf
|
||
<button id="btnIssuePinInstant" type="submit" class="issue-run issue-run--dark">
|
||
핀번호 바로 확인 실행
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
@if(isset($issueAllowed['SMS']))
|
||
<div class="issue-option {{ $issueOpenKey==='SMS' ? 'is-active' : '' }}" data-issue-card="sms">
|
||
<button type="button" class="issue-option__toggle" data-issue-toggle>
|
||
<div class="issue-option__kicker">문자 발송</div>
|
||
<div class="issue-option__title">SMS 발송</div>
|
||
<div class="issue-option__subtitle">문자로 핀번호를 전송합니다.</div>
|
||
<span class="issue-option__chev" aria-hidden="true">⌄</span>
|
||
</button>
|
||
<div class="issue-option__detail">
|
||
<div class="issue-option__detail-inner">
|
||
<p class="issue-option__detail-text">
|
||
SMS 발송 시 핀번호는 저장되지 않습니다. 문자 수신 후 즉시 확인하세요.
|
||
</p>
|
||
<button id="btnIssueSms" type="button" class="issue-run issue-run--sky">
|
||
SMS 발송 실행
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
@if(isset($issueAllowed['BUYBACK']))
|
||
<div class="issue-option {{ $issueOpenKey==='BUYBACK' ? 'is-active' : '' }}" data-issue-card="sell">
|
||
<button type="button" class="issue-option__toggle" data-issue-toggle>
|
||
<div class="issue-option__kicker">재판매</div>
|
||
<div class="issue-option__title">구매상품권 판매</div>
|
||
<div class="issue-option__subtitle">구매하신 상품권을 판매 처리합니다.</div>
|
||
<span class="issue-option__chev" aria-hidden="true">⌄</span>
|
||
</button>
|
||
<div class="issue-option__detail">
|
||
<div class="issue-option__detail-inner">
|
||
<p class="issue-option__detail-text">
|
||
구매하신 상품권을 판매합니다. 계좌번호가 등록되어 있어야 하며,
|
||
매입 처리 후 회원님 계좌로 입금됩니다.
|
||
</p>
|
||
<button id="btnIssueSell" type="button" class="issue-run issue-run--green">
|
||
구매상품권 판매 실행
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
@if(empty($issueAllowed))
|
||
<div class="muted" style="padding:12px 6px;">
|
||
현재 이 상품은 핀 발행 방식이 설정되지 않았습니다. 고객센터로 문의해 주세요.
|
||
</div>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
@endif
|
||
</aside>
|
||
</div>
|
||
|
||
@if(!$isCancelledAfterPaid)
|
||
@if($showPinsNow && $hasIssuedIssues)
|
||
<div class="gift-zone">
|
||
<div class="gift-zone__head">
|
||
<div>
|
||
<h3 class="gift-zone__title">핀번호</h3>
|
||
<div class="gift-zone__sub">
|
||
기본은 마스킹 상태로 표시됩니다.
|
||
핀번호 확인 버튼에서 2차 비밀번호를 입력하면 이번 화면에서만 전체 핀번호를 확인할 수 있습니다.
|
||
</div>
|
||
</div>
|
||
|
||
@if($pinsRevealed)
|
||
<span class="gift-badge gift-badge--danger">핀번호 확인됨</span>
|
||
@else
|
||
<span class="gift-badge">마스킹 표시중</span>
|
||
@endif
|
||
</div>
|
||
|
||
@if(empty($pins))
|
||
<div class="usage-card">
|
||
<p class="muted">표시할 핀이 없습니다.</p>
|
||
</div>
|
||
@else
|
||
<div class="gift-list">
|
||
@foreach($pins as $idx => $p)
|
||
@php
|
||
$raw = (string)($p['pin'] ?? '');
|
||
$masked = (string)($p['pin_mask'] ?? '****');
|
||
$display = $pinsRevealed ? ($raw ?: $masked) : $masked;
|
||
$amount = number_format((int)($p['face_value'] ?? 0));
|
||
@endphp
|
||
|
||
<article class="gift-card">
|
||
<div class="gift-card__top">
|
||
<div class="gift-card__brand">MOBILE GIFT</div>
|
||
<div class="gift-card__chip">No. {{ $idx + 1 }}</div>
|
||
</div>
|
||
|
||
<div class="gift-card__body">
|
||
<div class="gift-card__name">{{ $productName }}</div>
|
||
<div class="gift-card__amount">{{ $amount }}원</div>
|
||
|
||
<div class="gift-card__pinbox">
|
||
<div class="gift-card__pinlabel">PIN NUMBER</div>
|
||
<div
|
||
class="gift-card__pincode mono"
|
||
data-pin-value="{{ $pinsRevealed ? ($raw ?: $masked) : '' }}"
|
||
>
|
||
{{ $display }}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="gift-card__notice">
|
||
핀번호는 본인만 확인해 주세요.<br>
|
||
핀 발행이 완료된 주문은 회원이 직접 취소할 수 없습니다.
|
||
</div>
|
||
</div>
|
||
</article>
|
||
@endforeach
|
||
</div>
|
||
|
||
@if(!$pinsRevealed)
|
||
<div class="gift-actions">
|
||
<button type="button" class="issue-run issue-run--dark gift-open-btn" onclick="openPinRevealModal()">
|
||
핀번호 확인
|
||
</button>
|
||
</div>
|
||
@else
|
||
<div class="gift-actions">
|
||
<button type="button" class="issue-run issue-run--dark gift-open-btn" id="btnCopyPins">
|
||
핀번호 복사
|
||
</button>
|
||
</div>
|
||
@endif
|
||
@endif
|
||
</div>
|
||
@endif
|
||
|
||
@if($canCancel)
|
||
<div class="usage-card cancel-box">
|
||
<h3 class="card-title">결제 취소</h3>
|
||
|
||
<div class="muted">
|
||
취소 사유를 선택한 뒤 결제를 취소할 수 있습니다.
|
||
</div>
|
||
|
||
<form method="post"
|
||
action="{{ route('web.mypage.usage.cancel', ['attemptId' => $attemptId]) }}"
|
||
class="cancel-form cancel-form--inline"
|
||
id="cancelForm">
|
||
@csrf
|
||
|
||
<select class="inp sel" name="reason" id="cancelReason" required>
|
||
<option value="">취소 사유를 선택해 주세요</option>
|
||
<option value="단순 변심">단순 변심</option>
|
||
<option value="상품을 잘못 선택함">상품을 잘못 선택함</option>
|
||
<option value="구매 수량을 잘못 선택함">구매 수량을 잘못 선택함</option>
|
||
<option value="결제 수단을 잘못 선택함">결제 수단을 잘못 선택함</option>
|
||
<option value="중복 결제 시도">중복 결제 시도</option>
|
||
<option value="다른 상품으로 다시 구매 예정">다른 상품으로 다시 구매 예정</option>
|
||
<option value="가격을 다시 확인 후 구매 예정">가격을 다시 확인 후 구매 예정</option>
|
||
<option value="회원 정보 확인 후 다시 진행 예정">회원 정보 확인 후 다시 진행 예정</option>
|
||
<option value="프로모션/혜택 적용 후 재구매 예정">프로모션/혜택 적용 후 재구매 예정</option>
|
||
<option value="기타">기타</option>
|
||
</select>
|
||
|
||
<button id="btnCancel" class="btn btn--danger btn--sm" type="submit">
|
||
결제 취소
|
||
</button>
|
||
</form>
|
||
</div>
|
||
@endif
|
||
@endif
|
||
</div>
|
||
|
||
<div class="pin-auth-modal" id="pinRevealModal" hidden>
|
||
<div class="pin-auth-modal__backdrop" onclick="closePinRevealModal()"></div>
|
||
<div class="pin-auth-modal__dialog" role="dialog" aria-modal="true" aria-labelledby="pinRevealTitle">
|
||
<div class="pin-auth-modal__head">
|
||
<h3 id="pinRevealTitle">핀번호 확인</h3>
|
||
<button type="button" class="pin-auth-modal__close" onclick="closePinRevealModal()">×</button>
|
||
</div>
|
||
|
||
<div class="pin-auth-modal__body">
|
||
<p class="pin-auth-modal__desc">
|
||
전체 핀번호 확인을 위해 2차 비밀번호를 입력해 주세요.
|
||
</p>
|
||
|
||
<form id="pinRevealForm" method="post" action="{{ route('web.mypage.usage.reveal', ['attemptId' => $attemptId]) }}">
|
||
@csrf
|
||
<input
|
||
class="pin-auth-modal__input"
|
||
type="password"
|
||
name="pin2"
|
||
inputmode="numeric"
|
||
pattern="\d{4}"
|
||
maxlength="4"
|
||
autocomplete="off"
|
||
placeholder="2차 비밀번호 4자리"
|
||
>
|
||
|
||
<div class="pin-auth-modal__actions">
|
||
<button type="button" class="issue-run" onclick="closePinRevealModal()">닫기</button>
|
||
<button type="submit" class="issue-run issue-run--dark">핀번호 확인</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
.mypage-usage { display:flex; flex-direction:column; gap:14px; }
|
||
|
||
.topbar{display:flex; align-items:center; gap:10px; flex-wrap:wrap;}
|
||
.topbar .sp{flex:1;}
|
||
|
||
.btn{
|
||
display:inline-flex;align-items:center;justify-content:center;
|
||
padding:10px 12px;border-radius:12px;border:1px solid rgba(0,0,0,.14);
|
||
cursor:pointer;text-decoration:none;font-size:13px; white-space:nowrap;
|
||
}
|
||
.btn--sm{padding:8px 10px;border-radius:10px;font-size:12px;}
|
||
.btn--danger{border-color: rgba(220,0,0,.35); color:rgb(180,0,0); font-weight:800;}
|
||
|
||
.flash{padding:8px 10px;border-radius:10px;font-size:13px;}
|
||
.flash.ok{background:rgba(0,160,60,.08);}
|
||
.flash.err{background:rgba(220,0,0,.08);}
|
||
|
||
.mono{font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;}
|
||
.muted { color:rgba(0,0,0,.55); }
|
||
|
||
.pill{
|
||
display:inline-flex; padding:4px 10px; border-radius:999px; font-size:12px;
|
||
border:1px solid rgba(0,0,0,.12); white-space:nowrap;
|
||
}
|
||
.pill--ok{background:rgba(0,160,60,.08); border-color:rgba(0,160,60,.18);}
|
||
.pill--danger{background:rgba(220,0,0,.08); border-color:rgba(220,0,0,.18); color:rgb(180,0,0);}
|
||
.pill--wait{background:rgba(255,190,0,.12); border-color:rgba(255,190,0,.25);}
|
||
.pill--muted{opacity:.75;}
|
||
|
||
.notice-box { padding:12px; border-radius:12px; background:rgba(0,0,0,.04); margin-top:10px; }
|
||
.notice-box--err { background:rgba(220,0,0,.06); }
|
||
|
||
.detail-hero-grid{
|
||
display:grid;
|
||
grid-template-columns:1fr;
|
||
gap:14px;
|
||
}
|
||
@media (min-width: 960px){
|
||
.detail-hero-grid{
|
||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||
align-items: stretch;
|
||
}
|
||
.detail-hero-grid > * {
|
||
min-width: 0;
|
||
}
|
||
}
|
||
|
||
.right-panel{
|
||
display:block;
|
||
height:100%;
|
||
}
|
||
.right-panel .issue-panel,
|
||
.right-panel .banner-stack,
|
||
.right-panel .promo-vertical-banner{
|
||
height:100%;
|
||
}
|
||
|
||
@media (max-width: 959px){
|
||
.right-panel--mobile-hide{display:none;}
|
||
}
|
||
|
||
.receipt-card{
|
||
border:1px solid rgba(0,0,0,.08);
|
||
border-radius:18px;
|
||
padding:16px;
|
||
background:#fff;
|
||
}
|
||
.receipt-card--paper{
|
||
box-shadow: 0 10px 24px rgba(0,0,0,.04);
|
||
}
|
||
.receipt-head{
|
||
display:flex; justify-content:space-between; align-items:flex-start; gap:10px;
|
||
}
|
||
.receipt-title{font-size:18px; font-weight:900; line-height:1.1;}
|
||
.receipt-sub{margin-top:4px; color:rgba(0,0,0,.55); font-size:12px;}
|
||
|
||
.receipt-divider{
|
||
margin:12px 0;
|
||
border-top:1px solid rgba(0,0,0,.08);
|
||
}
|
||
.receipt-divider--dashed{
|
||
border-top-style:dashed;
|
||
border-top-color:rgba(0,0,0,.16);
|
||
}
|
||
|
||
.receipt-main{display:flex; flex-direction:column; gap:10px;}
|
||
.receipt-product{
|
||
font-size:15px; font-weight:900; line-height:1.35;
|
||
}
|
||
.receipt-item{
|
||
font-size:13px; font-weight:700; color:rgba(0,0,0,.6);
|
||
}
|
||
|
||
.receipt-grid{
|
||
display:grid; grid-template-columns:1fr; gap:8px;
|
||
}
|
||
.receipt-grid .row{
|
||
display:flex; justify-content:space-between; gap:10px; font-size:13px;
|
||
}
|
||
.receipt-grid .k{color:rgba(0,0,0,.55);}
|
||
.receipt-grid .v{font-weight:800; text-align:right;}
|
||
|
||
.receipt-amount{
|
||
display:flex; flex-direction:column; gap:8px;
|
||
padding:12px;
|
||
border-radius:14px;
|
||
background:rgba(0,0,0,.02);
|
||
border:1px solid rgba(0,0,0,.05);
|
||
}
|
||
.amt-row{display:flex; justify-content:space-between; gap:10px; font-size:13px;}
|
||
.amt-row .k{color:rgba(0,0,0,.6);}
|
||
.amt-row .v{font-weight:800;}
|
||
.amt-row.total{
|
||
margin-top:2px;
|
||
padding-top:8px;
|
||
border-top:1px dashed rgba(0,0,0,.14);
|
||
font-size:15px; font-weight:900;
|
||
}
|
||
|
||
.banner-stack{
|
||
display:flex;
|
||
flex-direction:column;
|
||
gap:10px;
|
||
}
|
||
|
||
.info-banner{
|
||
border-radius:18px;
|
||
padding:14px;
|
||
border:1px solid rgba(0,0,0,.08);
|
||
background:#fff;
|
||
box-shadow: 0 8px 20px rgba(0,0,0,.03);
|
||
}
|
||
.info-banner__title{
|
||
font-size:14px; font-weight:900;
|
||
}
|
||
.info-banner__desc{
|
||
margin-top:6px;
|
||
font-size:13px; line-height:1.45;
|
||
color:rgba(0,0,0,.62);
|
||
}
|
||
.info-banner--danger{
|
||
background:linear-gradient(180deg, rgba(220,0,0,.05), rgba(220,0,0,.02));
|
||
border-color:rgba(220,0,0,.14);
|
||
}
|
||
.info-banner--ok{
|
||
background:linear-gradient(180deg, rgba(0,160,60,.07), rgba(0,160,60,.03));
|
||
border-color:rgba(0,160,60,.16);
|
||
}
|
||
.info-banner--warn{
|
||
background:linear-gradient(180deg, rgba(255,190,0,.10), rgba(255,190,0,.04));
|
||
border-color:rgba(255,190,0,.20);
|
||
}
|
||
|
||
.promo-vertical-banner{
|
||
border-radius:20px;
|
||
position:relative;
|
||
overflow:hidden;
|
||
border:1px solid rgba(0,0,0,.08);
|
||
background:
|
||
radial-gradient(120% 80% at 0% 0%, rgba(255,120,120,.16), transparent 55%),
|
||
radial-gradient(90% 70% at 100% 100%, rgba(255,190,0,.16), transparent 55%),
|
||
linear-gradient(180deg, #fff 0%, #fbfbfd 100%);
|
||
box-shadow:
|
||
0 20px 35px rgba(0,0,0,.06),
|
||
0 8px 16px rgba(0,0,0,.03),
|
||
inset 0 1px 0 rgba(255,255,255,.9);
|
||
min-height:100%;
|
||
}
|
||
|
||
.promo-vertical-banner--cancel::before{
|
||
content:'';
|
||
position:absolute;
|
||
inset:0;
|
||
background:
|
||
linear-gradient(135deg, rgba(220,0,0,.04) 0%, transparent 38%),
|
||
linear-gradient(315deg, rgba(255,190,0,.05) 0%, transparent 42%);
|
||
pointer-events:none;
|
||
}
|
||
|
||
.promo-vertical-banner__inner{
|
||
position:relative;
|
||
z-index:1;
|
||
height:100%;
|
||
display:flex;
|
||
flex-direction:column;
|
||
padding:16px;
|
||
gap:10px;
|
||
}
|
||
|
||
.promo-vertical-banner__badge{
|
||
align-self:flex-start;
|
||
font-size:11px;
|
||
font-weight:900;
|
||
letter-spacing:.06em;
|
||
color:#7a1b1b;
|
||
background:rgba(220,0,0,.08);
|
||
border:1px solid rgba(220,0,0,.16);
|
||
border-radius:999px;
|
||
padding:4px 8px;
|
||
}
|
||
|
||
.promo-vertical-banner__eyebrow{
|
||
font-size:12px;
|
||
font-weight:800;
|
||
color:rgba(0,0,0,.45);
|
||
letter-spacing:.03em;
|
||
}
|
||
|
||
.promo-vertical-banner__title{
|
||
font-size:22px;
|
||
line-height:1.15;
|
||
font-weight:900;
|
||
letter-spacing:-0.02em;
|
||
color:#1d1d1f;
|
||
margin-top:2px;
|
||
}
|
||
|
||
.promo-vertical-banner__desc{
|
||
font-size:13px;
|
||
line-height:1.5;
|
||
color:rgba(0,0,0,.62);
|
||
}
|
||
|
||
.promo-vertical-banner__chips{
|
||
display:flex;
|
||
flex-wrap:wrap;
|
||
gap:8px;
|
||
margin-top:2px;
|
||
}
|
||
.promo-vertical-banner__chips .chip{
|
||
display:inline-flex;
|
||
align-items:center;
|
||
justify-content:center;
|
||
padding:6px 10px;
|
||
border-radius:999px;
|
||
font-size:12px;
|
||
font-weight:700;
|
||
background:rgba(255,255,255,.9);
|
||
border:1px solid rgba(0,0,0,.08);
|
||
box-shadow: 0 3px 6px rgba(0,0,0,.03);
|
||
}
|
||
|
||
.promo-vertical-banner__footer{
|
||
margin-top:auto;
|
||
border-top:1px dashed rgba(0,0,0,.10);
|
||
padding-top:10px;
|
||
}
|
||
.promo-vertical-banner__footer-title{
|
||
font-size:12px;
|
||
font-weight:900;
|
||
color:rgba(0,0,0,.75);
|
||
}
|
||
.promo-vertical-banner__footer-desc{
|
||
margin-top:4px;
|
||
font-size:12px;
|
||
line-height:1.45;
|
||
color:rgba(0,0,0,.55);
|
||
}
|
||
|
||
.issue-panel{
|
||
border-radius:20px;
|
||
padding:14px;
|
||
background:
|
||
radial-gradient(1200px 320px at -10% -20%, rgba(0,130,255,.10), transparent 45%),
|
||
radial-gradient(1000px 280px at 110% 120%, rgba(0,160,60,.08), transparent 45%),
|
||
linear-gradient(180deg, rgba(255,255,255,.98), rgba(250,251,253,.98));
|
||
border:1px solid rgba(0,0,0,.08);
|
||
box-shadow:
|
||
0 20px 35px rgba(0,0,0,.06),
|
||
0 6px 14px rgba(0,0,0,.03),
|
||
inset 0 1px 0 rgba(255,255,255,.8);
|
||
}
|
||
|
||
.issue-panel__head{
|
||
display:flex; flex-direction:column; gap:6px;
|
||
margin-bottom:12px;
|
||
}
|
||
.issue-panel__title{
|
||
margin:0; font-size:17px; font-weight:900;
|
||
}
|
||
|
||
.issue-picker{
|
||
display:flex; flex-direction:column; gap:10px;
|
||
}
|
||
|
||
.issue-option{
|
||
border:1px solid rgba(0,0,0,.08);
|
||
border-radius:16px;
|
||
background:linear-gradient(180deg, rgba(255,255,255,1), rgba(248,249,251,1));
|
||
overflow:hidden;
|
||
transition:
|
||
border-color .25s ease,
|
||
box-shadow .25s ease,
|
||
transform .18s ease,
|
||
background .25s ease;
|
||
box-shadow:
|
||
0 6px 12px rgba(0,0,0,.02),
|
||
inset 0 1px 0 rgba(255,255,255,.85);
|
||
position:relative;
|
||
}
|
||
|
||
.issue-option::before{
|
||
content:'';
|
||
position:absolute;
|
||
left:0; top:0; bottom:0;
|
||
width:4px;
|
||
background:rgba(0,0,0,.08);
|
||
transition:opacity .25s ease, background .25s ease;
|
||
opacity:.7;
|
||
}
|
||
|
||
.issue-option:hover{
|
||
border-color:rgba(0,0,0,.14);
|
||
transform:translateY(-1px);
|
||
box-shadow:
|
||
0 12px 18px rgba(0,0,0,.04),
|
||
inset 0 1px 0 rgba(255,255,255,.9);
|
||
}
|
||
|
||
.issue-option.is-active{
|
||
border-color:rgba(0,0,0,.18);
|
||
box-shadow:
|
||
0 18px 24px rgba(0,0,0,.06),
|
||
0 8px 14px rgba(0,0,0,.03),
|
||
inset 0 1px 0 rgba(255,255,255,.95);
|
||
transform:translateY(-1px);
|
||
}
|
||
|
||
.issue-option[data-issue-card="view"]::before{
|
||
background:linear-gradient(180deg, rgba(70,70,70,.85), rgba(20,20,20,.85));
|
||
}
|
||
.issue-option[data-issue-card="sms"]::before{
|
||
background:linear-gradient(180deg, rgba(0,130,255,.95), rgba(0,90,220,.85));
|
||
}
|
||
.issue-option[data-issue-card="sell"]::before{
|
||
background:linear-gradient(180deg, rgba(0,170,95,.95), rgba(0,130,70,.85));
|
||
}
|
||
|
||
.issue-option[data-issue-card="view"].is-active{
|
||
background:linear-gradient(180deg, rgba(0,0,0,.025), rgba(255,255,255,1));
|
||
}
|
||
.issue-option[data-issue-card="sms"].is-active{
|
||
background:linear-gradient(180deg, rgba(0,130,255,.06), rgba(255,255,255,1));
|
||
}
|
||
.issue-option[data-issue-card="sell"].is-active{
|
||
background:linear-gradient(180deg, rgba(0,160,60,.07), rgba(255,255,255,1));
|
||
}
|
||
|
||
.issue-option__toggle{
|
||
width:100%;
|
||
border:0;
|
||
background:transparent;
|
||
text-align:left;
|
||
cursor:pointer;
|
||
padding:12px 14px 12px 16px;
|
||
display:grid;
|
||
grid-template-columns:1fr auto;
|
||
gap:8px;
|
||
}
|
||
|
||
.issue-option__kicker{
|
||
grid-column:1 / 2;
|
||
font-size:11px; font-weight:800;
|
||
color:rgba(0,0,0,.45);
|
||
text-transform:uppercase;
|
||
letter-spacing:.03em;
|
||
}
|
||
.issue-option__title{
|
||
grid-column:1 / 2;
|
||
font-size:15px; font-weight:900; line-height:1.1;
|
||
}
|
||
.issue-option__subtitle{
|
||
grid-column:1 / 2;
|
||
font-size:12px; color:rgba(0,0,0,.58); line-height:1.35;
|
||
}
|
||
.issue-option__chev{
|
||
grid-column:2 / 3;
|
||
grid-row:1 / span 3;
|
||
align-self:center;
|
||
font-size:18px;
|
||
color:rgba(0,0,0,.45);
|
||
transition:transform .25s ease;
|
||
}
|
||
.issue-option.is-active .issue-option__chev{
|
||
transform:rotate(180deg);
|
||
}
|
||
|
||
.issue-option__detail{
|
||
max-height:0;
|
||
opacity:0;
|
||
overflow:hidden;
|
||
transition:max-height .32s ease, opacity .22s ease;
|
||
}
|
||
.issue-option.is-active .issue-option__detail{
|
||
max-height:220px;
|
||
opacity:1;
|
||
}
|
||
.issue-option__detail-inner{
|
||
padding:0 14px 14px 16px;
|
||
border-top:1px dashed rgba(0,0,0,.08);
|
||
}
|
||
.issue-option__detail-text{
|
||
margin:10px 0 12px;
|
||
font-size:13px; line-height:1.45;
|
||
color:rgba(0,0,0,.65);
|
||
}
|
||
|
||
.issue-run{
|
||
display:inline-flex; align-items:center; justify-content:center;
|
||
border:1px solid rgba(0,0,0,.12);
|
||
border-radius:12px;
|
||
background:#fff;
|
||
padding:10px 12px;
|
||
font-size:13px;
|
||
font-weight:800;
|
||
cursor:pointer;
|
||
box-shadow:
|
||
0 6px 12px rgba(0,0,0,.04),
|
||
inset 0 1px 0 rgba(255,255,255,.9);
|
||
}
|
||
.issue-run--dark{
|
||
background:linear-gradient(180deg, rgba(0,0,0,.06), rgba(0,0,0,.03));
|
||
}
|
||
.issue-run--sky{
|
||
background:linear-gradient(180deg, rgba(0,130,255,.10), rgba(0,130,255,.05));
|
||
border-color:rgba(0,130,255,.20);
|
||
}
|
||
.issue-run--green{
|
||
background:linear-gradient(180deg, rgba(0,160,60,.12), rgba(0,160,60,.06));
|
||
border-color:rgba(0,160,60,.18);
|
||
}
|
||
|
||
.usage-card{border:1px solid rgba(0,0,0,.08); border-radius:16px; padding:16px; background:#fff;}
|
||
.section-head{display:flex; flex-direction:column; gap:6px; margin-bottom:10px;}
|
||
.card-title{font-size:16px; margin:0;}
|
||
.sub{font-size:13px;}
|
||
|
||
.cancel-box{padding:14px;}
|
||
.cancel-form{margin-top:10px; display:flex; flex-direction:column; gap:8px; align-items:flex-start;}
|
||
.inp{
|
||
padding:10px 10px; border-radius:12px; border:1px solid rgba(0,0,0,.14);
|
||
background:#fff; font-size:13px; width:100%; max-width:420px;
|
||
}
|
||
|
||
.gift-zone{display:flex;flex-direction:column;gap:14px;}
|
||
.gift-zone__head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;flex-wrap:wrap;}
|
||
.gift-zone__title{margin:0;font-size:18px;font-weight:900;}
|
||
.gift-zone__sub{margin-top:6px;font-size:13px;color:rgba(0,0,0,.58);line-height:1.5;}
|
||
|
||
.gift-badge{
|
||
display:inline-flex;align-items:center;justify-content:center;
|
||
min-height:34px;padding:0 12px;border-radius:999px;
|
||
border:1px solid rgba(0,0,0,.08);background:#fff;font-size:12px;font-weight:800;
|
||
}
|
||
.gift-badge--danger{
|
||
color:#b42318;background:rgba(255,90,90,.08);border-color:rgba(180,35,24,.16);
|
||
}
|
||
.gift-badge--ok{
|
||
color:#067647;background:rgba(18,183,106,.10);border-color:rgba(6,118,71,.16);
|
||
}
|
||
|
||
.gift-list{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;}
|
||
.gift-card{
|
||
position:relative;overflow:hidden;
|
||
border-radius:24px;
|
||
padding:18px;
|
||
background:
|
||
radial-gradient(circle at top right, rgba(255,255,255,.82), rgba(255,255,255,.08) 35%),
|
||
linear-gradient(135deg, #0f172a 0%, #1e293b 44%, #334155 100%);
|
||
color:#fff;
|
||
box-shadow:0 18px 38px rgba(15,23,42,.16);
|
||
}
|
||
.gift-card::after{
|
||
content:"";
|
||
position:absolute;right:-28px;bottom:-28px;width:120px;height:120px;border-radius:50%;
|
||
background:rgba(255,255,255,.08);
|
||
}
|
||
.gift-card__top{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:18px;}
|
||
.gift-card__brand{font-size:12px;font-weight:900;letter-spacing:.18em;opacity:.92;}
|
||
.gift-card__chip{
|
||
padding:6px 10px;border-radius:999px;
|
||
background:rgba(255,255,255,.14);font-size:11px;font-weight:800;
|
||
border:1px solid rgba(255,255,255,.18);
|
||
}
|
||
.gift-card__body{position:relative;z-index:1;display:flex;flex-direction:column;gap:12px;}
|
||
.gift-card__name{font-size:17px;font-weight:900;line-height:1.35;}
|
||
.gift-card__amount{font-size:28px;font-weight:900;letter-spacing:-.02em;}
|
||
.gift-card__pinbox{
|
||
border-radius:18px;padding:14px;
|
||
background:rgba(255,255,255,.1);
|
||
border:1px solid rgba(255,255,255,.18);
|
||
backdrop-filter: blur(8px);
|
||
}
|
||
.gift-card__pinlabel{font-size:11px;letter-spacing:.14em;opacity:.8;margin-bottom:6px;}
|
||
.gift-card__pincode{font-size:18px;font-weight:900;letter-spacing:.08em;word-break:break-all;}
|
||
.gift-card__notice{font-size:12px;line-height:1.55;color:rgba(255,255,255,.82);}
|
||
.gift-actions{display:flex;justify-content:center;margin-top:6px;}
|
||
.gift-open-btn{min-width:260px;}
|
||
|
||
.pin-auth-modal[hidden]{display:none !important;}
|
||
.pin-auth-modal{position:fixed;inset:0;z-index:1000;}
|
||
.pin-auth-modal__backdrop{position:absolute;inset:0;background:rgba(15,23,42,.52);}
|
||
.pin-auth-modal__dialog{
|
||
position:relative;
|
||
width:min(92vw, 420px);
|
||
margin:8vh auto 0;
|
||
background:#fff;border-radius:24px;
|
||
box-shadow:0 24px 60px rgba(15,23,42,.22);
|
||
overflow:hidden;
|
||
}
|
||
.pin-auth-modal__head{
|
||
display:flex;justify-content:space-between;align-items:center;
|
||
padding:18px 18px 0 18px;
|
||
}
|
||
.pin-auth-modal__head h3{margin:0;font-size:18px;}
|
||
.pin-auth-modal__close{
|
||
border:0;background:transparent;font-size:28px;line-height:1;cursor:pointer;color:#111827;
|
||
}
|
||
.pin-auth-modal__body{padding:16px 18px 18px;}
|
||
.pin-auth-modal__desc{margin:0 0 14px;font-size:13px;line-height:1.6;color:rgba(0,0,0,.65);}
|
||
.pin-auth-modal__input{
|
||
width:100%;height:48px;border-radius:14px;border:1px solid rgba(0,0,0,.14);
|
||
padding:0 14px;font-size:15px;background:#fff;
|
||
}
|
||
.pin-auth-modal__actions{display:flex;justify-content:flex-end;gap:8px;margin-top:14px;flex-wrap:wrap;}
|
||
|
||
.cancel-form--inline{
|
||
margin-top:10px;
|
||
display:flex;
|
||
flex-direction:row;
|
||
align-items:center;
|
||
gap:8px;
|
||
flex-wrap:nowrap;
|
||
}
|
||
|
||
.cancel-form--inline .sel{
|
||
flex:1 1 auto;
|
||
min-width:0;
|
||
max-width:none;
|
||
height:40px;
|
||
}
|
||
|
||
.cancel-form--inline .btn{
|
||
flex:0 0 auto;
|
||
height:40px;
|
||
}
|
||
|
||
@media (max-width: 640px){
|
||
.cancel-form--inline{
|
||
flex-direction:column;
|
||
align-items:stretch;
|
||
}
|
||
|
||
.cancel-form--inline .btn{
|
||
width:100%;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
async function copyAllPins() {
|
||
const nodes = Array.from(document.querySelectorAll('[data-pin-value]'));
|
||
const pins = nodes
|
||
.map(el => (el.getAttribute('data-pin-value') || '').trim())
|
||
.filter(v => v !== '');
|
||
|
||
if (!pins.length) {
|
||
await showMsg(
|
||
"복사할 핀번호가 없습니다.",
|
||
{ type: 'alert', title: '안내' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
const text = pins.join('\n');
|
||
|
||
try {
|
||
await navigator.clipboard.writeText(text);
|
||
|
||
await showMsg(
|
||
"전체 핀번호가 복사되었습니다.",
|
||
{ type: 'alert', title: '복사 완료' }
|
||
);
|
||
} catch (e) {
|
||
// clipboard API 실패 시 fallback
|
||
const ta = document.createElement('textarea');
|
||
ta.value = text;
|
||
ta.style.position = 'fixed';
|
||
ta.style.left = '-9999px';
|
||
ta.style.top = '0';
|
||
document.body.appendChild(ta);
|
||
ta.focus();
|
||
ta.select();
|
||
|
||
let ok = false;
|
||
try {
|
||
ok = document.execCommand('copy');
|
||
} catch (_) {
|
||
ok = false;
|
||
}
|
||
|
||
document.body.removeChild(ta);
|
||
|
||
if (ok) {
|
||
await showMsg(
|
||
"전체 핀번호가 복사되었습니다.",
|
||
{ type: 'alert', title: '복사 완료' }
|
||
);
|
||
} else {
|
||
await showMsg(
|
||
"복사에 실패했습니다. 브라우저 권한을 확인해 주세요.",
|
||
{ type: 'alert', title: '복사 실패' }
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
async function onOpenPinsOnce(e) {
|
||
e.preventDefault();
|
||
|
||
const btn = e.currentTarget;
|
||
const form = btn ? btn.closest('form') : null;
|
||
|
||
const ok = await showMsg(
|
||
"핀 확인(오픈) 후에도 핀번호는 기본 마스킹 상태로 유지됩니다.\n\n진행할까요?",
|
||
{ type: 'confirm', title: '핀 오픈' }
|
||
);
|
||
|
||
if (!ok) return;
|
||
if (!form) return;
|
||
|
||
if (form.requestSubmit) form.requestSubmit();
|
||
else form.submit();
|
||
}
|
||
|
||
async function onCancelOnce(e) {
|
||
e.preventDefault();
|
||
|
||
const btn = e.currentTarget;
|
||
const form = btn ? btn.closest('form') : null;
|
||
if (!form) return;
|
||
|
||
const reasonEl = form.querySelector('select[name="reason"]');
|
||
const reason = (reasonEl?.value || '').trim();
|
||
|
||
if (!reason) {
|
||
await showMsg(
|
||
"취소 사유를 먼저 선택해 주세요.",
|
||
{ type: 'alert', title: '취소 사유 선택' }
|
||
);
|
||
reasonEl?.focus();
|
||
return;
|
||
}
|
||
|
||
const ok = await showMsg(
|
||
"선택한 사유로 결제를 취소할까요?\n\n취소 사유: " + reason,
|
||
{ type: 'confirm', title: '결제 취소' }
|
||
);
|
||
|
||
if (!ok) return;
|
||
|
||
if (form.requestSubmit) form.requestSubmit();
|
||
else form.submit();
|
||
}
|
||
|
||
async function onIssuePinInstant(e) {
|
||
e.preventDefault();
|
||
|
||
const btn = e.currentTarget;
|
||
const form = btn ? btn.closest('form') : null;
|
||
|
||
const ok = await showMsg(
|
||
"핀번호를 개인 암호화하여 발행합니다. 핀번호 유출에 주의하세요.",
|
||
{ type: 'confirm', title: '핀발행' }
|
||
);
|
||
|
||
if (!ok || !form) return;
|
||
|
||
if (form.requestSubmit) form.requestSubmit();
|
||
else form.submit();
|
||
}
|
||
|
||
async function onIssueSmsSoon() {
|
||
await showMsg(
|
||
"준비중입니다.\n\nSMS 발송 시 핀번호는 저장되지 않습니다. 문자 수신 후 즉시 확인하세요.",
|
||
{ type: 'alert', title: '안내' }
|
||
);
|
||
}
|
||
|
||
async function onIssueSellSoon() {
|
||
await showMsg(
|
||
"준비중입니다.\n\n구매하신 상품권을 판매합니다.\n계좌번호가 등록되어 있어야 합니다.\n매입 처리는 약간의 시간이 걸릴 수 있으며, 완료 후 회원님 계좌로 입금됩니다.",
|
||
{ type: 'alert', title: '안내' }
|
||
);
|
||
}
|
||
|
||
function openPinRevealModal() {
|
||
const modal = document.getElementById('pinRevealModal');
|
||
if (!modal) return;
|
||
modal.hidden = false;
|
||
|
||
const input = modal.querySelector('input[name="pin2"]');
|
||
setTimeout(() => input && input.focus(), 30);
|
||
}
|
||
|
||
function closePinRevealModal() {
|
||
const modal = document.getElementById('pinRevealModal');
|
||
if (!modal) return;
|
||
modal.hidden = true;
|
||
|
||
const input = modal.querySelector('input[name="pin2"]');
|
||
if (input) input.value = '';
|
||
}
|
||
|
||
document.addEventListener('keydown', function (e) {
|
||
if (e.key === 'Escape') closePinRevealModal();
|
||
});
|
||
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
const btnOpen = document.getElementById('btnOpenPins');
|
||
if (btnOpen) btnOpen.addEventListener('click', onOpenPinsOnce);
|
||
|
||
const btnCancel = document.getElementById('btnCancel');
|
||
if (btnCancel) btnCancel.addEventListener('click', onCancelOnce);
|
||
|
||
const btnPinInstant = document.getElementById('btnIssuePinInstant');
|
||
if (btnPinInstant) btnPinInstant.addEventListener('click', onIssuePinInstant);
|
||
|
||
const btn2 = document.getElementById('btnIssueSms');
|
||
if (btn2) btn2.addEventListener('click', onIssueSmsSoon);
|
||
|
||
const btn3 = document.getElementById('btnIssueSell');
|
||
if (btn3) btn3.addEventListener('click', onIssueSellSoon);
|
||
|
||
const btnCopyPins = document.getElementById('btnCopyPins');
|
||
if (btnCopyPins) {
|
||
btnCopyPins.addEventListener('click', copyAllPins);
|
||
}
|
||
|
||
const issueCards = Array.from(document.querySelectorAll('[data-issue-card]'));
|
||
issueCards.forEach((card) => {
|
||
const toggle = card.querySelector('[data-issue-toggle]');
|
||
if (!toggle) return;
|
||
|
||
toggle.addEventListener('click', () => {
|
||
const isActive = card.classList.contains('is-active');
|
||
issueCards.forEach(c => c.classList.remove('is-active'));
|
||
if (!isActive) {
|
||
card.classList.add('is-active');
|
||
}
|
||
});
|
||
});
|
||
});
|
||
</script>
|
||
@endsection
|