376 lines
12 KiB
TypeScript
376 lines
12 KiB
TypeScript
import { CommonModule } from '@angular/common';
|
|
import { Component, EventEmitter, inject, Input, Output } from '@angular/core';
|
|
import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
|
import { NotificationService } from '../../core/services/common/notification.service';
|
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
|
import { ShippingService } from '../../core/services/carnet/shipping.service';
|
|
import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service';
|
|
import { CommonService } from '../../core/services/common/common.service';
|
|
import { Shipping } from '../../core/models/carnet/shipping';
|
|
import { Country } from '../../core/models/country';
|
|
import { State } from '../../core/models/state';
|
|
import { ZipCodeValidator } from '../../shared/validators/zipcode-validator';
|
|
import { Subject, takeUntil } from 'rxjs';
|
|
import { DeliveryType } from '../../core/models/delivery-type';
|
|
import { DeliveryMethod } from '../../core/models/delivery-method';
|
|
import { PaymentType } from '../../core/models/payment-type';
|
|
|
|
@Component({
|
|
selector: 'app-shipping',
|
|
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule],
|
|
templateUrl: './shipping.component.html',
|
|
styleUrl: './shipping.component.scss'
|
|
})
|
|
export class ShippingComponent {
|
|
@Input() headerid: number = 0;
|
|
@Input() isEditMode = false;
|
|
@Output() completed = new EventEmitter<boolean>();
|
|
|
|
private fb = inject(FormBuilder);
|
|
private shippingService = inject(ShippingService);
|
|
private notificationService = inject(NotificationService);
|
|
private errorHandler = inject(ApiErrorHandlerService);
|
|
private commonService = inject(CommonService);
|
|
|
|
shippingForm: FormGroup;
|
|
isLoading = false;
|
|
showAddressForm = false;
|
|
showContactForm = false;
|
|
|
|
countriesHasStates = ['US', 'CA', 'MX'];
|
|
countries: Country[] = [];
|
|
states: State[] = [];
|
|
deliveryTypes: DeliveryType[] = [];
|
|
deliveryMethods: DeliveryMethod[] = [];
|
|
paymentTypes: PaymentType[] = [];
|
|
|
|
private destroy$ = new Subject<void>();
|
|
|
|
// preparer contact and address mock data
|
|
preparerContact = {
|
|
firstName: 'John',
|
|
lastName: 'Doe',
|
|
middleInitial: 'A',
|
|
title: 'Mr.',
|
|
phone: '1234567890',
|
|
mobile: '0987654321',
|
|
fax: '1234567890',
|
|
email: 'j@doe.com',
|
|
}
|
|
|
|
preparerAddress = {
|
|
address1: '123 Main St',
|
|
address2: 'Suite 100',
|
|
city: 'Anytown',
|
|
state: 'CA',
|
|
zip: '12345',
|
|
country: 'US'
|
|
};
|
|
|
|
holderAddress = {
|
|
address1: '456 Holder St',
|
|
address2: 'Apt 200',
|
|
city: 'Othertown',
|
|
state: 'NY',
|
|
zip: '67890',
|
|
country: 'US'
|
|
};
|
|
|
|
holderContact = {
|
|
firstName: 'Jane',
|
|
lastName: 'Smith',
|
|
middleInitial: 'B',
|
|
title: 'Ms.',
|
|
phone: '2345678901',
|
|
mobile: '1098765432',
|
|
fax: '2345678901',
|
|
email: 'jan@sm.cm'
|
|
};
|
|
|
|
constructor() {
|
|
this.shippingForm = this.fb.group({
|
|
needsBond: [false],
|
|
needsInsurance: [false],
|
|
needsLostDocProtection: [false],
|
|
shipTo: ['preparer', Validators.required],
|
|
address: this.fb.group({
|
|
address1: ['', [Validators.required, Validators.maxLength(100)]],
|
|
address2: ['', [Validators.maxLength(100)]],
|
|
city: ['', [Validators.required, Validators.maxLength(50)]],
|
|
state: ['', Validators.required],
|
|
country: ['', Validators.required],
|
|
zip: ['', [Validators.required, ZipCodeValidator('country')]],
|
|
}),
|
|
contact: this.fb.group({
|
|
firstName: ['', [Validators.required, Validators.maxLength(50)]],
|
|
lastName: ['', [Validators.required, Validators.maxLength(50)]],
|
|
middleInitial: ['', [Validators.maxLength(1)]],
|
|
title: ['', [Validators.required, Validators.maxLength(100)]],
|
|
phone: ['', [Validators.required, Validators.pattern(/^[0-9]{10,15}$/)]],
|
|
mobile: ['', [Validators.required, Validators.pattern(/^[0-9]{10,15}$/)]],
|
|
fax: ['', [Validators.pattern(/^[0-9]{10,15}$/)]],
|
|
email: ['', [Validators.required, Validators.email, Validators.maxLength(100)]],
|
|
refNumber: [''],
|
|
notes: ['']
|
|
}),
|
|
deliveryType: ['', Validators.required],
|
|
deliveryMethod: ['', Validators.required],
|
|
courierAccount: [''],
|
|
paymentMethod: ['', Validators.required],
|
|
notes: ['']
|
|
});
|
|
|
|
// Update form validation based on selections
|
|
// this.shippingForm.get('shipTo')?.valueChanges.subscribe(value => {
|
|
// this.updateShippingValidation(value);
|
|
// });
|
|
|
|
this.shippingForm.get('deliveryMethod')?.valueChanges.subscribe(value => {
|
|
const courierControl = this.shippingForm.get('courierAccount');
|
|
if (value === 'customerCourier') {
|
|
courierControl?.setValidators([Validators.required]);
|
|
} else {
|
|
courierControl?.clearValidators();
|
|
}
|
|
courierControl?.updateValueAndValidity();
|
|
});
|
|
|
|
this.shippingForm.valueChanges.subscribe(() => {
|
|
this.completed.emit(this.shippingForm.valid);
|
|
});
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
this.loadCountries();
|
|
this.loadDeliveryTypes();
|
|
this.loadDeliveryMethods();
|
|
this.loadPaymentTypes();
|
|
|
|
if (this.headerid && this.isEditMode) {
|
|
this.loadShippingData();
|
|
}
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
this.destroy$.next();
|
|
this.destroy$.complete();
|
|
}
|
|
|
|
onCountryChange(country: string): void {
|
|
this.shippingForm.get('address.state')?.reset();
|
|
|
|
if (country) {
|
|
this.loadStates(country);
|
|
}
|
|
|
|
this.shippingForm.get('address.zip')?.updateValueAndValidity();
|
|
}
|
|
|
|
loadCountries(): void {
|
|
this.commonService.getCountries(0)
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe({
|
|
next: (countries) => {
|
|
this.countries = countries;
|
|
},
|
|
error: (error) => {
|
|
console.error('Failed to load countries', error);
|
|
this.isLoading = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
loadDeliveryTypes(): void {
|
|
this.commonService.getDeliveryTypes(0)
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe({
|
|
next: (deliveryTypes) => {
|
|
this.deliveryTypes = deliveryTypes;
|
|
},
|
|
error: (error) => {
|
|
console.error('Failed to load delivery types', error);
|
|
this.isLoading = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
loadDeliveryMethods(): void {
|
|
this.commonService.getDeliveryMethods(0)
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe({
|
|
next: (deliveryMethods) => {
|
|
this.deliveryMethods = deliveryMethods;
|
|
},
|
|
error: (error) => {
|
|
console.error('Failed to load delivery methods', error);
|
|
this.isLoading = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
loadPaymentTypes(): void {
|
|
this.commonService.getPaymentTypes(0)
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe({
|
|
next: (paymentTypes) => {
|
|
this.paymentTypes = paymentTypes;
|
|
},
|
|
error: (error) => {
|
|
console.error('Failed to load payment types', error);
|
|
this.isLoading = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
loadStates(country: string): void {
|
|
this.isLoading = true;
|
|
country = this.countriesHasStates.includes(country) ? country : 'FN';
|
|
this.commonService.getStates(country, 0)
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe({
|
|
next: (states) => {
|
|
this.states = states;
|
|
const stateControl = this.shippingForm.get('contact.state');
|
|
if (this.countriesHasStates.includes(country)) {
|
|
stateControl?.enable();
|
|
} else {
|
|
stateControl?.disable();
|
|
stateControl?.setValue('FN');
|
|
}
|
|
this.isLoading = false;
|
|
},
|
|
error: (error) => {
|
|
console.error('Failed to load states', error);
|
|
this.isLoading = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
loadShippingData(): void {
|
|
this.isLoading = true;
|
|
this.shippingService.getShippingData(this.headerid).subscribe({
|
|
next: (data: Shipping) => {
|
|
this.patchShippingData(data);
|
|
this.isLoading = false;
|
|
},
|
|
error: (error: any) => {
|
|
let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load shipping and payments data');
|
|
this.notificationService.showError(errorMessage);
|
|
this.isLoading = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
patchShippingData(shipping: Shipping): void {
|
|
this.shippingForm.patchValue({
|
|
needsBond: shipping.needsBond,
|
|
needsInsurance: shipping.needsInsurance,
|
|
needsLostDocProtection: shipping.needsLostDocProtection,
|
|
shipTo: shipping.shipTo,
|
|
address: shipping.address,
|
|
contact: shipping.contact,
|
|
deliveryType: shipping.deliveryType,
|
|
deliveryMethod: shipping.deliveryMethod,
|
|
courierAccount: shipping.courierAccount,
|
|
paymentMethod: shipping.paymentMethod,
|
|
notes: shipping.notes
|
|
});
|
|
|
|
if (shipping.address?.country) {
|
|
this.loadStates(shipping.address?.country);
|
|
}
|
|
}
|
|
|
|
updateShippingValidation(shipTo: string): void {
|
|
// const addressGroup = this.shippingForm.get('address') as FormGroup;
|
|
// const contactGroup = this.shippingForm.get('contact') as FormGroup;
|
|
|
|
// if (shipTo === 'thirdParty') {
|
|
// Object.keys(addressGroup.controls).forEach(key => {
|
|
// addressGroup.get(key)?.setValidators(Validators.required);
|
|
// });
|
|
// Object.keys(contactGroup.controls).forEach(key => {
|
|
// if (key !== 'middleInitial' && key !== 'fax' && key !== 'notes' && key !== 'refNumber') {
|
|
// contactGroup.get(key)?.setValidators(Validators.required);
|
|
// }
|
|
// });
|
|
// } else {
|
|
// Object.keys(addressGroup.controls).forEach(key => {
|
|
// addressGroup.get(key)?.clearValidators();
|
|
// });
|
|
// Object.keys(contactGroup.controls).forEach(key => {
|
|
// contactGroup.get(key)?.clearValidators();
|
|
// });
|
|
// }
|
|
|
|
// addressGroup.updateValueAndValidity();
|
|
// contactGroup.updateValueAndValidity();
|
|
}
|
|
|
|
onSubmit(): void {
|
|
if (this.shippingForm.invalid) {
|
|
this.shippingForm.markAllAsTouched();
|
|
return;
|
|
}
|
|
|
|
this.isLoading = true;
|
|
const shippingData = this.shippingForm.value;
|
|
|
|
this.shippingService.saveShippingDetails(this.headerid, shippingData).subscribe({
|
|
next: () => {
|
|
this.notificationService.showSuccess('Shipping & payments information saved successfully');
|
|
this.completed.emit(true);
|
|
this.isLoading = false;
|
|
},
|
|
error: (error) => {
|
|
let errorMessage = this.errorHandler.handleApiError(error, 'Failed to save shipping and payment information');
|
|
this.notificationService.showError(errorMessage);
|
|
this.isLoading = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
getAddressLabel(): string {
|
|
let shipTo = this.shippingForm.get('shipTo')?.value;
|
|
|
|
if (shipTo === 'preparer') {
|
|
return `${this.preparerContact.firstName} ${this.preparerContact.lastName}, ${this.preparerAddress.address1}, ${this.preparerAddress.city}, ${this.preparerAddress.state}, ${this.preparerAddress.zip}, ${this.preparerAddress.country}`;
|
|
}
|
|
|
|
if (shipTo === 'holder') {
|
|
return `${this.holderContact.firstName} ${this.holderContact.lastName}, ${this.holderAddress.address1}, ${this.holderAddress.city}, ${this.holderAddress.state}, ${this.holderAddress.zip}, ${this.holderAddress.country}`;
|
|
}
|
|
return '';
|
|
}
|
|
|
|
editAddressForm(): void {
|
|
this.showAddressForm = true;
|
|
let shipTo = this.shippingForm.get('shipTo')?.value;
|
|
|
|
if (shipTo === 'preparer') {
|
|
this.shippingForm.get('address')?.patchValue(this.preparerAddress);
|
|
this.loadStates(this.preparerAddress.country);
|
|
} else if (shipTo === 'holder') {
|
|
this.shippingForm.get('address')?.patchValue(this.holderAddress);
|
|
this.loadStates(this.preparerAddress.country);
|
|
}
|
|
}
|
|
|
|
cancelEditAddressForm(): void {
|
|
this.showAddressForm = false;
|
|
this.shippingForm.get('address')?.reset();
|
|
}
|
|
|
|
onShipToChange(event: any): void {
|
|
const shipTo = event.value;
|
|
this.showAddressForm = false;
|
|
this.showContactForm = false;
|
|
|
|
if (shipTo === 'thirdParty') {
|
|
this.shippingForm.get('contact')?.reset();
|
|
this.shippingForm.get('address')?.reset();
|
|
this.showAddressForm = true;
|
|
this.showContactForm = true;
|
|
}
|
|
}
|
|
} |