feat(checkout): improve error handling for expired purchases and refactor toast service usage
This commit is contained in:
@@ -14,7 +14,6 @@ import { GlobalLoadingService } from '../../../../core/services/global-loading/g
|
|||||||
import { TenantService } from '../../../../core/services/tenant.service';
|
import { TenantService } from '../../../../core/services/tenant.service';
|
||||||
import { ToastService } from '../../../../core/services/toast.service';
|
import { ToastService } from '../../../../core/services/toast.service';
|
||||||
import { CartEditingPolicy } from '../../../../core/services/tenant.interface';
|
import { CartEditingPolicy } from '../../../../core/services/tenant.interface';
|
||||||
import { ToastService } from '../../../../core/services/toast.service';
|
|
||||||
import { CheckoutPageComponent } from './checkout-page.component';
|
import { CheckoutPageComponent } from './checkout-page.component';
|
||||||
|
|
||||||
describe('CheckoutPageComponent payment validation', () => {
|
describe('CheckoutPageComponent payment validation', () => {
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
private readonly globalLoadingService = inject(GlobalLoadingService);
|
private readonly globalLoadingService = inject(GlobalLoadingService);
|
||||||
private readonly toastService = inject(ToastService);
|
private readonly toastService = inject(ToastService);
|
||||||
private readonly qrPollingIntervalMs = 5_000;
|
private readonly qrPollingIntervalMs = 5_000;
|
||||||
private readonly toastService = inject(ToastService);
|
|
||||||
private readonly qrPollingMaxAttempts = 9;
|
private readonly qrPollingMaxAttempts = 9;
|
||||||
private readonly transferPollingIntervalMs = 3_000;
|
private readonly transferPollingIntervalMs = 3_000;
|
||||||
private readonly transferPollingMaxAttempts = 4;
|
private readonly transferPollingMaxAttempts = 4;
|
||||||
@@ -194,9 +193,9 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD
|
const tenant = this.tenantService.tenant();
|
||||||
if (editing && !this.canModifyCart()) {
|
const purchaseId = this.createdPurchaseId();
|
||||||
const tenant = this.tenantService.tenant();
|
if (!tenant || !purchaseId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,9 +216,9 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
} finally {
|
} finally {
|
||||||
this.globalLoadingService.stop();
|
this.globalLoadingService.stop();
|
||||||
this.isRestoringCart.set(false);
|
this.isRestoringCart.set(false);
|
||||||
>>>>>>> feature/restore-cart-on-modify
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async onStep1Continue(): Promise<void> {
|
protected async onStep1Continue(): Promise<void> {
|
||||||
if (this.form.invalid || this.isUpdatingPurchase()) return;
|
if (this.form.invalid || this.isUpdatingPurchase()) return;
|
||||||
|
|
||||||
@@ -409,10 +408,16 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (purchase.status === 'paid') {
|
if (purchase.status === 'paid') {
|
||||||
|
this.navigateToPurchaseStatus(purchaseId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.scheduleTransferPoll(runId);
|
this.scheduleTransferPoll(runId);
|
||||||
console.error('Failed to submit transfer payment for review:', error);
|
} catch (error) {
|
||||||
this.showRequestError(error, 'No se pudo enviar el pago para su validación.');
|
const expired = this.handleCheckoutError(
|
||||||
|
error,
|
||||||
|
'No se pudo enviar el pago para su validación.',
|
||||||
|
);
|
||||||
|
|
||||||
if (!expired && runId === this.transferPollingRunId) {
|
if (!expired && runId === this.transferPollingRunId) {
|
||||||
this.transferValidationStatus.set('error');
|
this.transferValidationStatus.set('error');
|
||||||
@@ -660,4 +665,51 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.toastService.danger(message);
|
this.toastService.danger(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleCheckoutError(error: unknown, fallbackMessage: string): boolean {
|
||||||
|
if (!(error instanceof HttpErrorResponse)) {
|
||||||
|
this.toastService.danger(fallbackMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = error.error as ApiErrorResponse | null;
|
||||||
|
|
||||||
|
if (response?.code === 'purchase.expired' || this.hasExpiredPurchase()) {
|
||||||
|
this.navigationStarted = true;
|
||||||
|
this.stopQrPolling();
|
||||||
|
this.stopTransferPolling();
|
||||||
|
this.toastService.danger(
|
||||||
|
response?.code === 'purchase.expired' && response.message
|
||||||
|
? response.message
|
||||||
|
: 'La compra venció. Iniciá una nueva compra.',
|
||||||
|
);
|
||||||
|
void this.router.navigate(['/']);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validationMessage = response?.errors
|
||||||
|
? Object.values(response.errors).flat().find(Boolean)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
this.toastService.danger(validationMessage ?? response?.message ?? fallbackMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasExpiredPurchase(): boolean {
|
||||||
|
const purchase = this.createdPurchase();
|
||||||
|
|
||||||
|
if (!purchase) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (purchase.status === 'expired') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!purchase.expires_at) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Date.parse(purchase.expires_at) <= Date.now();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user