277 lines
8.9 KiB
TypeScript
277 lines
8.9 KiB
TypeScript
import { Component, EventEmitter, inject, Input, Output, ViewChild } from '@angular/core';
|
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
|
import { CommonModule } from '@angular/common';
|
|
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
|
import { MatPaginator, MatPaginatorIntl } from '@angular/material/paginator';
|
|
import { MatSort } from '@angular/material/sort';
|
|
import { MatTableDataSource } from '@angular/material/table';
|
|
import { UserPreferences } from '../../core/models/user-preference';
|
|
import { Location } from '../../core/models/preparer/location';
|
|
import { LocationService } from '../../core/services/preparer/location.service';
|
|
import { NotificationService } from '../../core/services/common/notification.service';
|
|
import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service';
|
|
import { CustomPaginator } from '../../shared/custom-paginator';
|
|
import { ZipCodeValidator } from '../../shared/validators/zipcode-validator';
|
|
import { Country } from '../../core/models/country';
|
|
import { State } from '../../core/models/state';
|
|
import { finalize, Subject, takeUntil } from 'rxjs';
|
|
import { CommonService } from '../../core/services/common/common.service';
|
|
|
|
@Component({
|
|
selector: 'app-location',
|
|
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule],
|
|
templateUrl: './location.component.html',
|
|
styleUrl: './location.component.scss',
|
|
providers: [{ provide: MatPaginatorIntl, useClass: CustomPaginator }],
|
|
})
|
|
export class LocationComponent {
|
|
@ViewChild(MatPaginator, { static: false })
|
|
set paginator(value: MatPaginator) {
|
|
this.dataSource.paginator = value;
|
|
}
|
|
|
|
@ViewChild(MatSort) sort!: MatSort;
|
|
|
|
displayedColumns: string[] = ['name', 'address', 'city', 'state', 'country', 'actions'];
|
|
dataSource = new MatTableDataSource<any>();
|
|
locationForm: FormGroup;
|
|
isEditing = false;
|
|
currentLocationId: number | null = null;
|
|
isLoading = false;
|
|
changeInProgress = false;
|
|
showForm = false;
|
|
countries: Country[] = [];
|
|
states: State[] = [];
|
|
|
|
locationReadOnlyFields: any = {
|
|
lastChangedDate: null,
|
|
lastChangedBy: null,
|
|
isInactive: null,
|
|
inactivatedDate: null
|
|
};
|
|
|
|
@Input() clientid: number = 0;
|
|
@Input() userPreferences: UserPreferences = {};
|
|
@Output() hasLocations = new EventEmitter<boolean>();
|
|
@Output() updated = new EventEmitter<boolean>();
|
|
|
|
countriesHasStates = ['US', 'CA', 'MX'];
|
|
|
|
private destroy$ = new Subject<void>();
|
|
|
|
private fb = inject(FormBuilder);
|
|
private locationService = inject(LocationService);
|
|
private notificationService = inject(NotificationService);
|
|
private errorHandler = inject(ApiErrorHandlerService);
|
|
private commonService = inject(CommonService);
|
|
|
|
constructor() {
|
|
this.locationForm = this.fb.group({
|
|
name: ['', [Validators.required, Validators.maxLength(100)]],
|
|
address1: ['', [Validators.required, Validators.maxLength(100)]],
|
|
address2: ['', [Validators.maxLength(100)]],
|
|
city: ['', [Validators.required, Validators.maxLength(50)]],
|
|
state: ['', Validators.required],
|
|
country: ['US', Validators.required],
|
|
zip: ['', [Validators.required, ZipCodeValidator('country')]],
|
|
});
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
this.loadCountries();
|
|
this.loadLocations();
|
|
}
|
|
|
|
ngAfterViewInit() {
|
|
this.dataSource.paginator = this.paginator;
|
|
this.dataSource.sort = this.sort;
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
this.destroy$.next();
|
|
this.destroy$.complete();
|
|
}
|
|
|
|
public refreshLocationData(): void {
|
|
this.loadLocations();
|
|
}
|
|
|
|
loadLocations(): void {
|
|
this.isLoading = true;
|
|
|
|
this.locationService.getLocationsById(this.clientid).pipe(finalize(() => {
|
|
this.isLoading = false;
|
|
})).subscribe({
|
|
next: (locations: Location[]) => {
|
|
this.dataSource.data = locations;
|
|
},
|
|
error: (error: any) => {
|
|
let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load locations');
|
|
this.notificationService.showError(errorMessage);
|
|
console.error('Error loading locations:', error);
|
|
}
|
|
});
|
|
}
|
|
|
|
onCountryChange(country: string): void {
|
|
this.locationForm.get('state')?.reset();
|
|
|
|
if (country) {
|
|
this.loadStates(country);
|
|
}
|
|
|
|
this.locationForm.get('zip')?.updateValueAndValidity();
|
|
}
|
|
|
|
addNewLocation(): void {
|
|
this.showForm = true;
|
|
this.isEditing = false;
|
|
this.currentLocationId = null;
|
|
this.locationForm.reset();
|
|
|
|
this.locationForm.patchValue({
|
|
country: 'US'
|
|
});
|
|
this.loadStates('US');
|
|
}
|
|
|
|
editLocation(location: Location): void {
|
|
this.showForm = true;
|
|
this.isEditing = true;
|
|
this.currentLocationId = location.locationid;
|
|
this.locationForm.patchValue({
|
|
name: location.name,
|
|
address1: location.address1,
|
|
address2: location.address2,
|
|
city: location.city,
|
|
country: location.country,
|
|
state: location.state,
|
|
zip: location.zip,
|
|
});
|
|
|
|
if (location.country) {
|
|
this.loadStates(location.country);
|
|
}
|
|
|
|
this.locationReadOnlyFields.lastChangedDate = location.lastUpdatedDate ?? location.dateCreated;
|
|
this.locationReadOnlyFields.lastChangedBy = location.lastUpdatedBy ?? location.createdBy;
|
|
this.locationReadOnlyFields.isInactive = location.isInactive;
|
|
this.locationReadOnlyFields.inactivatedDate = location.inactivatedDate;
|
|
}
|
|
|
|
saveLocation(): void {
|
|
if (this.locationForm.invalid) {
|
|
this.locationForm.markAllAsTouched();
|
|
return;
|
|
}
|
|
|
|
// default the first location
|
|
const locationData: Location = this.locationForm.value;
|
|
|
|
const saveObservable = this.isEditing && (this.currentLocationId! > 0)
|
|
? this.locationService.updateLocation(this.currentLocationId!, locationData)
|
|
: this.locationService.createLocation(this.clientid, locationData);
|
|
|
|
this.changeInProgress = true;
|
|
saveObservable.pipe(finalize(() => this.changeInProgress = false)).subscribe({
|
|
next: () => {
|
|
this.notificationService.showSuccess(`Location ${this.isEditing ? 'updated' : 'added'} successfully`);
|
|
this.updated.emit(true); // to update dependent data
|
|
this.loadLocations();
|
|
this.cancelEdit();
|
|
this.hasLocations.emit(true);
|
|
},
|
|
error: (error) => {
|
|
let errorMessage = this.errorHandler.handleApiError(error, `Failed to ${this.isEditing ? 'update' : 'add'} location`);
|
|
this.notificationService.showError(errorMessage);
|
|
console.error('Error saving location:', error);
|
|
}
|
|
});
|
|
}
|
|
|
|
loadCountries(): void {
|
|
this.commonService.getCountries()
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe({
|
|
next: (countries) => {
|
|
this.countries = countries;
|
|
},
|
|
error: (error) => {
|
|
console.error('Failed to load countries', error);
|
|
}
|
|
});
|
|
}
|
|
|
|
loadStates(country: string): void {
|
|
this.isLoading = true;
|
|
country = this.countriesHasStates.includes(country) ? country : 'FN';
|
|
this.commonService.getStates(country)
|
|
.pipe(takeUntil(this.destroy$), finalize(() => {
|
|
this.isLoading = false;
|
|
}))
|
|
.subscribe({
|
|
next: (states) => {
|
|
this.states = states;
|
|
const stateControl = this.locationForm.get('state');
|
|
if (this.countriesHasStates.includes(country)) {
|
|
stateControl?.enable();
|
|
} else {
|
|
stateControl?.disable();
|
|
stateControl?.setValue('FN');
|
|
}
|
|
},
|
|
error: (error) => {
|
|
console.error('Failed to load states', error);
|
|
}
|
|
});
|
|
}
|
|
|
|
// deleteLocation(locationId: string): void {
|
|
// const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
|
// width: '350px',
|
|
// data: {
|
|
// title: 'Confirm Delete',
|
|
// message: 'Are you sure you want to delete this location?',
|
|
// confirmText: 'Delete',
|
|
// cancelText: 'Cancel'
|
|
// }
|
|
// });
|
|
|
|
// dialogRef.afterClosed().subscribe(result => {
|
|
// if (result) {
|
|
// this.locationService.deleteLocation(locationId).subscribe({
|
|
// next: () => {
|
|
// this.notificationService.showSuccess('Location deleted successfully');
|
|
// this.loadLocations();
|
|
// },
|
|
// error: (error) => {
|
|
// let errorMessage = this.errorHandler.handleApiError(error, 'Failed to delete location');
|
|
// this.notificationService.showError(errorMessage);
|
|
// console.error('Error deleting location:', error);
|
|
// }
|
|
// });
|
|
// }
|
|
// });
|
|
// }
|
|
|
|
getAddressLabel(address1: string, address2?: string): string {
|
|
let addressLabel = address1;
|
|
if (address2) {
|
|
addressLabel += `, ${address2}`;
|
|
}
|
|
return addressLabel;
|
|
}
|
|
|
|
getCountryLabel(value: string): string {
|
|
const country = this.countries.find(c => c.value === value);
|
|
return country ? country.name : value;
|
|
}
|
|
|
|
cancelEdit(): void {
|
|
this.showForm = false;
|
|
this.isEditing = false;
|
|
this.currentLocationId = null;
|
|
this.locationForm.reset();
|
|
}
|
|
}
|