[accelerator] reference counting for checkout lock

This commit is contained in:
Mononaut 2024-12-22 12:27:29 +00:00
parent ba1ee15286
commit 464fabf137
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
2 changed files with 26 additions and 13 deletions

View File

@ -1,4 +1,4 @@
<div class="box card w-100 accelerate-checkout-inner" [class.input-disabled]="checkoutLocked" style="background: var(--box-bg)" id=acceleratePreviewAnchor> <div class="box card w-100 accelerate-checkout-inner" [class.input-disabled]="isCheckoutLocked > 0" style="background: var(--box-bg)" id=acceleratePreviewAnchor>
@if (accelerateError) { @if (accelerateError) {
<div class="row mb-1 text-center"> <div class="row mb-1 text-center">
<div class="col-sm"> <div class="col-sm">
@ -484,7 +484,7 @@
</div> </div>
} }
</div> </div>
@if (tokenizing) { @if (isTokenizing > 0) {
<div class="d-flex flex-row justify-content-center"> <div class="d-flex flex-row justify-content-center">
<div class="ml-2 spinner-border text-light" style="width: 25px; height: 25px"></div> <div class="ml-2 spinner-border text-light" style="width: 25px; height: 25px"></div>
</div> </div>

View File

@ -76,8 +76,8 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
calculating = true; calculating = true;
processing = false; processing = false;
checkoutLocked = false; isCheckoutLocked = 0; // reference counter, 0 = unlocked, >0 = locked
tokenizing = false; isTokenizing = 0; // reference counter, 0 = false, >0 = true
selectedOption: 'wait' | 'accel'; selectedOption: 'wait' | 'accel';
cantPayReason = ''; cantPayReason = '';
quoteError = ''; // error fetching estimate or initial data quoteError = ''; // error fetching estimate or initial data
@ -508,8 +508,8 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
event.preventDefault(); event.preventDefault();
try { try {
// lock the checkout UI and show a loading spinner until the square modals are finished // lock the checkout UI and show a loading spinner until the square modals are finished
this.checkoutLocked = true; this.isCheckoutLocked++;
this.tokenizing = true; this.isTokenizing++;
const tokenResult = await this.applePay.tokenize(); const tokenResult = await this.applePay.tokenize();
if (tokenResult?.status === 'OK') { if (tokenResult?.status === 'OK') {
const card = tokenResult.details?.card; const card = tokenResult.details?.card;
@ -520,6 +520,9 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
return; return;
} }
const cardTag = md5(`${card.brand}${card.expMonth}${card.expYear}${card.last4}`.toLowerCase()); const cardTag = md5(`${card.brand}${card.expMonth}${card.expYear}${card.last4}`.toLowerCase());
// keep checkout in loading state until the acceleration request completes
this.isTokenizing++;
this.isCheckoutLocked++;
this.servicesApiService.accelerateWithApplePay$( this.servicesApiService.accelerateWithApplePay$(
this.tx.txid, this.tx.txid,
tokenResult.token, tokenResult.token,
@ -535,12 +538,16 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
this.applePay.destroy(); this.applePay.destroy();
} }
setTimeout(() => { setTimeout(() => {
this.isTokenizing--;
this.isCheckoutLocked--;
this.moveToStep('paid'); this.moveToStep('paid');
}, 1000); }, 1000);
}, },
error: (response) => { error: (response) => {
this.processing = false; this.processing = false;
this.accelerateError = response.error; this.accelerateError = response.error;
this.isTokenizing--;
this.isCheckoutLocked--;
if (!(response.status === 403 && response.error === 'not_available')) { if (!(response.status === 403 && response.error === 'not_available')) {
setTimeout(() => { setTimeout(() => {
// Reset everything by reloading the page :D, can be improved // Reset everything by reloading the page :D, can be improved
@ -562,8 +569,8 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
} }
} finally { } finally {
// always unlock the checkout once we're finished // always unlock the checkout once we're finished
this.tokenizing = false; this.isTokenizing--;
this.checkoutLocked = false; this.isCheckoutLocked--;
} }
}); });
} catch (e) { } catch (e) {
@ -616,10 +623,9 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
event.preventDefault(); event.preventDefault();
try { try {
// lock the checkout UI and show a loading spinner until the square modals are finished // lock the checkout UI and show a loading spinner until the square modals are finished
this.checkoutLocked = true; this.isCheckoutLocked++;
this.tokenizing = true; this.isTokenizing++;
const tokenResult = await this.googlePay.tokenize(); const tokenResult = await this.googlePay.tokenize();
tokenResult.token = 'ccof:customer-card-id-requires-verification';
if (tokenResult?.status === 'OK') { if (tokenResult?.status === 'OK') {
const card = tokenResult.details?.card; const card = tokenResult.details?.card;
if (!card || !card.brand || !card.expMonth || !card.expYear || !card.last4) { if (!card || !card.brand || !card.expMonth || !card.expYear || !card.last4) {
@ -636,6 +642,9 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
return; return;
} }
const cardTag = md5(`${card.brand}${card.expMonth}${card.expYear}${card.last4}`.toLowerCase()); const cardTag = md5(`${card.brand}${card.expMonth}${card.expYear}${card.last4}`.toLowerCase());
// keep checkout in loading state until the acceleration request completes
this.isCheckoutLocked++;
this.isTokenizing++;
this.servicesApiService.accelerateWithGooglePay$( this.servicesApiService.accelerateWithGooglePay$(
this.tx.txid, this.tx.txid,
tokenResult.token, tokenResult.token,
@ -646,6 +655,8 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
).subscribe({ ).subscribe({
next: () => { next: () => {
this.processing = false; this.processing = false;
this.isTokenizing--;
this.isCheckoutLocked--;
this.apiService.logAccelerationRequest$(this.tx.txid).subscribe(); this.apiService.logAccelerationRequest$(this.tx.txid).subscribe();
this.audioService.playSound('ascend-chime-cartoon'); this.audioService.playSound('ascend-chime-cartoon');
if (this.googlePay) { if (this.googlePay) {
@ -658,6 +669,8 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
error: (response) => { error: (response) => {
this.processing = false; this.processing = false;
this.accelerateError = response.error; this.accelerateError = response.error;
this.isTokenizing--;
this.isCheckoutLocked--;
if (!(response.status === 403 && response.error === 'not_available')) { if (!(response.status === 403 && response.error === 'not_available')) {
setTimeout(() => { setTimeout(() => {
// Reset everything by reloading the page :D, can be improved // Reset everything by reloading the page :D, can be improved
@ -679,8 +692,8 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
} }
} finally { } finally {
// always unlock the checkout once we're finished // always unlock the checkout once we're finished
this.tokenizing = false; this.isTokenizing--;
this.checkoutLocked = false; this.isCheckoutLocked--;
} }
}); });
} }