From 882d73c24860268428e2b469aec84d486458e8d9 Mon Sep 17 00:00:00 2001 From: Cyril Joseph Date: Sat, 2 Aug 2025 23:24:17 -0300 Subject: [PATCH] ui and feedback updates --- src/app/app.routes.server.ts | 2 + src/app/app.routes.ts | 2 + src/app/common/footer/footer.component.html | 2 +- src/app/common/footer/footer.component.ts | 19 +- .../secured-header.component.html | 32 +-- src/app/core/models/param/parameters.ts | 22 ++ src/app/core/models/param/types.ts | 1 + .../core/models/service-provider/basic-fee.ts | 1 + .../models/service-provider/carnet-fee.ts | 1 + .../continuation-sheet-fee.ts | 1 + .../service-provider/counterfoil-fee.ts | 1 + .../models/service-provider/expedited-fee.ts | 1 + .../service-provider/security-deposit.ts | 1 + src/app/core/models/user.ts | 1 + .../core/services/common/common.service.ts | 38 +-- src/app/core/services/common/user.service.ts | 3 +- src/app/core/services/home.service.ts | 11 +- src/app/core/services/param/param.service.ts | 110 +++++++ .../service-provider/basic-fee.service.ts | 3 +- .../service-provider/carnet-fee.service.ts | 3 +- .../service-provider/contact.service.ts | 3 +- .../continuation-sheet-fee.service.ts | 3 +- .../counterfoil-fee.service.ts | 3 +- .../service-provider/expedited-fee.service.ts | 3 +- .../security-deposit.service.ts | 3 +- src/app/home/home.component.html | 32 +++ src/app/home/home.component.ts | 117 +++++++- .../manage-param-record.component.html | 1 + .../manage-param-record.component.scss | 0 .../manage-param-record.component.ts | 22 ++ .../manage-table-record.component.html | 1 + .../manage-table-record.component.scss | 0 .../manage-table-record.component.ts | 14 + .../param/table/param-table.component.html | 266 +++++++++++++++++ .../param/table/param-table.component.scss | 185 ++++++++++++ src/app/param/table/param-table.component.ts | 269 ++++++++++++++++++ .../preparer/add/add-preparer.component.html | 7 +- .../preparer/add/add-preparer.component.ts | 18 +- .../basic-details.component.html | 5 +- .../basic-details/basic-details.component.ts | 28 +- .../preparer/contacts/contacts.component.html | 47 +-- .../preparer/contacts/contacts.component.ts | 93 +++--- .../edit/edit-preparer.component.html | 3 +- .../preparer/edit/edit-preparer.component.ts | 10 +- .../preparer/location/location.component.html | 3 +- .../preparer/location/location.component.ts | 32 +-- .../basic-details.component.html | 5 +- .../basic-details/basic-details.component.ts | 43 +-- .../basic-fee/basic-fee.component.html | 8 +- .../basic-fee/basic-fee.component.scss | 10 + .../basic-fee/basic-fee.component.ts | 43 ++- .../carnet-fee/carnet-fee.component.html | 6 +- .../carnet-fee/carnet-fee.component.scss | 5 + .../carnet-fee/carnet-fee.component.ts | 32 ++- .../carnet-sequence.component.html | 3 +- .../carnet-sequence.component.ts | 23 +- .../contacts/contacts.component.html | 7 +- .../contacts/contacts.component.scss | 5 + .../contacts/contacts.component.ts | 37 ++- .../continuation-sheet-fee.component.html | 6 +- .../continuation-sheet-fee.component.scss | 5 + .../continuation-sheet-fee.component.ts | 33 ++- .../counterfoil-fee.component.html | 6 +- .../counterfoil-fee.component.scss | 5 + .../counterfoil-fee.component.ts | 32 ++- .../expedited-fee.component.html | 6 +- .../expedited-fee.component.scss | 5 + .../expedited-fee/expedited-fee.component.ts | 38 ++- .../security-deposit.component.html | 6 +- .../security-deposit.component.scss | 5 + .../security-deposit.component.ts | 36 ++- src/app/shared/pipes/proper-case.pipe.ts | 15 + 72 files changed, 1562 insertions(+), 286 deletions(-) create mode 100644 src/app/core/models/param/parameters.ts create mode 100644 src/app/core/models/param/types.ts create mode 100644 src/app/core/services/param/param.service.ts create mode 100644 src/app/param/manage-param-record/manage-param-record.component.html create mode 100644 src/app/param/manage-param-record/manage-param-record.component.scss create mode 100644 src/app/param/manage-param-record/manage-param-record.component.ts create mode 100644 src/app/param/manage-table-record/manage-table-record.component.html create mode 100644 src/app/param/manage-table-record/manage-table-record.component.scss create mode 100644 src/app/param/manage-table-record/manage-table-record.component.ts create mode 100644 src/app/param/table/param-table.component.html create mode 100644 src/app/param/table/param-table.component.scss create mode 100644 src/app/param/table/param-table.component.ts create mode 100644 src/app/shared/pipes/proper-case.pipe.ts diff --git a/src/app/app.routes.server.ts b/src/app/app.routes.server.ts index 23350c9..959b2db 100644 --- a/src/app/app.routes.server.ts +++ b/src/app/app.routes.server.ts @@ -9,6 +9,8 @@ export const serverRoutes: ServerRoute[] = [ { path: ':appId/preparer', renderMode: RenderMode.Client }, { path: ':appId/preparer/:id', renderMode: RenderMode.Client }, { path: ':appId/add-preparer', renderMode: RenderMode.Client }, + { path: ':appId/table-record', renderMode: RenderMode.Client }, + { path: ':appId/add-preparer', renderMode: RenderMode.Client }, { path: '**', renderMode: RenderMode.Prerender diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index d36dc1c..ba68ece 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -17,6 +17,8 @@ export const routes: Routes = [ { path: 'preparer', loadComponent: () => import('./preparer/manage/manage-preparer.component').then(m => m.ManagePreparerComponent) }, { path: 'preparer/:id', loadComponent: () => import('./preparer/edit/edit-preparer.component').then(m => m.EditPreparerComponent) }, { path: 'add-preparer', loadComponent: () => import('./preparer/add/add-preparer.component').then(m => m.AddPreparerComponent) }, + { path: 'table-record', loadComponent: () => import('./param/manage-table-record/manage-table-record.component').then(m => m.ManageTableRecordComponent) }, + { path: 'param-record/:id', loadComponent: () => import('./param/manage-param-record/manage-param-record.component').then(m => m.ManageParamRecordComponent) }, { path: '', redirectTo: 'home', pathMatch: 'full' } ], canActivate: [AuthGuard, AppIdGuard] diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index 0a8b626..01d4752 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -7,7 +7,7 @@ \ No newline at end of file diff --git a/src/app/common/footer/footer.component.ts b/src/app/common/footer/footer.component.ts index 2f94b31..ba744bb 100644 --- a/src/app/common/footer/footer.component.ts +++ b/src/app/common/footer/footer.component.ts @@ -1,6 +1,8 @@ -import { Component, Input } from '@angular/core'; +import { Component, effect, inject, Input } from '@angular/core'; import { AngularMaterialModule } from '../../shared/module/angular-material.module'; import { CommonModule } from '@angular/common'; +import { User } from '../../core/models/user'; +import { UserService } from '../../core/services/common/user.service'; @Component({ selector: 'app-footer', @@ -10,5 +12,20 @@ import { CommonModule } from '@angular/common'; }) export class FooterComponent { currentYear = new Date().getFullYear(); + currentServiceProviderName: string = ''; + userDetails: User | null = {}; + @Input() isUserLoggedIn = false; + + private userService = inject(UserService); + + constructor( + ) { + effect(() => { + this.userDetails = this.userService.userDetailsSignal(); + if (this.userDetails?.userDetails) { + this.currentServiceProviderName = this.userDetails.userDetails.serviceProviderName || ''; + } + }); + } } \ No newline at end of file diff --git a/src/app/common/secured-header/secured-header.component.html b/src/app/common/secured-header/secured-header.component.html index 59343fd..7721448 100644 --- a/src/app/common/secured-header/secured-header.component.html +++ b/src/app/common/secured-header/secured-header.component.html @@ -6,33 +6,14 @@
-
diff --git a/src/app/preparer/basic-details/basic-details.component.ts b/src/app/preparer/basic-details/basic-details.component.ts index c712b56..ce672dc 100644 --- a/src/app/preparer/basic-details/basic-details.component.ts +++ b/src/app/preparer/basic-details/basic-details.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, inject, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; -import { Subject, takeUntil } from 'rxjs'; +import { finalize, Subject, takeUntil } from 'rxjs'; import { AngularMaterialModule } from '../../shared/module/angular-material.module'; import { CommonModule } from '@angular/common'; import { Country } from '../../core/models/country'; @@ -35,6 +35,7 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { states: State[] = []; isLoading = true; + changeInProgress = false; countriesHasStates = ['US', 'CA', 'MX']; private destroy$ = new Subject(); @@ -55,18 +56,18 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { // this.spidCreated.emit(this.spid?.toString()); // Patch edit form data if (this.clientid > 0) { - this.basicDetailService.getBasicDetailsById(this.clientid).subscribe({ + this.basicDetailService.getBasicDetailsById(this.clientid).pipe(finalize(() => { + this.isLoading = false; + })).subscribe({ next: (basicDetail: BasicDetail) => { if (basicDetail?.clientid > 0) { this.patchFormData(basicDetail); this.clientName.emit(basicDetail.name); } - this.isLoading = false; }, error: (error: any) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load basic details'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading basic details:', error); } }); @@ -97,7 +98,7 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { } loadLookupData(): void { - this.commonService.getCountries(0) + this.commonService.getCountries() .pipe(takeUntil(this.destroy$)) .subscribe({ next: (countries) => { @@ -105,7 +106,6 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { }, error: (error) => { console.error('Failed to load countries', error); - this.isLoading = false; } }); @@ -118,11 +118,9 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { .subscribe({ next: (regions) => { this.regions = regions; - this.isLoading = false; }, error: (error) => { console.error('Failed to load regions', error); - this.isLoading = false; } }); } @@ -130,18 +128,17 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { loadStates(country: string): void { this.isLoading = true; country = this.countriesHasStates.includes(country) ? country : 'FN'; - this.commonService.getStates(country, this.clientid) - .pipe(takeUntil(this.destroy$)) + this.commonService.getStates(country) + .pipe(takeUntil(this.destroy$), + finalize(() => this.isLoading = false)) .subscribe({ next: (states) => { this.states = states; this.updateStateControl('state', country); this.updateStateControl('revenueLocation', country); - this.isLoading = false; }, error: (error) => { console.error('Failed to load states', error); - this.isLoading = false; } }); } @@ -218,13 +215,18 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { ? this.basicDetailService.updateBasicDetails(this.clientid, basicDetailData) : this.basicDetailService.createBasicDetails(basicDetailData); - saveObservable.subscribe({ + this.changeInProgress = true; + saveObservable.pipe(finalize(() => this.changeInProgress = false)).subscribe({ next: (basicData: any) => { this.notificationService.showSuccess(`Basic details ${this.isEditMode ? 'updated' : 'added'} successfully`); if (!this.isEditMode) { this.clientidCreated.emit(basicData.CLIENTID); this.saveLocation(basicData.CLIENTID, basicDetailData); + + // change to edit mode after creation + this.isEditMode = true; + this.clientid = basicData.CLIENTID; } if (this.isEditMode) { diff --git a/src/app/preparer/contacts/contacts.component.html b/src/app/preparer/contacts/contacts.component.html index 3a7dd55..6fc64d5 100644 --- a/src/app/preparer/contacts/contacts.component.html +++ b/src/app/preparer/contacts/contacts.component.html @@ -69,7 +69,7 @@ edit @@ -269,53 +269,12 @@
-
- - -
- -
-
-

Create Login

-
- -
-
-
- -
- -
- {{contactLoginReadOnlyFields.email}} -
-
-
-
-
- - -
- - -
-
-
\ No newline at end of file diff --git a/src/app/preparer/contacts/contacts.component.ts b/src/app/preparer/contacts/contacts.component.ts index a0bd1a6..1db6991 100644 --- a/src/app/preparer/contacts/contacts.component.ts +++ b/src/app/preparer/contacts/contacts.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, inject, Input, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { Component, EventEmitter, inject, Input, Output, ViewChild } from '@angular/core'; import { MatPaginator, MatPaginatorIntl } from '@angular/material/paginator'; import { CustomPaginator } from '../../shared/custom-paginator'; import { AngularMaterialModule } from '../../shared/module/angular-material.module'; @@ -17,6 +17,7 @@ import { ConfirmDialogComponent } from '../../shared/components/confirm-dialog/c import { ContactLogin } from '../../core/models/preparer/contact-login'; import { LocationService } from '../../core/services/preparer/location.service'; import { Location } from '../../core/models/preparer/location'; +import { finalize } from 'rxjs'; @Component({ selector: 'app-contacts', @@ -32,12 +33,12 @@ export class ContactsComponent { displayedColumns: string[] = ['firstName', 'lastName', 'title', 'phone', 'mobile', 'email', 'defaultContact', 'actions']; dataSource = new MatTableDataSource(); contactForm: FormGroup; - // contactLoginForm: FormGroup; + // contactLoginForm: FormGroup; isEditing = false; currentContactId: number | null = null; isLoading = false; + changeInProgress = false; showForm = false; - showLoginForm = false showInactiveContacts = false; contacts: Contact[] = []; locations: Location[] = []; @@ -55,7 +56,6 @@ export class ContactsComponent { @Input() clientid: number = 0; @Input() userPreferences: UserPreferences = {}; - @Input() refreshLocationData = false; @Output() hasContacts = new EventEmitter(); private fb = inject(FormBuilder); @@ -71,9 +71,9 @@ export class ContactsComponent { 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}$/)]], + 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)]], locationid: [''], defaultContact: [false] @@ -93,24 +93,19 @@ export class ContactsComponent { this.dataSource.sort = this.sort; } - ngOnChanges(changes: SimpleChanges) { - if (changes['refreshLocationData']) { - this.loadLocations(); - } + public refreshLocationData() { + this.loadLocations(); } loadLocations(): void { - this.isLoading = true; this.locationService.getLocationsById(this.clientid).subscribe({ next: (locations: Location[]) => { this.locations = locations; this.loadContacts(); - this.isLoading = false; }, error: (error: any) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load locations'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading locations:', error); } }); @@ -119,16 +114,16 @@ export class ContactsComponent { loadContacts(): void { this.isLoading = true; - this.contactService.getContactsById(this.clientid).subscribe({ + this.contactService.getContactsById(this.clientid).pipe(finalize(() => { + this.isLoading = false; + })).subscribe({ next: (contacts: Contact[]) => { this.contacts = contacts; this.renderContacts(); - this.isLoading = false; }, error: (error: any) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load contacts'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading contacts:', error); } }); @@ -136,7 +131,6 @@ export class ContactsComponent { addNewContact(): void { this.showForm = true; - this.showLoginForm = false; this.isEditing = false; this.currentContactId = null; this.contactForm.reset(); @@ -146,7 +140,6 @@ export class ContactsComponent { editContact(contact: Contact): void { this.showForm = true; - this.showLoginForm = false; this.isEditing = true; this.currentContactId = contact.clientContactId; this.contactForm.patchValue({ @@ -184,7 +177,8 @@ export class ContactsComponent { ? this.contactService.updateContact(this.currentContactId!, contactData) : this.contactService.createContact(contactData); - saveObservable.subscribe({ + this.changeInProgress = true; + saveObservable.pipe(finalize(() => this.changeInProgress = false)).subscribe({ next: () => { this.notificationService.showSuccess(`Contact ${this.isEditing ? 'updated' : 'added'} successfully`); this.loadContacts(); @@ -268,47 +262,44 @@ export class ContactsComponent { }); } - createLogin(contact: Contact): void { - this.showForm = false; - this.showLoginForm = true; - this.isEditing = true; - this.currentContactId = contact.clientContactId; + createLogin(contactId: string): void { + const dialogRef = this.dialog.open(ConfirmDialogComponent, { + width: '350px', + data: { + title: 'Confirm Login Creation', + message: 'Are you sure you want to create a login for this contact?', + confirmText: 'Yes', + cancelText: 'Cancel' + } + }); - this.contactLoginReadOnlyFields.email = contact.email; - } - - saveLogin(): void { - // if (this.contactLoginForm.invalid) { - // this.contactLoginForm.markAllAsTouched(); - // return; - // } - - const contactLoginData: ContactLogin = { - clientContactId: this.currentContactId!, - // password: this.contactLoginForm.value.password - }; - - this.contactService.createContactLogin(contactLoginData).subscribe({ - next: () => { - this.notificationService.showSuccess(`Login created successfully`); - this.loadContacts(); - this.cancelEdit(); - }, - error: (error) => { - let errorMessage = this.errorHandler.handleApiError(error, `Failed to create login`); - this.notificationService.showError(errorMessage); - console.error('Error saving login:', error); + dialogRef.afterClosed().subscribe(result => { + if (result) { + const contactLoginData: ContactLogin = { + clientContactId: +contactId + }; + this.contactService.createContactLogin(contactLoginData).subscribe({ + next: () => { + this.notificationService.showSuccess(`Login created successfully`); + this.loadContacts(); + this.cancelEdit(); + }, + error: (error) => { + let errorMessage = this.errorHandler.handleApiError(error, `Failed to create login`); + this.notificationService.showError(errorMessage); + console.error('Error saving login:', error); + } + }); } }); } cancelEdit(): void { this.showForm = false; - this.showLoginForm = false; this.isEditing = false; this.currentContactId = null; this.contactForm.reset(); - // this.contactLoginForm.reset(); + // this.contactLoginForm.reset(); } // setDefaultContact(contactId: string): void { diff --git a/src/app/preparer/edit/edit-preparer.component.html b/src/app/preparer/edit/edit-preparer.component.html index c7bd2cd..e1be28c 100644 --- a/src/app/preparer/edit/edit-preparer.component.html +++ b/src/app/preparer/edit/edit-preparer.component.html @@ -26,8 +26,7 @@ Contacts - + \ No newline at end of file diff --git a/src/app/preparer/edit/edit-preparer.component.ts b/src/app/preparer/edit/edit-preparer.component.ts index b7ddbac..f4af96d 100644 --- a/src/app/preparer/edit/edit-preparer.component.ts +++ b/src/app/preparer/edit/edit-preparer.component.ts @@ -1,4 +1,4 @@ -import { afterNextRender, Component, inject, viewChild } from '@angular/core'; +import { afterNextRender, Component, inject, ViewChild, viewChild } from '@angular/core'; import { AngularMaterialModule } from '../../shared/module/angular-material.module'; import { BasicDetailsComponent } from '../basic-details/basic-details.component'; import { ContactsComponent } from '../contacts/contacts.component'; @@ -21,7 +21,9 @@ export class EditPreparerComponent { clientid = 0; clientName: string | null = null; userPreferences: UserPreferences; - refreshLocationData: boolean = false; + + @ViewChild(ContactsComponent, { static: false }) + private contactsComponent!: ContactsComponent; private route = inject(ActivatedRoute); @@ -43,6 +45,8 @@ export class EditPreparerComponent { } onLocationUpdated(updated: boolean): void { - this.refreshLocationData = updated; + if (updated) { + this.contactsComponent?.refreshLocationData(); + } } } diff --git a/src/app/preparer/location/location.component.html b/src/app/preparer/location/location.component.html index afe3f8b..1b53f82 100644 --- a/src/app/preparer/location/location.component.html +++ b/src/app/preparer/location/location.component.html @@ -210,7 +210,8 @@
- diff --git a/src/app/preparer/location/location.component.ts b/src/app/preparer/location/location.component.ts index 93ae3ab..31c5fe4 100644 --- a/src/app/preparer/location/location.component.ts +++ b/src/app/preparer/location/location.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, inject, Input, Output, SimpleChanges, ViewChild } from '@angular/core'; +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'; @@ -14,7 +14,7 @@ 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 { Subject, takeUntil } from 'rxjs'; +import { finalize, Subject, takeUntil } from 'rxjs'; import { CommonService } from '../../core/services/common/common.service'; @Component({ @@ -34,6 +34,7 @@ export class LocationComponent { isEditing = false; currentLocationId: number | null = null; isLoading = false; + changeInProgress = false; showForm = false; countries: Country[] = []; states: State[] = []; @@ -47,7 +48,6 @@ export class LocationComponent { @Input() clientid: number = 0; @Input() userPreferences: UserPreferences = {}; - @Input() refreshLocationData: boolean = false; @Output() hasLocations = new EventEmitter(); @Output() updated = new EventEmitter(); @@ -88,24 +88,22 @@ export class LocationComponent { this.destroy$.complete(); } - ngOnChanges(changes: SimpleChanges) { - if (changes['refreshLocationData']) { - this.loadLocations(); - } + public refreshLocationData(): void { + this.loadLocations(); } loadLocations(): void { this.isLoading = true; - this.locationService.getLocationsById(this.clientid).subscribe({ + this.locationService.getLocationsById(this.clientid).pipe(finalize(() => { + this.isLoading = false; + })).subscribe({ next: (locations: Location[]) => { this.dataSource.data = locations; - this.isLoading = false; }, error: (error: any) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load locations'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading locations:', error); } }); @@ -170,7 +168,8 @@ export class LocationComponent { ? this.locationService.updateLocation(this.currentLocationId!, locationData) : this.locationService.createLocation(this.clientid, locationData); - saveObservable.subscribe({ + 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 @@ -187,7 +186,7 @@ export class LocationComponent { } loadCountries(): void { - this.commonService.getCountries(this.clientid) + this.commonService.getCountries() .pipe(takeUntil(this.destroy$)) .subscribe({ next: (countries) => { @@ -195,7 +194,6 @@ export class LocationComponent { }, error: (error) => { console.error('Failed to load countries', error); - this.isLoading = false; } }); } @@ -203,8 +201,10 @@ export class LocationComponent { loadStates(country: string): void { this.isLoading = true; country = this.countriesHasStates.includes(country) ? country : 'FN'; - this.commonService.getStates(country, this.clientid) - .pipe(takeUntil(this.destroy$)) + this.commonService.getStates(country) + .pipe(takeUntil(this.destroy$), finalize(() => { + this.isLoading = false; + })) .subscribe({ next: (states) => { this.states = states; @@ -215,11 +215,9 @@ export class LocationComponent { stateControl?.disable(); stateControl?.setValue('FN'); } - this.isLoading = false; }, error: (error) => { console.error('Failed to load states', error); - this.isLoading = false; } }); } diff --git a/src/app/service-provider/basic-details/basic-details.component.html b/src/app/service-provider/basic-details/basic-details.component.html index 20701a1..2dd09f0 100644 --- a/src/app/service-provider/basic-details/basic-details.component.html +++ b/src/app/service-provider/basic-details/basic-details.component.html @@ -176,8 +176,9 @@
-
diff --git a/src/app/service-provider/basic-details/basic-details.component.ts b/src/app/service-provider/basic-details/basic-details.component.ts index 308ecb2..84e87ee 100644 --- a/src/app/service-provider/basic-details/basic-details.component.ts +++ b/src/app/service-provider/basic-details/basic-details.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit, Output, EventEmitter, OnDestroy, inject } from '@angular/core'; import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { finalize, takeUntil } from 'rxjs/operators'; import { BasicDetail } from '../../core/models/service-provider/basic-detail'; import { Country } from '../../core/models/country'; import { Region } from '../../core/models/region'; @@ -38,6 +38,7 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { cargoPolicies: CargoPolicy[] = []; isLoading = true; + changeInProgress = false; countriesHasStates = ['US', 'CA', 'MX']; private destroy$ = new Subject(); @@ -57,21 +58,24 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { // this.spidCreated.emit(this.spid?.toString()); // Patch edit form data if (this.spid > 0) { - this.basicDetailService.getBasicDetailsById(this.spid).subscribe({ + this.isLoading = true; + this.basicDetailService.getBasicDetailsById(this.spid).pipe(finalize(() => { + this.isLoading = false; + })).subscribe({ next: (basicDetail: BasicDetail) => { if (basicDetail?.spid > 0) { this.patchFormData(basicDetail); this.serviceProviderName.emit(basicDetail.companyName); } - this.isLoading = false; }, error: (error: any) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load basic details'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading basic details:', error); } }); + } else { + this.loadStates('US'); } } @@ -87,7 +91,7 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { address1: ['', [Validators.required, Validators.maxLength(100)]], address2: ['', [Validators.maxLength(100)]], city: ['', [Validators.required, Validators.maxLength(50)]], - country: ['', Validators.required], + country: ['US', Validators.required], state: ['', Validators.required], zip: ['', [Validators.required, ZipCodeValidator('country')]], issuingRegion: ['', Validators.required], @@ -99,7 +103,7 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { } loadLookupData(): void { - this.commonService.getCountries(this.spid) + this.commonService.getCountries() .pipe(takeUntil(this.destroy$)) .subscribe({ next: (countries) => { @@ -107,7 +111,6 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { }, error: (error) => { console.error('Failed to load countries', error); - this.isLoading = false; } }); @@ -123,11 +126,9 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { .subscribe({ next: (regions) => { this.regions = regions; - this.isLoading = false; }, error: (error) => { console.error('Failed to load regions', error); - this.isLoading = false; } }); } @@ -135,9 +136,10 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { loadStates(country: string): void { this.isLoading = true; country = this.countriesHasStates.includes(country) ? country : 'FN'; - this.commonService.getStates(country, this.spid) - .pipe(takeUntil(this.destroy$)) - .subscribe({ + this.commonService.getStates(country) + .pipe(takeUntil(this.destroy$), finalize(() => { + this.isLoading = false; + })).subscribe({ next: (states) => { this.states = states; const stateControl = this.basicDetailsForm.get('state'); @@ -147,11 +149,9 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { stateControl?.disable(); stateControl?.setValue('FN'); } - this.isLoading = false; }, error: (error) => { console.error('Failed to load states', error); - this.isLoading = false; } }); } @@ -162,11 +162,9 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { .subscribe({ next: (bondSuretys) => { this.bondSuretys = bondSuretys; - this.isLoading = false; }, error: (error) => { console.error('Failed to load bond suretys', error); - this.isLoading = false; } }); } @@ -177,11 +175,9 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { .subscribe({ next: (cargoSuretys) => { this.cargoSuretys = cargoSuretys; - this.isLoading = false; }, error: (error) => { console.error('Failed to load cargo suretys', error); - this.isLoading = false; } }); } @@ -192,11 +188,9 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { .subscribe({ next: (cargoPolicies) => { this.cargoPolicies = cargoPolicies; - this.isLoading = false; }, error: (error) => { console.error('Failed to load cargo policies', error); - this.isLoading = false; } }); } @@ -220,6 +214,8 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { if (data.country) { this.loadStates(data.country); + } else { + this.loadStates('US'); } if (this.isEditMode) { @@ -270,12 +266,17 @@ export class BasicDetailsComponent implements OnInit, OnDestroy { ? this.basicDetailService.updateBasicDetails(this.spid, basicDetailData) : this.basicDetailService.createBasicDetails(basicDetailData); - saveObservable.subscribe({ + this.changeInProgress = true; + saveObservable.pipe(finalize(() => this.changeInProgress = false)).subscribe({ next: (basicData: any) => { this.notificationService.showSuccess(`Basic details ${this.isEditMode ? 'updated' : 'added'} successfully`); if (!this.isEditMode) { this.spidCreated.emit(basicData.SPID); + + // change to edit mode after creation + this.isEditMode = true; + this.spid = basicData.SPID; } }, error: (error) => { diff --git a/src/app/service-provider/basic-fee/basic-fee.component.html b/src/app/service-provider/basic-fee/basic-fee.component.html index 130e8e4..fede157 100644 --- a/src/app/service-provider/basic-fee/basic-fee.component.html +++ b/src/app/service-provider/basic-fee/basic-fee.component.html @@ -1,4 +1,9 @@
+
+ + Show Expired Records + +
@@ -136,7 +141,8 @@
- diff --git a/src/app/service-provider/basic-fee/basic-fee.component.scss b/src/app/service-provider/basic-fee/basic-fee.component.scss index 7b80d35..d3b55a6 100644 --- a/src/app/service-provider/basic-fee/basic-fee.component.scss +++ b/src/app/service-provider/basic-fee/basic-fee.component.scss @@ -4,6 +4,16 @@ flex-direction: column; gap: 24px; + .actions-bar { + clear: both; + margin-bottom: -16px; + + mat-slide-toggle { + transform: scale(0.8); + margin-left: -0.5rem; + } + } + .table-container { position: relative; overflow: auto; diff --git a/src/app/service-provider/basic-fee/basic-fee.component.ts b/src/app/service-provider/basic-fee/basic-fee.component.ts index 0c042b2..658f116 100644 --- a/src/app/service-provider/basic-fee/basic-fee.component.ts +++ b/src/app/service-provider/basic-fee/basic-fee.component.ts @@ -7,7 +7,7 @@ import { AngularMaterialModule } from '../../shared/module/angular-material.modu import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; import { CommonModule } from '@angular/common'; import { CustomPaginator } from '../../shared/custom-paginator'; -import { forkJoin } from 'rxjs'; +import { finalize, forkJoin } from 'rxjs'; import { UserPreferences } from '../../core/models/user-preference'; import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service'; import { NotificationService } from '../../core/services/common/notification.service'; @@ -30,7 +30,10 @@ export class BasicFeeComponent { isEditing = false; currentFeeId: number | null = null; isLoading = false; + changeInProgress = false; showForm = false; + showExpiredRecords = false; + basicFees: BasicFee[] = []; readOnlyFields: any = { lastChangedDate: null, @@ -67,11 +70,14 @@ export class BasicFeeComponent { loadBasicFees(): void { this.isLoading = true; - this.basicFeeService.getBasicFees(this.spid).subscribe({ + this.basicFeeService.getBasicFees(this.spid).pipe(finalize(() => { + this.isLoading = false; + })).subscribe({ next: (fees) => { - this.dataSource.data = fees; + this.basicFees = fees; + this.dataSource.data = this.basicFees; + this.renderRecods(); this.hasBasicFees.emit(fees.length > 0); - this.isLoading = false; if (this.dataSource.data.length == 0) { this.initializeDefaultFees(); @@ -80,14 +86,25 @@ export class BasicFeeComponent { error: (error) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load basic fees'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading basic fees:', error); } }); } + toggleShowExpiredRecords(): void { + this.showExpiredRecords = !this.showExpiredRecords; + this.renderRecods(); + } + + renderRecods(): void { + if (this.showExpiredRecords) { + this.dataSource.data = this.basicFees; + } else { + this.dataSource.data = this.basicFees.filter(record => !record.expired); + } + } + initializeDefaultFees(): void { - this.isLoading = true; const defaultFees: BasicFee[] = [ { basicFeeId: 0, startCarnetValue: 1, endCarnetValue: 9999, fees: 255, effectiveDate: new Date() }, { basicFeeId: 0, startCarnetValue: 10000, endCarnetValue: 49999, fees: 300, effectiveDate: new Date() }, @@ -102,14 +119,16 @@ export class BasicFeeComponent { this.basicFeeService.createBasicFee(this.spid, fee) ); + this.changeInProgress = true; + // Execute all creations in parallel and wait for all to complete - forkJoin(creationObservables).subscribe({ + forkJoin(creationObservables).pipe(finalize(() => { + this.changeInProgress = false; + })).subscribe({ next: () => { this.loadBasicFees(); // Refresh the list after all creations are done - this.isLoading = false; }, error: (error) => { - this.isLoading = false; console.error('Error initializing default fees:', error); // Even if some failed, try to load what was created this.loadBasicFees(); @@ -175,7 +194,11 @@ export class BasicFeeComponent { ? this.basicFeeService.updateBasicFee(this.currentFeeId, feeData) : this.basicFeeService.createBasicFee(this.spid, feeData); - saveObservable.subscribe({ + this.changeInProgress = true; + + saveObservable.pipe(finalize(() => { + this.changeInProgress = false; + })).subscribe({ next: () => { this.notificationService.showSuccess(`Basic fee ${this.isEditing ? 'updated' : 'added'} successfully`); this.loadBasicFees(); diff --git a/src/app/service-provider/carnet-fee/carnet-fee.component.html b/src/app/service-provider/carnet-fee/carnet-fee.component.html index 39c0420..58a694c 100644 --- a/src/app/service-provider/carnet-fee/carnet-fee.component.html +++ b/src/app/service-provider/carnet-fee/carnet-fee.component.html @@ -1,5 +1,8 @@
+ + Show Expired Records + @@ -123,7 +126,8 @@
- diff --git a/src/app/service-provider/carnet-fee/carnet-fee.component.scss b/src/app/service-provider/carnet-fee/carnet-fee.component.scss index ed58b0f..1b67170 100644 --- a/src/app/service-provider/carnet-fee/carnet-fee.component.scss +++ b/src/app/service-provider/carnet-fee/carnet-fee.component.scss @@ -8,6 +8,11 @@ clear: both; margin-bottom: -16px; + mat-slide-toggle { + transform: scale(0.8); + margin-left: -0.5rem; + } + button { float: right; } diff --git a/src/app/service-provider/carnet-fee/carnet-fee.component.ts b/src/app/service-provider/carnet-fee/carnet-fee.component.ts index f328546..d18a023 100644 --- a/src/app/service-provider/carnet-fee/carnet-fee.component.ts +++ b/src/app/service-provider/carnet-fee/carnet-fee.component.ts @@ -14,6 +14,7 @@ import { ApiErrorHandlerService } from '../../core/services/common/api-error-han import { CommonService } from '../../core/services/common/common.service'; import { NotificationService } from '../../core/services/common/notification.service'; import { CarnetFeeService } from '../../core/services/service-provider/carnet-fee.service'; +import { finalize } from 'rxjs'; @Component({ selector: 'app-carnet-fee', @@ -33,8 +34,11 @@ export class CarnetFeeComponent implements OnInit { isEditing = false; currentFeeCommissionId: number | null = null; isLoading = false; + changeInProgress = false; showForm = false; feeTypes: FeeType[] = []; + showExpiredRecords = false; + carnetFees: CarnetFee[] = []; readOnlyFields: any = { lastChangedDate: null, @@ -72,21 +76,36 @@ export class CarnetFeeComponent implements OnInit { loadFeeCommissions(): void { this.isLoading = true; - this.feeCommissionService.getFeeCommissions(this.spid).subscribe({ + this.feeCommissionService.getFeeCommissions(this.spid).pipe(finalize(() => { + this.isLoading = false; + })).subscribe({ next: (fees) => { - this.dataSource.data = fees; + this.carnetFees = fees; + this.dataSource.data = this.carnetFees; + this.renderRecods(); this.hasFeeCommissions.emit(fees.length > 0); - this.isLoading = false; }, error: (error) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load fee & commission data'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading fee & commission data:', error); } }); } + toggleShowExpiredRecords(): void { + this.showExpiredRecords = !this.showExpiredRecords; + this.renderRecods(); + } + + renderRecods(): void { + if (this.showExpiredRecords) { + this.dataSource.data = this.carnetFees; + } else { + this.dataSource.data = this.carnetFees.filter(record => !record.expired); + } + } + loadFeeTypes(): void { this.commonService.getFeeTypes().subscribe({ next: (types) => { @@ -151,7 +170,10 @@ export class CarnetFeeComponent implements OnInit { ? this.feeCommissionService.updateFeeCommission(this.currentFeeCommissionId, feeCommissionData) : this.feeCommissionService.createFeeCommission(this.spid, feeCommissionData); - saveObservable.subscribe({ + this.changeInProgress + saveObservable.pipe(finalize(() => { + this.changeInProgress = false; + })).subscribe({ next: () => { this.notificationService.showSuccess(`Fee & commission ${this.isEditing ? 'updated' : 'added'} successfully`); this.loadFeeCommissions(); diff --git a/src/app/service-provider/carnet-sequence/carnet-sequence.component.html b/src/app/service-provider/carnet-sequence/carnet-sequence.component.html index a102d7d..bde676e 100644 --- a/src/app/service-provider/carnet-sequence/carnet-sequence.component.html +++ b/src/app/service-provider/carnet-sequence/carnet-sequence.component.html @@ -138,7 +138,8 @@
- diff --git a/src/app/service-provider/carnet-sequence/carnet-sequence.component.ts b/src/app/service-provider/carnet-sequence/carnet-sequence.component.ts index 3317afc..67372a1 100644 --- a/src/app/service-provider/carnet-sequence/carnet-sequence.component.ts +++ b/src/app/service-provider/carnet-sequence/carnet-sequence.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, inject, Input, OnInit, Output, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; import { CarnetSequence } from '../../core/models/service-provider/carnet-sequence'; -import { Subject, takeUntil } from 'rxjs'; +import { finalize, Subject, takeUntil } from 'rxjs'; import { Region } from '../../core/models/region'; import { MatPaginator, MatPaginatorIntl } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; @@ -32,6 +32,7 @@ export class CarnetSequenceComponent implements OnInit { isEditing = false; currentSequenceId: string | null = null; isLoading = false; + changeInProgress = false; showForm = false; carnetTypes = [ @@ -98,11 +99,9 @@ export class CarnetSequenceComponent implements OnInit { .subscribe({ next: (regions) => { this.regions = regions; - this.isLoading = false; }, error: (error) => { console.error('Failed to load regions', error); - this.isLoading = false; } }); } @@ -113,17 +112,15 @@ export class CarnetSequenceComponent implements OnInit { this.isLoading = true; - this.carnetSequenceService.getCarnetSequenceById(this.spid).subscribe({ + this.carnetSequenceService.getCarnetSequenceById(this.spid).pipe(finalize(() => { + this.isLoading = false; + })).subscribe({ next: (carnetSequences: CarnetSequence[]) => { - // this.sequences = carnetSequences; - this.isLoading = false; this.dataSource.data = carnetSequences; - this.isLoading = false; }, error: (error: any) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load sequences'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading sequences:', error); } }); @@ -141,7 +138,10 @@ export class CarnetSequenceComponent implements OnInit { lastNumber: this.sequenceForm.value.startNumber }; - this.carnetSequenceService.createCarnetSequence(sequenceData).subscribe({ + this.changeInProgress = true; + this.carnetSequenceService.createCarnetSequence(sequenceData).pipe(finalize(() => { + this.changeInProgress = false; + })).subscribe({ next: () => { this.notificationService.showSuccess('Sequence added successfully'); this.loadSequences(); @@ -182,7 +182,10 @@ export class CarnetSequenceComponent implements OnInit { spid: this.spid }; - this.carnetSequenceService.createCarnetSequence(sequenceData) + this.changeInProgress = true; + this.carnetSequenceService.createCarnetSequence(sequenceData).pipe(finalize(() => { + this.changeInProgress = false; + })) .subscribe({ next: () => { this.notificationService.showSuccess('Sequence added successfully'); diff --git a/src/app/service-provider/contacts/contacts.component.html b/src/app/service-provider/contacts/contacts.component.html index 453b98a..1efc24d 100644 --- a/src/app/service-provider/contacts/contacts.component.html +++ b/src/app/service-provider/contacts/contacts.component.html @@ -4,6 +4,10 @@ search --> + + Show Inactive Contacts + + @@ -243,7 +247,8 @@
- diff --git a/src/app/service-provider/contacts/contacts.component.scss b/src/app/service-provider/contacts/contacts.component.scss index 7a17274..27e5b8a 100644 --- a/src/app/service-provider/contacts/contacts.component.scss +++ b/src/app/service-provider/contacts/contacts.component.scss @@ -8,6 +8,11 @@ clear: both; margin-bottom: -16px; + mat-slide-toggle { + transform: scale(0.8); + margin-left: -0.5rem; + } + button { float: right; } diff --git a/src/app/service-provider/contacts/contacts.component.ts b/src/app/service-provider/contacts/contacts.component.ts index 4e38ebe..4442179 100644 --- a/src/app/service-provider/contacts/contacts.component.ts +++ b/src/app/service-provider/contacts/contacts.component.ts @@ -14,6 +14,7 @@ import { UserPreferences } from '../../core/models/user-preference'; import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service'; import { NotificationService } from '../../core/services/common/notification.service'; import { ContactService } from '../../core/services/service-provider/contact.service'; +import { finalize } from 'rxjs'; @Component({ selector: 'app-contacts', @@ -32,7 +33,10 @@ export class ContactsComponent implements OnInit { isEditing = false; currentContactId: number | null = null; isLoading = false; + changeInProgress = false; showForm = false; + showInactiveContacts = false; + contacts: Contact[] = []; contactReadOnlyFields: any = { lastChangedDate: null, @@ -57,9 +61,9 @@ export class ContactsComponent implements OnInit { 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.required, Validators.pattern(/^[0-9]{10,15}$/)]], + phone: ['', [Validators.required, Validators.pattern(/^[0-9\-\(\)]{10,15}$/)]], + mobile: ['', [Validators.required, Validators.pattern(/^[0-9\-\(\)]{10,15}$/)]], + fax: ['', [Validators.required, Validators.pattern(/^[0-9\-\(\)]{10,15}$/)]], email: ['', [Validators.required, Validators.email, Validators.maxLength(100)]], defaultContact: [false] }); @@ -77,20 +81,34 @@ export class ContactsComponent implements OnInit { loadContacts(): void { this.isLoading = true; - this.contactService.getContactsById(this.spid).subscribe({ + this.contactService.getContactsById(this.spid).pipe(finalize(() => { + this.isLoading = false; + })).subscribe({ next: (contacts: Contact[]) => { - this.dataSource.data = contacts; - this.isLoading = false; + this.contacts = contacts; + this.renderContacts(); }, error: (error: any) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load contacts'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading contacts:', error); } }); } + toggleShowInactiveContacts(): void { + this.showInactiveContacts = !this.showInactiveContacts; + this.renderContacts(); + } + + renderContacts(): void { + if (this.showInactiveContacts) { + this.dataSource.data = this.contacts; + } else { + this.dataSource.data = this.contacts.filter(contact => !contact.isInactive); + } + } + // applyFilter(event: Event): void { // const filterValue = (event.target as HTMLInputElement).value; // this.dataSource.filter = filterValue.trim().toLowerCase(); @@ -144,7 +162,10 @@ export class ContactsComponent implements OnInit { ? this.contactService.updateContact(this.currentContactId!, contactData) : this.contactService.createContact(this.spid, contactData); - saveObservable.subscribe({ + this.changeInProgress = true; + saveObservable.pipe(finalize(() => { + this.changeInProgress = false; + })).subscribe({ next: () => { this.notificationService.showSuccess(`Contact ${this.isEditing ? 'updated' : 'added'} successfully`); this.loadContacts(); diff --git a/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.html b/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.html index ad10873..70870fe 100644 --- a/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.html +++ b/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.html @@ -1,5 +1,8 @@
+ + Show Expired Records + @@ -151,7 +154,8 @@
- diff --git a/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.scss b/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.scss index 1a79907..008a48b 100644 --- a/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.scss +++ b/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.scss @@ -8,6 +8,11 @@ clear: both; margin-bottom: -16px; + mat-slide-toggle { + transform: scale(0.8); + margin-left: -0.5rem; + } + button { float: right; } diff --git a/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.ts b/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.ts index bbd62a5..9a9db93 100644 --- a/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.ts +++ b/src/app/service-provider/continuation-sheet-fee/continuation-sheet-fee.component.ts @@ -5,7 +5,7 @@ import { MatSort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; import { AngularMaterialModule } from '../../shared/module/angular-material.module'; import { CommonModule } from '@angular/common'; -import { of } from 'rxjs'; +import { finalize, of } from 'rxjs'; import { CustomPaginator } from '../../shared/custom-paginator'; import { UserPreferences } from '../../core/models/user-preference'; import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service'; @@ -29,7 +29,10 @@ export class ContinuationSheetFeeComponent implements OnInit { isEditing = false; currentContinuationSheetId: number | null = null; isLoading = false; + changeInProgress = false; showForm = false; + showExpiredRecords = false; + continuationSheets: any[] = []; readOnlyFields: any = { lastChangedDate: null, @@ -84,20 +87,35 @@ export class ContinuationSheetFeeComponent implements OnInit { if (!this.spid) return; this.isLoading = true; - this.continuationSheetFeeService.getContinuationSheets(this.spid).subscribe({ + this.continuationSheetFeeService.getContinuationSheets(this.spid).pipe(finalize(() => { + this.isLoading = false; + })).subscribe({ next: (continuationSheets) => { - this.dataSource.data = continuationSheets; - this.isLoading = false; + this.continuationSheets = continuationSheets; + this.dataSource.data = this.continuationSheets; + this.renderRecods(); }, error: (error) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load continuation sheets'); this.notificationService.showError(errorMessage); - this.isLoading = false; return of([]); } }); } + toggleShowExpiredRecords(): void { + this.showExpiredRecords = !this.showExpiredRecords; + this.renderRecods(); + } + + renderRecods(): void { + if (this.showExpiredRecords) { + this.dataSource.data = this.continuationSheets; + } else { + this.dataSource.data = this.continuationSheets.filter(record => !record.expired); + } + } + // applyFilter(event: Event): void { // const filterValue = (event.target as HTMLInputElement).value; // this.dataSource.filter = filterValue.trim().toLowerCase(); @@ -153,7 +171,10 @@ export class ContinuationSheetFeeComponent implements OnInit { ? this.continuationSheetFeeService.updateContinuationSheet(this.currentContinuationSheetId, continuationSheetData) : this.continuationSheetFeeService.addContinuationSheet(this.spid, continuationSheetData); - saveObservable.subscribe({ + this.changeInProgress = true; + saveObservable.pipe(finalize(() => { + this.changeInProgress = false; + })).subscribe({ next: () => { this.notificationService.showSuccess(`Continuation Sheet ${this.isEditing ? 'updated' : 'added'} successfully`); this.loadContinuationSheets(); diff --git a/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.html b/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.html index db8f2f5..a54abd6 100644 --- a/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.html +++ b/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.html @@ -1,5 +1,8 @@
+ + Show Expired Records + @@ -197,7 +200,8 @@
- diff --git a/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.scss b/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.scss index 9ce03be..31e7744 100644 --- a/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.scss +++ b/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.scss @@ -8,6 +8,11 @@ clear: both; margin-bottom: -16px; + mat-slide-toggle { + transform: scale(0.8); + margin-left: -0.5rem; + } + button { float: right; } diff --git a/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.ts b/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.ts index 3d7a867..2a50178 100644 --- a/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.ts +++ b/src/app/service-provider/counterfoil-fee/counterfoil-fee.component.ts @@ -11,6 +11,7 @@ import { UserPreferences } from '../../core/models/user-preference'; import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service'; import { NotificationService } from '../../core/services/common/notification.service'; import { CounterfoilFeeService } from '../../core/services/service-provider/counterfoil-fee.service'; +import { finalize } from 'rxjs'; @Component({ selector: 'app-counterfoil-fee', @@ -29,7 +30,10 @@ export class CounterfoilFeeComponent implements OnInit { isEditing = false; currentCounterfoilId: number | null = null; isLoading = false; + changeInProgress = false; showForm = false; + showExpiredRecords = false; + counterfoilFees: CounterfoilFee[] = []; readOnlyFields: any = { lastChangedDate: null, @@ -100,22 +104,37 @@ export class CounterfoilFeeComponent implements OnInit { if (!this.spid) return; this.isLoading = true; - this.counterfoilFeeService.getCounterfoils(this.spid) + this.counterfoilFeeService.getCounterfoils(this.spid).pipe(finalize(() => { + this.isLoading = false; + })) .subscribe({ next: ( counterfoils: CounterfoilFee[]) => { - this.dataSource.data = counterfoils; - this.isLoading = false; + this.counterfoilFees = counterfoils; + this.dataSource.data = this.counterfoilFees; + this.renderRecods(); }, error: (error: any) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load counterfoils'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading counterfoils:', error); } }); } + toggleShowExpiredRecords(): void { + this.showExpiredRecords = !this.showExpiredRecords; + this.renderRecods(); + } + + renderRecods(): void { + if (this.showExpiredRecords) { + this.dataSource.data = this.counterfoilFees; + } else { + this.dataSource.data = this.counterfoilFees.filter(record => !record.expired); + } + } + // applyFilter(event: Event): void { // const filterValue = (event.target as HTMLInputElement).value; // this.dataSource.filter = filterValue.trim().toLowerCase(); @@ -177,7 +196,10 @@ export class CounterfoilFeeComponent implements OnInit { ? this.counterfoilFeeService.updateCounterfoil(this.currentCounterfoilId, counterfoilData) : this.counterfoilFeeService.addCounterfoil(this.spid, counterfoilData); - saveObservable.subscribe({ + this.changeInProgress = true; + saveObservable.pipe(finalize(() => { + this.changeInProgress = false; + })).subscribe({ next: () => { this.notificationService.showSuccess(`Counterfoil ${this.isEditing ? 'updated' : 'added'} successfully`); this.loadCounterfoils(); diff --git a/src/app/service-provider/expedited-fee/expedited-fee.component.html b/src/app/service-provider/expedited-fee/expedited-fee.component.html index 8764777..6bf2b38 100644 --- a/src/app/service-provider/expedited-fee/expedited-fee.component.html +++ b/src/app/service-provider/expedited-fee/expedited-fee.component.html @@ -1,5 +1,8 @@
+ + Show Expired Records + @@ -195,7 +198,8 @@
- diff --git a/src/app/service-provider/expedited-fee/expedited-fee.component.scss b/src/app/service-provider/expedited-fee/expedited-fee.component.scss index 5107430..6aa0c20 100644 --- a/src/app/service-provider/expedited-fee/expedited-fee.component.scss +++ b/src/app/service-provider/expedited-fee/expedited-fee.component.scss @@ -8,6 +8,11 @@ clear: both; margin-bottom: -16px; + mat-slide-toggle { + transform: scale(0.8); + margin-left: -0.5rem; + } + button { float: right; } diff --git a/src/app/service-provider/expedited-fee/expedited-fee.component.ts b/src/app/service-provider/expedited-fee/expedited-fee.component.ts index b7b1afc..1800baf 100644 --- a/src/app/service-provider/expedited-fee/expedited-fee.component.ts +++ b/src/app/service-provider/expedited-fee/expedited-fee.component.ts @@ -9,7 +9,7 @@ import { CustomPaginator } from '../../shared/custom-paginator'; import { ExpeditedFee } from '../../core/models/service-provider/expedited-fee'; import { DeliveryType } from '../../core/models/delivery-type'; import { TimeZone } from '../../core/models/timezone'; -import { Subject, takeUntil } from 'rxjs'; +import { finalize, Subject, takeUntil } from 'rxjs'; import { UserPreferences } from '../../core/models/user-preference'; import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service'; import { CommonService } from '../../core/services/common/common.service'; @@ -34,7 +34,10 @@ export class ExpeditedFeeComponent implements OnInit, OnDestroy { isEditing = false; currentFeeId: number | null = null; isLoading = false; + changeInProgress = false; showForm = false; + showExpiredRecords = false; + expeditedFees: ExpeditedFee[] = []; readOnlyFields: any = { lastChangedDate: null, @@ -99,20 +102,35 @@ export class ExpeditedFeeComponent implements OnInit, OnDestroy { loadExpeditedFees(): void { this.isLoading = true; - this.expeditedFeeService.getExpeditedFees(this.spid).subscribe({ + this.expeditedFeeService.getExpeditedFees(this.spid).pipe(finalize(() => { + this.isLoading = false; + })).subscribe({ next: (fees: ExpeditedFee[]) => { - this.dataSource.data = fees; - this.isLoading = false; + this.expeditedFees = fees; + this.dataSource.data = this.expeditedFees; + this.renderRecods(); }, error: (error: any) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load expedited fees'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading expedited fees:', error); } }); } + toggleShowExpiredRecords(): void { + this.showExpiredRecords = !this.showExpiredRecords; + this.renderRecods(); + } + + renderRecods(): void { + if (this.showExpiredRecords) { + this.dataSource.data = this.expeditedFees; + } else { + this.dataSource.data = this.expeditedFees.filter(record => !record.expired); + } + } + loadLookupData(): void { this.loadDeliveryTypes(); this.loadTimeZones(); @@ -124,17 +142,15 @@ export class ExpeditedFeeComponent implements OnInit, OnDestroy { .subscribe({ next: (timeZones) => { this.timeZones = timeZones; - this.isLoading = false; }, error: (error) => { console.error('Failed to load time zones', error); - this.isLoading = false; } }); } loadDeliveryTypes(): void { - this.commonService.getDeliveryTypes(this.spid) + this.commonService.getDeliveryTypes() .pipe(takeUntil(this.destroy$)) .subscribe({ next: (deliveryTypes) => { @@ -142,7 +158,6 @@ export class ExpeditedFeeComponent implements OnInit, OnDestroy { }, error: (error) => { console.error('Failed to load delivery types', error); - this.isLoading = false; } }); } @@ -207,7 +222,10 @@ export class ExpeditedFeeComponent implements OnInit, OnDestroy { ? this.expeditedFeeService.updateExpeditedFee(this.currentFeeId, feeData) : this.expeditedFeeService.createExpeditedFee(this.spid, feeData); - saveObservable.subscribe({ + this.changeInProgress = true; + saveObservable.pipe(finalize(() => { + this.changeInProgress = false; + })).subscribe({ next: () => { this.notificationService.showSuccess(`Expedited fee ${this.isEditing ? 'updated' : 'added'} successfully`); this.loadExpeditedFees(); diff --git a/src/app/service-provider/security-deposit/security-deposit.component.html b/src/app/service-provider/security-deposit/security-deposit.component.html index 29a19ca..f086d3a 100644 --- a/src/app/service-provider/security-deposit/security-deposit.component.html +++ b/src/app/service-provider/security-deposit/security-deposit.component.html @@ -1,5 +1,8 @@
+ + Show Expired Records + @@ -179,7 +182,8 @@
- diff --git a/src/app/service-provider/security-deposit/security-deposit.component.scss b/src/app/service-provider/security-deposit/security-deposit.component.scss index c2bc1cd..b9fa0d1 100644 --- a/src/app/service-provider/security-deposit/security-deposit.component.scss +++ b/src/app/service-provider/security-deposit/security-deposit.component.scss @@ -8,6 +8,11 @@ clear: both; margin-bottom: -16px; + mat-slide-toggle { + transform: scale(0.8); + margin-left: -0.5rem; + } + button { float: right; } diff --git a/src/app/service-provider/security-deposit/security-deposit.component.ts b/src/app/service-provider/security-deposit/security-deposit.component.ts index f71978e..49a0409 100644 --- a/src/app/service-provider/security-deposit/security-deposit.component.ts +++ b/src/app/service-provider/security-deposit/security-deposit.component.ts @@ -13,6 +13,7 @@ import { ApiErrorHandlerService } from '../../core/services/common/api-error-han import { CommonService } from '../../core/services/common/common.service'; import { NotificationService } from '../../core/services/common/notification.service'; import { SecurityDepositService } from '../../core/services/service-provider/security-deposit.service'; +import { finalize } from 'rxjs'; @Component({ selector: 'app-security-deposit', @@ -31,7 +32,10 @@ export class SecurityDepositComponent implements OnInit { isEditing = false; currentDepositId: number | null = null; isLoading = false; + changeInProgress = false; showForm = false; + showExpiredRecords = false; + securityDeposits: SecurityDeposit[] = []; readOnlyFields: any = { lastChangedDate: null, @@ -67,7 +71,7 @@ export class SecurityDepositComponent implements OnInit { holderType: ['CORP', Validators.required], uscibMember: ['Y', Validators.required], specialCommodity: [''], - specialCountry: [''], + specialCountry: ['US'], rate: [0, [Validators.required, Validators.min(0)]], effectiveDate: ['', Validators.required] }); @@ -85,20 +89,35 @@ export class SecurityDepositComponent implements OnInit { loadSecurityDeposits(): void { this.isLoading = true; - this.securityDepositService.getSecurityDeposits(this.spid).subscribe({ + this.securityDepositService.getSecurityDeposits(this.spid).pipe(finalize(() => { + this.changeInProgress = false; + })).subscribe({ next: (deposits) => { - this.dataSource.data = deposits; - this.isLoading = false; + this.securityDeposits = deposits; + this.dataSource.data = this.securityDeposits; + this.renderRecods(); }, error: (error) => { let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load security deposits'); this.notificationService.showError(errorMessage); - this.isLoading = false; console.error('Error loading security deposits:', error); } }); } + toggleShowExpiredRecords(): void { + this.showExpiredRecords = !this.showExpiredRecords; + this.renderRecods(); + } + + renderRecods(): void { + if (this.showExpiredRecords) { + this.dataSource.data = this.securityDeposits; + } else { + this.dataSource.data = this.securityDeposits.filter(record => !record.expired); + } + } + loadCountries(): void { this.commonService.getCountries().subscribe({ next: (countries) => { @@ -126,6 +145,7 @@ export class SecurityDepositComponent implements OnInit { this.depositForm.reset({ holderType: 'CORP', uscibMember: 'N', + specialCountry: 'US', }); this.depositForm.patchValue({ rate: 0 }); @@ -174,7 +194,10 @@ export class SecurityDepositComponent implements OnInit { ? this.securityDepositService.updateSecurityDeposit(this.currentDepositId, depositData) : this.securityDepositService.createSecurityDeposit(this.spid, depositData); - saveObservable.subscribe({ + this.changeInProgress = true; + saveObservable.pipe(finalize(() => { + this.changeInProgress = false; + })).subscribe({ next: () => { this.notificationService.showSuccess(`Security deposit ${this.isEditing ? 'updated' : 'added'} successfully`); this.loadSecurityDeposits(); @@ -222,6 +245,7 @@ export class SecurityDepositComponent implements OnInit { this.depositForm.reset({ holderType: 'CORP', uscibMember: 'N', + specialCountry: 'US', }); } diff --git a/src/app/shared/pipes/proper-case.pipe.ts b/src/app/shared/pipes/proper-case.pipe.ts new file mode 100644 index 0000000..49cc838 --- /dev/null +++ b/src/app/shared/pipes/proper-case.pipe.ts @@ -0,0 +1,15 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'properCase' +}) +export class ProperCasePipe implements PipeTransform { + + transform(value: string): string { + if (!value) return ''; + + return value + .toLowerCase() + .replace(/\b\w/g, char => char.toUpperCase()); + } +}