feat(checkout): enhance countdown synchronization and cleanup logic
This commit is contained in:
parent
51d051733c
commit
b6a52ceb8c
|
|
@ -54,4 +54,16 @@ describe('CheckoutCountdownService', () => {
|
|||
|
||||
expect(service.remainingSeconds()).toBeNull();
|
||||
});
|
||||
|
||||
it('keeps the active countdown when a partial checkout response omits timing fields', () => {
|
||||
service.synchronize({
|
||||
expires_at: null,
|
||||
expires_in_seconds: 10,
|
||||
server_time: '2026-08-27T15:00:00.000Z',
|
||||
});
|
||||
|
||||
service.synchronize({});
|
||||
|
||||
expect(service.remainingSeconds()).toBe(10);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,9 +16,13 @@ export class CheckoutCountdownService implements OnDestroy {
|
|||
|
||||
readonly remainingSeconds = this.remainingSecondsState.asReadonly();
|
||||
|
||||
synchronize(timing: CheckoutTiming): void {
|
||||
synchronize(timing: Partial<CheckoutTiming>): void {
|
||||
const remainingSeconds = this.resolveRemainingSeconds(timing);
|
||||
|
||||
if (remainingSeconds === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (remainingSeconds === null) {
|
||||
this.clear();
|
||||
return;
|
||||
|
|
@ -43,9 +47,15 @@ export class CheckoutCountdownService implements OnDestroy {
|
|||
this.clear();
|
||||
}
|
||||
|
||||
private resolveRemainingSeconds(timing: CheckoutTiming): number | null {
|
||||
const expiresAt = timing.expires_at ? Date.parse(timing.expires_at) : Number.NaN;
|
||||
const serverTime = Date.parse(timing.server_time);
|
||||
private resolveRemainingSeconds(timing: Partial<CheckoutTiming>): number | null | undefined {
|
||||
if (timing.expires_at === null && timing.expires_in_seconds === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const expiresAt =
|
||||
typeof timing.expires_at === 'string' ? Date.parse(timing.expires_at) : Number.NaN;
|
||||
const serverTime =
|
||||
typeof timing.server_time === 'string' ? Date.parse(timing.server_time) : Number.NaN;
|
||||
|
||||
if (Number.isFinite(expiresAt) && Number.isFinite(serverTime)) {
|
||||
return Math.max(0, Math.ceil((expiresAt - serverTime) / 1_000));
|
||||
|
|
@ -62,7 +72,7 @@ export class CheckoutCountdownService implements OnDestroy {
|
|||
return Math.max(0, Math.ceil((expiresAt - Date.now()) / 1_000));
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private updateRemainingSeconds(): void {
|
||||
|
|
|
|||
|
|
@ -177,7 +177,6 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||
ngOnDestroy(): void {
|
||||
this.stopQrPolling();
|
||||
this.stopTransferPolling();
|
||||
this.checkoutCountdownService.clear();
|
||||
}
|
||||
|
||||
private mapPurchaseItemToMock(item: PurchaseDetailItemResponse): CartItemMock {
|
||||
|
|
@ -287,6 +286,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||
const tenant = this.tenantService.tenant();
|
||||
const purchaseId = this.createdPurchaseId();
|
||||
if (!tenant || !purchaseId) {
|
||||
this.checkoutCountdownService.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -297,6 +297,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||
await firstValueFrom(this.cartService.loadCart());
|
||||
this.createdPurchaseId.set(null);
|
||||
this.createdPurchase.set(null);
|
||||
this.checkoutCountdownService.clear();
|
||||
|
||||
this.navigationStarted = true;
|
||||
return true;
|
||||
|
|
@ -310,6 +311,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
this.createdPurchaseId.set(null);
|
||||
this.createdPurchase.set(null);
|
||||
this.checkoutCountdownService.clear();
|
||||
this.navigationStarted = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -671,6 +673,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||
this.navigationStarted = true;
|
||||
this.stopQrPolling();
|
||||
this.stopTransferPolling();
|
||||
this.checkoutCountdownService.clear();
|
||||
|
||||
void this.router.navigate(['/checkout/status', purchaseId]);
|
||||
}
|
||||
|
|
@ -792,6 +795,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||
this.navigationStarted = true;
|
||||
this.stopQrPolling();
|
||||
this.stopTransferPolling();
|
||||
this.checkoutCountdownService.clear();
|
||||
void this.router.navigate(['/checkout/status', purchaseId], {
|
||||
queryParams: { status: 'expired' },
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue