diff --git a/src/app/carnet/add/add-carnet.component.html b/src/app/carnet/add/add-carnet.component.html index 1671e6a..cb8a6fe 100644 --- a/src/app/carnet/add/add-carnet.component.html +++ b/src/app/carnet/add/add-carnet.component.html @@ -36,33 +36,11 @@ - - - Insurance - - - - - + - Shipping + Shipping & Payment - - - - Delivery Method - - - - - - - Payment - - - \ No newline at end of file diff --git a/src/app/carnet/add/add-carnet.component.ts b/src/app/carnet/add/add-carnet.component.ts index d81ef99..ecb8611 100644 --- a/src/app/carnet/add/add-carnet.component.ts +++ b/src/app/carnet/add/add-carnet.component.ts @@ -7,18 +7,15 @@ import { ApplicationComponent } from "../application/application.component"; import { HolderComponent } from '../holder/holder.component'; import { GoodsComponent } from '../goods/goods.component'; import { TravelPlanComponent } from '../travel-plan/travel-plan.component'; -import { InsuranceComponent } from '../insurance/insurance.component'; -import { PaymentComponent } from '../payment/payment.component'; import { ShippingComponent } from '../shipping/shipping.component'; -import { DeliveryComponent } from '../delivery/delivery.component'; import { UserPreferencesService } from '../../core/services/user-preference.service'; import { UserPreferences } from '../../core/models/user-preference'; @Component({ selector: 'app-add-carnet', imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule, - ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent, InsuranceComponent, - ShippingComponent, DeliveryComponent, PaymentComponent], + ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent, + ShippingComponent], templateUrl: './add-carnet.component.html', styleUrl: './add-carnet.component.scss' }) @@ -36,10 +33,7 @@ export class AddCarnetComponent { holderSelection: false, goodsSection: false, travelPlan: false, - insurance: false, - shipping: false, - deliveryMethod: false, - payment: false + shipping: false }; constructor(userPrefenceService: UserPreferencesService) { @@ -51,7 +45,7 @@ export class AddCarnetComponent { } onApplicationDetailCreated(headerid: number): void { - this.headerid = this.headerid; + this.headerid = headerid; this.stepsCompleted.applicationDetail = true; this.isLinear = false; // Disable linear mode after application detail is created } @@ -68,19 +62,7 @@ export class AddCarnetComponent { this.stepsCompleted.travelPlan = completed; } - onInsuranceSaved(completed: boolean): void { - this.stepsCompleted.insurance = completed; - } - onShippingSaved(completed: boolean): void { this.stepsCompleted.shipping = completed; } - - onDeliveryMethodSaved(completed: boolean): void { - this.stepsCompleted.deliveryMethod = completed; - } - - onPaymentSaved(completed: boolean): void { - this.stepsCompleted.payment = completed; - } } diff --git a/src/app/carnet/application/application.component.ts b/src/app/carnet/application/application.component.ts index 4081bc2..19ede44 100644 --- a/src/app/carnet/application/application.component.ts +++ b/src/app/carnet/application/application.component.ts @@ -102,7 +102,7 @@ export class ApplicationComponent { this.applicationDetailService.createApplicationDetails(applicationDetailData).subscribe({ next: (applicationData: any) => { this.notificationService.showSuccess(`Application details added successfully`); - this.headerIdCreated.emit(applicationData.HEADERID); + this.headerIdCreated.emit(+applicationData.HEADERID); this.applicationDetailsForm.get('name')?.disable(); this.disableSaveButton = true; this.isLoading = false; diff --git a/src/app/carnet/delivery/delivery.component.html b/src/app/carnet/delivery/delivery.component.html deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/carnet/delivery/delivery.component.scss b/src/app/carnet/delivery/delivery.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/carnet/delivery/delivery.component.ts b/src/app/carnet/delivery/delivery.component.ts deleted file mode 100644 index 8ccfec4..0000000 --- a/src/app/carnet/delivery/delivery.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; - -@Component({ - selector: 'app-delivery', - imports: [], - templateUrl: './delivery.component.html', - styleUrl: './delivery.component.scss' -}) -export class DeliveryComponent { - @Input() headerid: number = 0; - @Output() completed = new EventEmitter(); - -} diff --git a/src/app/carnet/edit/edit-carnet.component.html b/src/app/carnet/edit/edit-carnet.component.html index 761da22..49d6cfa 100644 --- a/src/app/carnet/edit/edit-carnet.component.html +++ b/src/app/carnet/edit/edit-carnet.component.html @@ -23,7 +23,7 @@ Goods Section - @@ -36,33 +36,11 @@ - - - Insurance - - - - - + - Shipping + Shipping & Payment - - - - Delivery Method - - - - - - - Payment - - - \ No newline at end of file diff --git a/src/app/carnet/edit/edit-carnet.component.ts b/src/app/carnet/edit/edit-carnet.component.ts index 9ef173b..64e3d50 100644 --- a/src/app/carnet/edit/edit-carnet.component.ts +++ b/src/app/carnet/edit/edit-carnet.component.ts @@ -7,9 +7,6 @@ import { StepperSelectionEvent } from '@angular/cdk/stepper'; import { GoodsComponent } from '../goods/goods.component'; import { HolderComponent } from '../holder/holder.component'; import { ActivatedRoute } from '@angular/router'; -import { DeliveryComponent } from '../delivery/delivery.component'; -import { InsuranceComponent } from '../insurance/insurance.component'; -import { PaymentComponent } from '../payment/payment.component'; import { ShippingComponent } from '../shipping/shipping.component'; import { TravelPlanComponent } from '../travel-plan/travel-plan.component'; import { UserPreferences } from '../../core/models/user-preference'; @@ -18,8 +15,7 @@ import { UserPreferencesService } from '../../core/services/user-preference.serv @Component({ selector: 'app-edit-carnet', imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule, - ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent, InsuranceComponent, - ShippingComponent, DeliveryComponent, PaymentComponent], + ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent, ShippingComponent], templateUrl: './edit-carnet.component.html', styleUrl: './edit-carnet.component.scss' }) @@ -37,10 +33,7 @@ export class EditCarnetComponent { holderSelection: false, goodsSection: false, travelPlan: false, - insurance: false, - shipping: false, - deliveryMethod: false, - payment: false + shipping: false }; private route = inject(ActivatedRoute); @@ -70,19 +63,7 @@ export class EditCarnetComponent { this.stepsCompleted.travelPlan = completed; } - onInsuranceSaved(completed: boolean): void { - this.stepsCompleted.insurance = completed; - } - onShippingSaved(completed: boolean): void { this.stepsCompleted.shipping = completed; } - - onDeliveryMethodSaved(completed: boolean): void { - this.stepsCompleted.deliveryMethod = completed; - } - - onPaymentSaved(completed: boolean): void { - this.stepsCompleted.payment = completed; - } } diff --git a/src/app/carnet/goods/goods.component.html b/src/app/carnet/goods/goods.component.html index b7671a1..9457a02 100644 --- a/src/app/carnet/goods/goods.component.html +++ b/src/app/carnet/goods/goods.component.html @@ -89,7 +89,7 @@ Value - {{ formatDecimalDisplay(item.value, 2) }} + {{ formatDecimalDisplay(item.value, 2) | currency}} diff --git a/src/app/carnet/goods/goods.component.ts b/src/app/carnet/goods/goods.component.ts index 5ca457c..4eeffda 100644 --- a/src/app/carnet/goods/goods.component.ts +++ b/src/app/carnet/goods/goods.component.ts @@ -29,6 +29,7 @@ import { Goods, GoodsItem } from '../../core/models/carnet/goods'; export class GoodsComponent { @Input() headerid: number = 0; @Input() userPreferences: UserPreferences = {}; + @Input() isEditMode: boolean = false; @Output() completed = new EventEmitter(); @ViewChild(MatPaginator) paginator!: MatPaginator; @@ -85,10 +86,6 @@ export class GoodsComponent { value: [0, [Validators.required, Validators.min(1), Validators.pattern(/^\d+(\.\d{1,2})?$/)]], countryOfOrigin: ['', Validators.required] }); - - this.goodsForm.valueChanges.subscribe(() => { - this.completed.emit(this.goodsForm.valid && this.dataSource.data.length > 0); - }); } ngAfterViewInit() { @@ -117,6 +114,7 @@ export class GoodsComponent { }); this.loadGoodsItems(); + this.completed.emit(this.goodsForm.valid && this.dataSource.data.length > 0); } } @@ -314,10 +312,10 @@ export class GoodsComponent { return; } - items.map(item => { - item.countryOfOrigin = this.getCountryValue(item.countryOfOrigin); - item.unitOfMeasure = this.getUnitOfMeasureValue(item.unitOfMeasure); - }); + // items.map(item => { + // item.countryOfOrigin = this.getCountryValue(item.countryOfOrigin); + // item.unitOfMeasure = this.getUnitOfMeasureValue(item.unitOfMeasure); + // }); this.goodsService.addGoodsItem(this.headerid, items).subscribe({ next: () => { @@ -395,7 +393,7 @@ export class GoodsComponent { this.goodsService.saveGoodsData(this.headerid, formData).subscribe({ next: () => { this.notificationService.showSuccess('Goods information saved successfully'); - this.completed.emit(true); + this.completed.emit(this.goodsForm.valid && this.dataSource.data.length > 0); }, error: (error) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to save goods information'); diff --git a/src/app/carnet/insurance/insurance.component.html b/src/app/carnet/insurance/insurance.component.html deleted file mode 100644 index d4f2ff5..0000000 --- a/src/app/carnet/insurance/insurance.component.html +++ /dev/null @@ -1 +0,0 @@ -

insurance works!

diff --git a/src/app/carnet/insurance/insurance.component.scss b/src/app/carnet/insurance/insurance.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/carnet/insurance/insurance.component.ts b/src/app/carnet/insurance/insurance.component.ts deleted file mode 100644 index 353e5cf..0000000 --- a/src/app/carnet/insurance/insurance.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; - -@Component({ - selector: 'app-insurance', - imports: [], - templateUrl: './insurance.component.html', - styleUrl: './insurance.component.scss' -}) -export class InsuranceComponent { - @Input() headerid: number = 0; - @Output() completed = new EventEmitter(); -} diff --git a/src/app/carnet/payment/payment.component.html b/src/app/carnet/payment/payment.component.html deleted file mode 100644 index d9cf5ff..0000000 --- a/src/app/carnet/payment/payment.component.html +++ /dev/null @@ -1 +0,0 @@ -

payment works!

diff --git a/src/app/carnet/payment/payment.component.scss b/src/app/carnet/payment/payment.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/carnet/payment/payment.component.ts b/src/app/carnet/payment/payment.component.ts deleted file mode 100644 index 2637d52..0000000 --- a/src/app/carnet/payment/payment.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; - -@Component({ - selector: 'app-payment', - imports: [], - templateUrl: './payment.component.html', - styleUrl: './payment.component.scss' -}) -export class PaymentComponent { - @Input() headerid: number = 0; - @Output() completed = new EventEmitter(); -} diff --git a/src/app/carnet/shipping/shipping.component.html b/src/app/carnet/shipping/shipping.component.html index 892d52b..6c8ec95 100644 --- a/src/app/carnet/shipping/shipping.component.html +++ b/src/app/carnet/shipping/shipping.component.html @@ -1 +1,302 @@ -

shipping works!

+
+
+ +
+

Insurance & Bond

+
+ Do you need Bond from + us? + Do you need insurance for your + goods? + Do you need Lost document + protection? +
+
+ + +
+

Ship To

+ + Preparer + Holder + 3rd Party + + + + +

{{getAddressLabel()}}

+
+ + + +
+
+

Shipping Address

+ + +
+ + Address Line 1 + + + Address is required + + + Maximum 100 characters allowed + + +
+ +
+ + Address Line 2 (Optional) + + + Maximum 100 characters allowed + + +
+ + +
+ + City + + + City is required + + + Maximum 50 characters allowed + + + + + Country + + + {{ country.name }} + + + + Country is required + + + + + State/Province + + + {{ state.name }} + + + + State is required + + + + + ZIP/Postal Code + + + ZIP/Postal code is required + + + Please enter a valid 5-digit US ZIP code + + + Please enter a valid postal code (e.g., A1B2C3) + + +
+ +
+ +
+
+ +
+

Contact Information

+
+ + First Name + + person + + First name is required + + + Maximum 50 characters allowed + + + + + Middle Initial + + + Only 1 character allowed + + + + + Last Name + + person + + Last name is required + + + Maximum 50 characters allowed + + +
+
+ + Title + + work + + Title is required + + + Maximum 100 characters allowed + + +
+ +
+ + Phone + + phone + + Phone is required + + + Please enter a valid phone number (10-15 digits) + + + + + Mobile + + smartphone + + Mobile is required + + + Please enter a valid mobile number (10-15 digits) + + +
+ +
+ + Fax + + fax + + Please enter a valid fax number (10-15 digits) + + + + + Email + + email + + Email is required + + + Please enter a valid email address + + + Maximum 100 characters allowed + + +
+
+ + Reference Number + + +
+
+ + Notes + + +
+
+
+ + +
+

Delivery Method

+
+ + Delivery Type + + + {{ deliveryType.name }} + + + + Delivery Type is required + + + + Delivery Method + + + {{ deliveryMethod.name }} + + + + Delivery Method is required + + +
+
+ + Courier Account Number + + Required when using customer courier + +
+
+ + +
+

Payment Method

+
+ + Payment Method + + + {{ paymentType.name }} + + + + Payment Method is required + + +
+ +
+ +
+ +
+
+
\ No newline at end of file diff --git a/src/app/carnet/shipping/shipping.component.scss b/src/app/carnet/shipping/shipping.component.scss index e69de29..e1973a7 100644 --- a/src/app/carnet/shipping/shipping.component.scss +++ b/src/app/carnet/shipping/shipping.component.scss @@ -0,0 +1,76 @@ +.shipping-container { + padding: 16px; + + .section { + margin-bottom: 24px; + padding: 16px; + border: 1px solid #e0e0e0; + border-radius: 4px; + + h3 { + margin: 0px 0px 16px 0px; + color: var(--mat-sys-primary); + font-weight: 500; + } + + h4 { + margin: 16px 0 8px; + color: var(--mat-sys-primary); + font-weight: 500; + } + + .mat-mdc-card-content:first-child { + padding: 0 16px; + } + } + + .checkbox-group { + display: flex; + flex-direction: column; + gap: 8px; + } + + .radio-group { + display: flex; + gap: 16px; + margin-bottom: 16px; + } + + .form-row { + display: flex; + gap: 16px; + + mat-form-field { + flex: 1; + margin-bottom: 6px; + + &.full-width { + flex: 100%; + } + } + + .small-field { + max-width: 120px; + } + } + + .form-actions { + display: flex; + justify-content: flex-end; + gap: 16px; + margin-top: 16px; + } +} + +@media (max-width: 768px) { + .shipping-container { + .form-row { + flex-direction: column; + gap: 8px; + + mat-form-field { + width: 100%; + } + } + } +} \ No newline at end of file diff --git a/src/app/carnet/shipping/shipping.component.ts b/src/app/carnet/shipping/shipping.component.ts index a972ee4..4cb0ade 100644 --- a/src/app/carnet/shipping/shipping.component.ts +++ b/src/app/carnet/shipping/shipping.component.ts @@ -1,12 +1,376 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; +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: [], + 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; + } + } +} \ No newline at end of file diff --git a/src/app/core/models/carnet/delivery.ts b/src/app/core/models/carnet/delivery.ts deleted file mode 100644 index 964b03f..0000000 --- a/src/app/core/models/carnet/delivery.ts +++ /dev/null @@ -1,2 +0,0 @@ -export interface Delivery { -} diff --git a/src/app/core/models/carnet/insurance.ts b/src/app/core/models/carnet/insurance.ts deleted file mode 100644 index 786147b..0000000 --- a/src/app/core/models/carnet/insurance.ts +++ /dev/null @@ -1,2 +0,0 @@ -export interface Insurance { -} diff --git a/src/app/core/models/carnet/payment.ts b/src/app/core/models/carnet/payment.ts deleted file mode 100644 index 820c46e..0000000 --- a/src/app/core/models/carnet/payment.ts +++ /dev/null @@ -1,2 +0,0 @@ -export interface Payment { -} diff --git a/src/app/core/models/carnet/shipping-address.ts b/src/app/core/models/carnet/shipping-address.ts new file mode 100644 index 0000000..ea647c4 --- /dev/null +++ b/src/app/core/models/carnet/shipping-address.ts @@ -0,0 +1,8 @@ +export interface ShippingAddress { + address1: string; + address2?: string | null; + city: string; + state: string; + country: string; + zip: string; +} diff --git a/src/app/core/models/carnet/shipping-contact.ts b/src/app/core/models/carnet/shipping-contact.ts new file mode 100644 index 0000000..39d532f --- /dev/null +++ b/src/app/core/models/carnet/shipping-contact.ts @@ -0,0 +1,12 @@ +export interface ShippingContact { + firstName: string; + lastName: string; + middleInitial?: string | null; + title: string; + phone: string; + mobile: string; + fax?: string | null; + email: string; + refNumber?: string | null; + notes?: string | null; +} diff --git a/src/app/core/models/carnet/shipping.ts b/src/app/core/models/carnet/shipping.ts index a1b72da..a191c7b 100644 --- a/src/app/core/models/carnet/shipping.ts +++ b/src/app/core/models/carnet/shipping.ts @@ -1,2 +1,23 @@ +import { ShippingAddress } from "./shipping-address"; +import { ShippingContact } from "./shipping-contact"; + export interface Shipping { + // Insurance details + needsBond: boolean; + needsInsurance: boolean; + needsLostDocProtection: boolean; + + // Shipping details + shipTo: string; + address?: ShippingAddress; + contact?: ShippingContact; + + // Delivery details + deliveryType: string; + deliveryMethod: string; + courierAccount?: string; + + // Payment details + paymentMethod: string; + notes?: string; } diff --git a/src/app/core/models/delivery-method.ts b/src/app/core/models/delivery-method.ts new file mode 100644 index 0000000..1adc1f1 --- /dev/null +++ b/src/app/core/models/delivery-method.ts @@ -0,0 +1,5 @@ +export interface DeliveryMethod { + name: string; + id: string; + value: string; +} diff --git a/src/app/core/models/payment-type.ts b/src/app/core/models/payment-type.ts new file mode 100644 index 0000000..10baebb --- /dev/null +++ b/src/app/core/models/payment-type.ts @@ -0,0 +1,5 @@ +export interface PaymentType { + name: string; + id: string; + value: string; +} diff --git a/src/app/core/services/carnet/delivery.service.ts b/src/app/core/services/carnet/delivery.service.ts deleted file mode 100644 index b5dec8a..0000000 --- a/src/app/core/services/carnet/delivery.service.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class DeliveryService { - - constructor() { } -} diff --git a/src/app/core/services/carnet/payment.service.ts b/src/app/core/services/carnet/payment.service.ts deleted file mode 100644 index f58bf94..0000000 --- a/src/app/core/services/carnet/payment.service.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class PaymentService { - - constructor() { } -} diff --git a/src/app/core/services/carnet/shipping.service.ts b/src/app/core/services/carnet/shipping.service.ts index 227ebda..b045e2e 100644 --- a/src/app/core/services/carnet/shipping.service.ts +++ b/src/app/core/services/carnet/shipping.service.ts @@ -1,9 +1,103 @@ -import { Injectable } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; +import { environment } from '../../../../environments/environment'; +import { HttpClient } from '@angular/common/http'; +import { filter, map, Observable } from 'rxjs'; +import { UserService } from '../common/user.service'; +import { Shipping } from '../../models/carnet/shipping'; @Injectable({ providedIn: 'root' }) export class ShippingService { + private apiUrl = environment.apiUrl; + private apiDb = environment.apiDb; - constructor() { } + private http = inject(HttpClient); + private userService = inject(UserService); + + getShippingData(headerid: number): Shipping | any { + return this.http.get(`${this.apiUrl}/${this.apiDb}/GetShipPaymentDetailstoEdit/${this.userService.getUserSpid()}/${this.userService.getUser()}/${headerid}`).pipe( + filter(response => response.length > 0), + map(response => this.mapToShippingData(response?.[0]))); + } + + private mapToShippingData(shippingDetails: any): Shipping { + + let shippingData: Shipping = { + shipTo: shippingDetails.SHIPADDRTYPE, + deliveryType: shippingDetails.DELIVERYTYPE, + deliveryMethod: shippingDetails.DELIVERYMETHOD, + courierAccount: shippingDetails.CUSTCOURIERNO, + paymentMethod: shippingDetails.PAYMENTMETHOD, + + notes: shippingDetails.NOTES, + needsBond: shippingDetails.INSPROTECTION === 'Y', + needsInsurance: shippingDetails.LDIPROTECTION === 'Y', + needsLostDocProtection: shippingDetails.LDIPROTECTION === 'Y' + }; + + if (shippingDetails.address) { + shippingData.address = { + address1: shippingDetails.ADDRESS1, + address2: shippingDetails.ADDRESS2, + city: shippingDetails.CITY, + state: shippingDetails.STATE, + zip: shippingDetails.ZIP, + country: shippingDetails.COUNTRY + } + } + + if (shippingDetails.contact) { + shippingData.contact = { + firstName: shippingDetails.FIRSTNAME, + lastName: shippingDetails.LASTNAME, + middleInitial: shippingDetails.MIDDLEINITIAL, + title: shippingDetails.TITLE, + phone: shippingDetails.PHONENO, + mobile: shippingDetails.MOBILENO, + fax: shippingDetails.FAXNO, + email: shippingDetails.EMAILADDRESS, + refNumber: shippingDetails.REFNO, + } + } + + return shippingData; + } + + saveShippingDetails(headerid: number, shippingData: Shipping): Observable { + + const shippingDetails = { + P_HEADERID: headerid, + P_SHIPTOTYPE: shippingData.shipTo, + P_DELIVERYTYPE: shippingData.deliveryType, + P_DELIVERYMETHOD: shippingData.deliveryMethod, + P_CUSTCOURIERNO: shippingData.courierAccount, + P_PAYMENTMETHOD: shippingData.paymentMethod, + P_NOTES: shippingData.notes, + + P_FORMOFSECURITY: shippingData.needsBond ? 'Y' : 'N', + P_INSPROTECTION: shippingData.needsInsurance ? 'Y' : 'N', + P_LDIPROTECTION: shippingData.needsLostDocProtection ? 'Y' : 'N', + + address1: shippingData.address?.address1 || '', + address2: shippingData.address?.address2 || null, + city: shippingData.address?.city || '', + state: shippingData.address?.state || '', + zip: shippingData.address?.zip || '', + country: shippingData.address?.country || '', + + firstName: shippingData.contact?.firstName || '', + lastName: shippingData.contact?.lastName || '', + middleInitial: shippingData.contact?.middleInitial || null, + title: shippingData.contact?.title || '', + phone: shippingData.contact?.phone || '', + mobile: shippingData.contact?.mobile || '', + fax: shippingData.contact?.fax || null, + emailAddress: shippingData.contact?.email || '', + refNo: shippingData.contact?.refNumber || '', + P_USERID: this.userService.getUser() + } + + return this.http.patch(`${this.apiUrl}/${this.apiDb}/UpdateShippingDetails`, shippingDetails); + } } diff --git a/src/app/core/services/common/common.service.ts b/src/app/core/services/common/common.service.ts index e0c45ef..3e93f0e 100644 --- a/src/app/core/services/common/common.service.ts +++ b/src/app/core/services/common/common.service.ts @@ -13,6 +13,8 @@ import { CargoSurety } from '../../models/cargo-surety'; import { CarnetStatus } from '../../models/carnet-status'; import { Country } from '../../models/country'; import { UnitOfMeasure } from '../../models/unitofmeasure'; +import { DeliveryMethod } from '../../models/delivery-method'; +import { PaymentType } from '../../models/payment-type'; @Injectable({ providedIn: 'root' @@ -156,7 +158,30 @@ export class CommonService { name: item.PARAMDESC, id: item.PARAMID, value: item.PARAMVALUE, - color: item.ADDLPARAMVALUE1, + })) + ) + ); + } + + getDeliveryMethods(_spid: number = 0): Observable { + return this.http.get(`${this.apiUrl}/${this.apiDb}/GetParamValues?P_PARAMTYPE=007&P_SPID=0`).pipe( + map((response) => + response.map((item) => ({ + name: item.PARAMDESC, + id: item.PARAMID, + value: item.PARAMVALUE, + })) + ) + ); + } + + getPaymentTypes(_spid: number = 0): Observable { + return this.http.get(`${this.apiUrl}/${this.apiDb}/GetParamValues?P_PARAMTYPE=008&P_SPID=0`).pipe( + map((response) => + response.map((item) => ({ + name: item.PARAMDESC, + id: item.PARAMID, + value: item.PARAMVALUE, })) ) ); diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html index 90acb7e..0a392d6 100644 --- a/src/app/home/home.component.html +++ b/src/app/home/home.component.html @@ -11,7 +11,7 @@
- Do you need a new carnet? + Do you need a new carnet? Yes No @@ -19,7 +19,7 @@
- Do you need additional sets? + Do you need additional sets? Yes No @@ -27,7 +27,8 @@
- Did you lose your carnet? Are you looking for duplicates? + Did you lose your carnet? Are you looking for + duplicates? Yes No @@ -35,7 +36,7 @@
- Do you need to extend the carnet? + Do you need to extend the carnet? Yes No diff --git a/src/app/home/home.component.scss b/src/app/home/home.component.scss index 48a842b..7dd0a34 100644 --- a/src/app/home/home.component.scss +++ b/src/app/home/home.component.scss @@ -21,9 +21,12 @@ .questions-section { flex: 0 0 70%; - padding: 24px 0px; - margin-bottom: 24px; + padding: 12px 16px; + margin-bottom: 46px; margin-left: 1rem; + margin-top: 24px; + background: var(--mat-sys-surface); + border-radius: 4px; .question-row { margin-bottom: 1rem; @@ -32,6 +35,15 @@ display: flex; gap: 8px; + .question { + color: var(--mat-sys-on-surface); + font-family: var(--mat-sys-body-medium-font); + line-height: var(--mat-sys-body-medium-line-height); + font-size: var(--mat-sys-body-medium-size); + letter-spacing: var(--mat-sys-body-medium-tracking); + font-weight: var(--mat-sys-medium-font-weight); + } + mat-radio-button { margin-top: -5px; }