204 lines
8.0 KiB
TypeScript
204 lines
8.0 KiB
TypeScript
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 doesn’t 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'
|
||
}
|
||
})
|
||
}
|
||
} |