Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/main/resources/static/order.css
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,28 @@

#cancel-button:hover {
background-color: #c82333;
}

.loading-spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #1b64da;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 1s linear infinite;
margin: 20px auto;
}

@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

/* 초기에는 로딩만 표시 */
#loading-section {
display: block;
}

#success-section {
display: none;
}
96 changes: 70 additions & 26 deletions src/main/resources/static/payment-success.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,73 @@
<link rel="stylesheet" type="text/css" href="style.css" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>결제 성공</title>
<title>결제 처리중</title>
<style>
.loading-spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #1b64da;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 1s linear infinite;
margin: 20px auto;
}

@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

/* 초기에는 로딩만 표시 */
#loading-section {
display: block;
}

#success-section {
display: none;
}
</style>
</head>
<body>
<div class="box_section" style="width: 600px">
<img width="100px" src="https://static.toss.im/illusts/check-blue-spot-ending-frame.png" />
<h2>결제를 완료했어요</h2>

<div class="p-grid" style="margin-top: 30px">
<button class="button p-grid-col5" onclick="location.href='https://docs.tosspayments.com/guides/v2/payment-widget/integration';">연동 문서</button>
<button class="button p-grid-col5" onclick="location.href='https://discord.gg/A4fRFXQhRu';" style="background-color: #e8f3ff; color: #1b64da">실시간 문의</button>
<div id="loading-section">
<div class="box_section" style="width: 600px; text-align: center;">
<div class="loading-spinner"></div>
<h2>결제를 처리하고 있어요</h2>
<p style="color: #666; margin-top: 10px;">잠시만 기다려주세요...</p>
</div>
<div class="p-grid typography--p" style="margin-top: 50px">
<div class="p-grid-col text--left"><b>결제금액</b></div>
<div class="p-grid-col text--right" id="amount"></div>
</div>
<div class="p-grid typography--p" style="margin-top: 10px">
<div class="p-grid-col text--left"><b>주문번호</b></div>
<div class="p-grid-col text--right" id="orderId"></div>
</div>

<!-- ✅ 성공 화면 (API 성공 후 표시) -->
<div id="success-section">
<div class="box_section" style="width: 600px">
<img width="100px" src="https://static.toss.im/illusts/check-blue-spot-ending-frame.png" />
<h2>결제를 완료했어요</h2>

<div class="p-grid" style="margin-top: 30px">
<button class="button p-grid-col5" onclick="location.href='https://docs.tosspayments.com/guides/v2/payment-widget/integration';">연동 문서</button>
<button class="button p-grid-col5" onclick="location.href='https://discord.gg/A4fRFXQhRu';" style="background-color: #e8f3ff; color: #1b64da">실시간 문의</button>
</div>
<div class="p-grid typography--p" style="margin-top: 50px">
<div class="p-grid-col text--left"><b>결제금액</b></div>
<div class="p-grid-col text--right" id="amount"></div>
</div>
<div class="p-grid typography--p" style="margin-top: 10px">
<div class="p-grid-col text--left"><b>주문번호</b></div>
<div class="p-grid-col text--right" id="orderId"></div>
</div>
<div class="p-grid typography--p" style="margin-top: 10px">
<div class="p-grid-col text--left"><b>paymentKey</b></div>
<div class="p-grid-col text--right" id="paymentKey" style="white-space: initial; width: 250px"></div>
</div>
</div>
<div class="p-grid typography--p" style="margin-top: 10px">
<div class="p-grid-col text--left"><b>paymentKey</b></div>
<div class="p-grid-col text--right" id="paymentKey" style="white-space: initial; width: 250px"></div>

<div class="box_section" style="width: 600px; text-align: left">
<b>Response Data :</b>
<div id="response" style="white-space: initial"></div>
</div>
</div>

