|
142 | 142 | font-size: .75rem; |
143 | 143 | } |
144 | 144 |
|
| 145 | + .makepay-checkout .makepay-payment-received { |
| 146 | + width: 100%; |
| 147 | + max-width: 28rem; |
| 148 | + margin: 0 auto; |
| 149 | + padding: 2rem 1rem; |
| 150 | + } |
| 151 | +
|
| 152 | + .makepay-checkout .makepay-payment-received-icon { |
| 153 | + display: inline-flex; |
| 154 | + align-items: center; |
| 155 | + justify-content: center; |
| 156 | + width: 4rem; |
| 157 | + height: 4rem; |
| 158 | + margin-bottom: 1rem; |
| 159 | + border-radius: 50%; |
| 160 | + background: var(--btcpay-success-dim-bg, rgba(60, 153, 110, .18)); |
| 161 | + color: var(--btcpay-success, #3c996e); |
| 162 | + } |
| 163 | +
|
| 164 | + .makepay-checkout .makepay-payment-received-icon svg { |
| 165 | + width: 2rem; |
| 166 | + height: 2rem; |
| 167 | + } |
| 168 | +
|
145 | 169 | @@media (max-width: 420px) { |
146 | 170 | .makepay-checkout .makepay-option > span { |
147 | 171 | grid-template-columns: 2.5rem minmax(0, 1fr); |
|
382 | 406 | </div> |
383 | 407 | </div> |
384 | 408 |
|
| 409 | + <div v-else-if="paymentStarted && isPaymentReceived" |
| 410 | + class="makepay-payment-received text-center" |
| 411 | + role="status" |
| 412 | + aria-live="polite"> |
| 413 | + <span class="makepay-payment-received-icon" aria-hidden="true"> |
| 414 | + <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 415 | + <path d="M5 12.5l4.25 4.25L19 7" |
| 416 | + stroke="currentColor" |
| 417 | + stroke-width="2.5" |
| 418 | + stroke-linecap="round" |
| 419 | + stroke-linejoin="round"></path> |
| 420 | + </svg> |
| 421 | + </span> |
| 422 | + <div class="h4 mb-2">{{ paymentReceivedTitle }}</div> |
| 423 | + <p class="text-muted mb-0">{{ paymentReceivedMessage }}</p> |
| 424 | + </div> |
| 425 | + |
385 | 426 | <div v-else-if="paymentStarted && isCashAppPayment" |
386 | 427 | class="makepay-cash-app-transfer text-center"> |
387 | 428 | <div class="makepay-cash-app-summary justify-content-center mb-3"> |
|
452 | 493 | </button> |
453 | 494 | </div> |
454 | 495 |
|
455 | | - <div v-if="status && !isCashAppPayment" class="mt-3 small text-muted text-center"> |
456 | | - Status: {{ status }} |
| 496 | + <div v-if="status && !isCashAppPayment && !isPaymentReceived" |
| 497 | + class="mt-3 small text-muted text-center" |
| 498 | + role="status" |
| 499 | + aria-live="polite"> |
| 500 | + {{ checkoutStatusLabel }} |
457 | 501 | </div> |
458 | 502 |
|
459 | 503 | <div v-if="isBusy" class="text-center py-3"> |
|
499 | 543 | cashAppPaymentRequest: '', |
500 | 544 | paymentExpiresAtMs: 0, |
501 | 545 | status: '', |
| 546 | + paymentReceived: false, |
502 | 547 | error: '', |
503 | 548 | success: '', |
504 | 549 | isBusy: false, |
|
615 | 660 | }; |
616 | 661 | return labels[this.status] || 'Waiting for payment'; |
617 | 662 | }, |
| 663 | + isPaymentReceived: function () { |
| 664 | + return this.paymentReceived || |
| 665 | + ['deposit_received', 'swapping', 'sending', 'complete'] |
| 666 | + .indexOf(this.status) >= 0; |
| 667 | + }, |
| 668 | + paymentReceivedTitle: function () { |
| 669 | + if (['expired', 'failed', 'cancelled', 'refunded'].indexOf(this.status) >= 0) { |
| 670 | + return 'Payment needs attention'; |
| 671 | + } |
| 672 | +
|
| 673 | + return this.status === 'complete' |
| 674 | + ? 'Payment complete' |
| 675 | + : 'Payment received'; |
| 676 | + }, |
| 677 | + paymentReceivedMessage: function () { |
| 678 | + if (['expired', 'failed', 'cancelled', 'refunded'].indexOf(this.status) >= 0) { |
| 679 | + return 'We received your transfer, but could not finish processing it. Do not send another payment to this address. Please contact the merchant for help.'; |
| 680 | + } |
| 681 | +
|
| 682 | + return this.status === 'complete' |
| 683 | + ? 'Thank you. This invoice is paid and you can safely close this window.' |
| 684 | + : 'Thank you. We received your payment and are finalizing the invoice. This page will update automatically.'; |
| 685 | + }, |
| 686 | + checkoutStatusLabel: function () { |
| 687 | + var labels = { |
| 688 | + quoted: 'Quote ready', |
| 689 | + awaiting_deposit: 'Waiting for payment', |
| 690 | + pending: 'Waiting for payment', |
| 691 | + deposit_received: 'Payment received', |
| 692 | + swapping: 'Processing payment', |
| 693 | + sending: 'Processing payment', |
| 694 | + complete: 'Payment complete', |
| 695 | + expired: 'Payment expired', |
| 696 | + failed: 'Payment failed', |
| 697 | + cancelled: 'Payment cancelled' |
| 698 | + }; |
| 699 | + return labels[this.status] || 'Checking payment status'; |
| 700 | + }, |
618 | 701 | refundAddressMode: function () { |
619 | 702 | return this.model.makePayRefundAddressMode === 'payer_entered' |
620 | 703 | ? 'payer_entered' |
|
1116 | 1199 | this.cashAppPaymentRequest = ''; |
1117 | 1200 | this.paymentExpiresAtMs = 0; |
1118 | 1201 | this.status = ''; |
| 1202 | + this.paymentReceived = false; |
1119 | 1203 | this.error = ''; |
1120 | 1204 | this.success = ''; |
1121 | 1205 | this.awaitingConfirmation = false; |
|
1363 | 1447 | this.selectedAsset = String(payload.selectedSellAsset); |
1364 | 1448 | this.syncSelectedCurrencyFromAsset(); |
1365 | 1449 | } |
1366 | | - this.status = payload.status || this.status; |
| 1450 | + var nextStatus = payload.status || this.status; |
| 1451 | + if (['deposit_received', 'swapping', 'sending', 'complete'].indexOf(nextStatus) >= 0) { |
| 1452 | + // Once the payer transfer is observed, never expose payment |
| 1453 | + // instructions again because of a weaker tracking response. |
| 1454 | + this.paymentReceived = true; |
| 1455 | + } |
| 1456 | + this.status = nextStatus; |
1367 | 1457 | this.applyQuotedAmounts(payload); |
1368 | 1458 | this.paymentExpiresAtMs = this.parseDateMs(payload.expiresAt) || this.paymentExpiresAtMs; |
1369 | 1459 | if (payload.deposit) { |
|
0 commit comments