service-provider-app/src/app/carnet/checkout/checkout.component.ts
2025-12-06 05:59:06 -04:00

204 lines
8.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Component, ElementRef, inject, ViewChild } from '@angular/core';
import { PaymentService } from '../../core/services/carnet/payment.service';
import { CommonModule } from '@angular/common';
import { Fees } from '../../core/models/carnet/fee';
import { CarnetService } from '../../core/services/carnet/carnet.service';
import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service';
import { NavigationService } from '../../core/services/common/navigation.service';
import { NotificationService } from '../../core/services/common/notification.service';
import { StorageService } from '../../core/services/common/storage.service';
import { finalize } from 'rxjs';
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
import { PaymentDetail } from '../../core/models/carnet/payment-details';
// This is necessary to tell TypeScript that a global 'paypal' object exists.
declare var paypal: any;
@Component({
selector: 'app-checkout',
imports: [CommonModule, AngularMaterialModule],
templateUrl: './checkout.component.html',
styleUrl: './checkout.component.scss'
})
export class CheckoutComponent {
paymentCompleted: boolean = false;
paymentError: boolean = false;
isLoading: boolean = false;
paymentDetails: any = null;
currentApplicationDetails: { headerid: number, applicationName: string, applicationType: string } | null = null;
changeInProgress: boolean = false;
estimatedFees: Fees = {};
bondPremiumLabel: string = 'Bond Premium';
@ViewChild('paypalcontrol', { static: true }) paypalElement!: ElementRef;
orderDetails: PaymentDetail = {};
orderTotal = 0.00;
currency = 'USD';
private paymentService = inject(PaymentService);
private notificationService = inject(NotificationService);
private errorHandler = inject(ApiErrorHandlerService);
private storageService = inject(StorageService);
private navigationService = inject(NavigationService);
private carnetService = inject(CarnetService);
constructor() {
this.currentApplicationDetails = this.storageService.get<{ headerid: number, applicationName: string, applicationType: string }>('currentapplication')
this.orderDetails.headerid = this.currentApplicationDetails?.headerid;
this.orderDetails.applicationName = this.currentApplicationDetails?.applicationName;
this.orderDetails.description = ` 'Carnet Application - ${this.currentApplicationDetails?.headerid} - ${this.currentApplicationDetails?.applicationName}`
}
ngOnInit(): void {
if (this.currentApplicationDetails?.headerid) {
this.carnetService.getEstimatedFees(this.currentApplicationDetails?.headerid).subscribe({
next: (data: Fees) => {
if (data) {
this.estimatedFees = data;
if (this.estimatedFees.securityType === 'B') {
this.bondPremiumLabel = 'Bond Premium';
} else if (this.estimatedFees.securityType === 'C') {
this.bondPremiumLabel = 'Cash Deposit';
} else if (this.estimatedFees.securityType === 'G') {
this.bondPremiumLabel = 'Refundable claim deposit';
}
this.calculateTotal();
}
},
error: (error: any) => {
let errorMessage = this.errorHandler.handleApiError(error, 'Failed to get estimated fees');
this.notificationService.showError(errorMessage);
console.error('Error getting estimated fees:', error);
}
});
}
}
ngAfterViewInit(): void {
this.initConfig();
}
initConfig(): void {
paypal
.Buttons({
style: {
layout: 'vertical', // or 'horizontal'
color: 'gold',
shape: 'pill',
label: 'pay',
height: 35 // Height in pixels (default is ~35-45px)
// 'paypal' Standard PayPal button [defoult]
// 'checkout' "Checkout with PayPal"
// 'buynow' "Buy Now with PayPal"
// 'pay' "Pay with PayPal"
// 'installment' Displays installment information
// 'subscribe' For subscriptions
// 'donate' For donations
// pay : Pay with [PayPal]
// buynow : [PayPal] Buy Now
// Error: Expected style.height to be between 25px and 55px - got 10px
// width width usually doesnt need to be set or must be reasonable.
},
// 1. Call your server to set up the transaction
createOrder: async (data: any, actions: any) => {
try {
// Call the createOrder method from your service
const orderId = await this.paymentService.createOrder(this.orderDetails);
this.orderDetails.orderId = orderId;
return orderId;
} catch (error) {
this.notificationService.showError('Failed to initiate the payment');
console.error('Error creating order:', error);
return;
}
},
// 2. Call your server to finalize the transaction
onApprove: async (data: any, actions: any) => {
try {
// data.orderID is the ID of the transaction from PayPal
await this.paymentService.completePayment(this.orderDetails);
// You can now redirect the user or update the UI
this.changeInProgress = true;
this.carnetService.submitApplication(this.currentApplicationDetails?.headerid!).pipe(finalize(() => {
this.changeInProgress = false;
})).subscribe({
next: () => {
this.notificationService.showSuccess('Application submitted successfully');
this.storageService.removeItem('currentapplication');
this.navigationService.navigate(["home"]);
},
error: (error) => {
this.notificationService.showError('Failed to submit application');
console.error('Error submitting the application', error);
}
});
} catch (error) {
this.notificationService.showError('Failed to complete the payment');
console.error('Error completing the payment:', error);
return;
}
},
// 3. Handle errors
onError: (error: any) => {
this.notificationService.showError('Payment transaction failed');
this.orderDetails.paymentStatus = 'Failed';
this.orderDetails.paymentErrorDetails = JSON.stringify(error);
this.paymentService.logTransactionDetails(this.orderDetails);
console.error('An error occurred during the transaction:', error);
},
// 4. Handle cancellation
onCancel: (data: any) => {
this.orderDetails.paymentStatus = 'Cancelled';
if (this.orderDetails.orderId) {
this.paymentService.logTransactionDetails(this.orderDetails);
}
this.onCancel();
}
}).render(this.paypalElement.nativeElement)
.catch((error: any) => {
console.error('Failed to render PayPal Buttons:', error);
});
}
calculateTotal(): void {
const validFees = Object.values(this.estimatedFees).filter(
(fee): fee is number => typeof fee === 'number'
);
this.orderTotal = validFees.reduce((total, fee) => total + fee, 0);
this.orderDetails.price = this.orderTotal?.toString() ?? '0.00';
}
onCancel(): void {
this.storageService.removeItem('currentapplication');
let route: string = 'edit-carnet';
if (this.currentApplicationDetails?.applicationType === 'duplicate') {
route = 'duplicate-carnet';
}
else if (this.currentApplicationDetails?.applicationType === 'extend') {
route = 'extend-carnet';
} else if (this.currentApplicationDetails?.applicationType === 'additional') {
route = 'additional-sets';
}
this.navigationService.navigate([route, this.currentApplicationDetails?.headerid],
{
state: { isEditMode: true },
queryParams: {
applicationname: this.currentApplicationDetails?.applicationName,
return: 'shipping'
}
})
}
}