<div class="box_section" style="width: 600px; text-align: left">
<b>Response Data :</b>
<div id="response" style="white-space: initial"></div>
</div>
<script>
// 쿼리 파라미터 값이 결제 요청할 때 보낸 데이터와 동일한지 반드시 확인
// 클라이언트에서 결제 금액을 조작하는 행위를 방지할 수 있음
Expand All @@ -51,8 +89,11 @@ <h2>결제를 완료했어요</h2>
const accessToken = sessionStorage.getItem('paymentAccessToken');

if (!accessToken) {
alert('인증 토큰이 없습니다. 다시 시도해주세요.');
window.location.href = '/payment-test.html';
const params = new URLSearchParams({
message: "인증 토큰이 없습니다. 다시 시도해주세요.",
code: "NO_AUTH_TOKEN"
});
window.location.href = `/payment-fail.html?${params.toString()}`;
return;
}

Expand All @@ -72,20 +113,23 @@ <h2>결제를 완료했어요</h2>
const errorMessage = json.message || "결제 승인에 실패했습니다.";
const errorCode = json.code || "UNKNOWN_ERROR";

alert("결제 승인 실패: " + errorMessage);

const params = new URLSearchParams({
message: errorMessage,
code: errorCode
});

window.location.href = `/payment-fail.html?${params.toString()}`;

return;
}

sessionStorage.removeItem('paymentAccessToken');
document.getElementById("loading-section").style.display = "none";
document.getElementById("success-section").style.display = "block";

document.getElementById("response").innerHTML = `<pre>${JSON.stringify(json, null, 4)}</pre>`;
document.getElementById("orderId").textContent = urlParams.get("orderId");
document.getElementById("amount").textContent = urlParams.get("amount") + "원";
document.getElementById("paymentKey").textContent = urlParams.get("paymentKey");
document.getElementById("response").innerHTML = `<pre>${JSON.stringify(json, null, 4)}</pre>`;

if (json.paymentId) {
Expand Down
12 changes: 11 additions & 1 deletion src/main/resources/static/payment-test.html
Original file line number Diff line number Diff line change
Expand Up @@ -255,14 +255,16 @@ <h2 style="color: #666;">주문 처리 완료</h2>
await loadPaymentInfo(data.orderId);
}
// CANCELLED, REFUNDED 등: 안내 메시지만 표시
else if (['PENDING_PAYMENT ', 'CANCELLED', 'REFUNDED', 'RETURN_REQUESTED', 'RETURNED', 'REFUND_REQUESTED'].includes(orderStatus)) {
else if (['PAYMENT_FAILED', 'CANCELLED', 'REFUNDED', 'RETURN_REQUESTED', 'RETURNED', 'REFUND_REQUESTED'].includes(orderStatus)) {
cannotActionArea.style.display = 'block';
const messageElement = document.getElementById('cannot-action-message');

if (orderStatus === 'CANCELLED') {
messageElement.textContent = '이 주문은 취소되었습니다.';
} else if (orderStatus === 'REFUNDED') {
messageElement.textContent = '이 주문은 환불 완료되었습니다.';
} else if (orderStatus === 'PAYMENT_FAILED') {
messageElement.textContent = '이 주문은 결제에 실패해 환불되었습니다 다시 주문해주세요.';
} else {
messageElement.textContent = `주문 상태: ${data.orderStatusDescription}`;
}
Expand Down Expand Up @@ -474,6 +476,10 @@ <h2 style="color: #666;">주문 처리 완료</h2>
button.onclick = null; // 기존 이벤트 제거
button.addEventListener("click", async function () {
try {
button.disabled = true;
button.textContent = "처리중...";
button.style.backgroundColor = "#ccc";
button.style.cursor = "not-allowed";

const accessToken = document.getElementById('accessToken').value.trim();
sessionStorage.setItem('paymentAccessToken', accessToken);
Expand All @@ -489,6 +495,10 @@ <h2 style="color: #666;">주문 처리 완료</h2>
});
} catch (error) {
console.error("결제 요청 실패:", error);
button.disabled = false;
button.textContent = "결제하기";
button.style.backgroundColor = "";
button.style.cursor = "pointer";
alert("결제 요청을 취소하였습니다.");
}
});
Expand Down
Loading