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(); 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(); // 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; } } }