service-provider-app/src/app/preparer/location/location.component.ts

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