feat(checkout): enhance countdown synchronization and cleanup logic
This commit is contained in:
@@ -54,4 +54,16 @@ describe('CheckoutCountdownService', () => {
|
|||||||
|
|
||||||
expect(service.remainingSeconds()).toBeNull();
|
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();
|
readonly remainingSeconds = this.remainingSecondsState.asReadonly();
|
||||||
|
|
||||||
synchronize(timing: CheckoutTiming): void {
|
synchronize(timing: Partial<CheckoutTiming>): void {
|
||||||
const remainingSeconds = this.resolveRemainingSeconds(timing);
|
const remainingSeconds = this.resolveRemainingSeconds(timing);
|
||||||
|
|
||||||
|
if (remainingSeconds === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (remainingSeconds === null) {
|
if (remainingSeconds === null) {
|
||||||
this.clear();
|
this.clear();
|
||||||
return;
|
return;
|
||||||
@@ -43,9 +47,15 @@ export class CheckoutCountdownService implements OnDestroy {
|
|||||||
this.clear();
|
this.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private resolveRemainingSeconds(timing: CheckoutTiming): number | null {
|
private resolveRemainingSeconds(timing: Partial<CheckoutTiming>): number | null | undefined {
|
||||||
const expiresAt = timing.expires_at ? Date.parse(timing.expires_at) : Number.NaN;
|
if (timing.expires_at === null && timing.expires_in_seconds === null) {
|
||||||
const serverTime = Date.parse(timing.server_time);
|
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)) {
|
if (Number.isFinite(expiresAt) && Number.isFinite(serverTime)) {
|
||||||
return Math.max(0, Math.ceil((expiresAt - serverTime) / 1_000));
|
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 Math.max(0, Math.ceil((expiresAt - Date.now()) / 1_000));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateRemainingSeconds(): void {
|
private updateRemainingSeconds(): void {
|
||||||
|
|||||||
@@ -177,7 +177,6 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.stopQrPolling();
|
this.stopQrPolling();
|
||||||
this.stopTransferPolling();
|
this.stopTransferPolling();
|
||||||
this.checkoutCountdownService.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapPurchaseItemToMock(item: PurchaseDetailItemResponse): CartItemMock {
|
private mapPurchaseItemToMock(item: PurchaseDetailItemResponse): CartItemMock {
|
||||||
@@ -287,6 +286,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
const tenant = this.tenantService.tenant();
|
const tenant = this.tenantService.tenant();
|
||||||
const purchaseId = this.createdPurchaseId();
|
const purchaseId = this.createdPurchaseId();
|
||||||
if (!tenant || !purchaseId) {
|
if (!tenant || !purchaseId) {
|
||||||
|
this.checkoutCountdownService.clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,6 +297,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
await firstValueFrom(this.cartService.loadCart());
|
await firstValueFrom(this.cartService.loadCart());
|
||||||
this.createdPurchaseId.set(null);
|
this.createdPurchaseId.set(null);
|
||||||
this.createdPurchase.set(null);
|
this.createdPurchase.set(null);
|
||||||
|
this.checkoutCountdownService.clear();
|
||||||
|
|
||||||
this.navigationStarted = true;
|
this.navigationStarted = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -310,6 +311,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
this.createdPurchaseId.set(null);
|
this.createdPurchaseId.set(null);
|
||||||
this.createdPurchase.set(null);
|
this.createdPurchase.set(null);
|
||||||
|
this.checkoutCountdownService.clear();
|
||||||
this.navigationStarted = true;
|
this.navigationStarted = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -671,6 +673,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
this.navigationStarted = true;
|
this.navigationStarted = true;
|
||||||
this.stopQrPolling();
|
this.stopQrPolling();
|
||||||
this.stopTransferPolling();
|
this.stopTransferPolling();
|
||||||
|
this.checkoutCountdownService.clear();
|
||||||
|
|
||||||
void this.router.navigate(['/checkout/status', purchaseId]);
|
void this.router.navigate(['/checkout/status', purchaseId]);
|
||||||
}
|
}
|
||||||
@@ -792,6 +795,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
this.navigationStarted = true;
|
this.navigationStarted = true;
|
||||||
this.stopQrPolling();
|
this.stopQrPolling();
|
||||||
this.stopTransferPolling();
|
this.stopTransferPolling();
|
||||||
|
this.checkoutCountdownService.clear();
|
||||||
void this.router.navigate(['/checkout/status', purchaseId], {
|
void this.router.navigate(['/checkout/status', purchaseId], {
|
||||||
queryParams: { status: 'expired' },
|
queryParams: { status: 'expired' },
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user