holder selection flow
This commit is contained in:
parent
d1bc0eb45a
commit
ad32f5c1ff
@ -15,6 +15,8 @@ export const routes: Routes = [
|
|||||||
{ path: 'usersettings', loadComponent: () => import('./user-settings/user-settings.component').then(m => m.UserSettingsComponent) },
|
{ path: 'usersettings', loadComponent: () => import('./user-settings/user-settings.component').then(m => m.UserSettingsComponent) },
|
||||||
{ path: 'add-carnet', loadComponent: () => import('./carnet/add/add-carnet.component').then(m => m.AddCarnetComponent) },
|
{ path: 'add-carnet', loadComponent: () => import('./carnet/add/add-carnet.component').then(m => m.AddCarnetComponent) },
|
||||||
{ path: 'edit-carnet/:headerid', loadComponent: () => import('./carnet/edit/edit-carnet.component').then(m => m.EditCarnetComponent) },
|
{ path: 'edit-carnet/:headerid', loadComponent: () => import('./carnet/edit/edit-carnet.component').then(m => m.EditCarnetComponent) },
|
||||||
|
{ path: 'add-holder', loadComponent: () => import('./holder/add/add.component').then(m => m.AddComponent) },
|
||||||
|
{ path: 'edit-holder/:holderid', loadComponent: () => import('./holder/edit/edit.component').then(m => m.EditComponent) },
|
||||||
{ path: '', redirectTo: 'home', pathMatch: 'full' }
|
{ path: '', redirectTo: 'home', pathMatch: 'full' }
|
||||||
],
|
],
|
||||||
canActivate: [AuthGuard, AppIdGuard]
|
canActivate: [AuthGuard, AppIdGuard]
|
||||||
|
|||||||
@ -15,8 +15,17 @@
|
|||||||
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.holderSelection"
|
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.holderSelection"
|
||||||
[editable]="stepsCompleted.applicationDetail">
|
[editable]="stepsCompleted.applicationDetail">
|
||||||
<ng-template matStepLabel>Holder Selection</ng-template>
|
<ng-template matStepLabel>Holder Selection</ng-template>
|
||||||
<app-holder (completed)="onHolderSelectionSaved($event)" [headerid]="headerid">
|
|
||||||
</app-holder>
|
<!-- <app-holder (completed)="onHolderSelectionSaved($event)" [headerid]="headerid">
|
||||||
|
</app-holder> -->
|
||||||
|
|
||||||
|
<!-- <app-search [searchedHolder]="searchedHolder" (searchedHolderEmit)="onSearchedHolder($event)"
|
||||||
|
(selectHolderCompleted)="onHolderSelectionSaved($event)" [HOLDERID]="holderid"
|
||||||
|
[headerid]="headerid"></app-search> -->
|
||||||
|
|
||||||
|
<app-search
|
||||||
|
(selectHolderCompleted)="onHolderSelectionSaved($event)"
|
||||||
|
[headerid]="headerid"></app-search>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<!-- Goods Section Step -->
|
<!-- Goods Section Step -->
|
||||||
|
|||||||
@ -10,16 +10,19 @@ import { TravelPlanComponent } from '../travel-plan/travel-plan.component';
|
|||||||
import { ShippingComponent } from '../shipping/shipping.component';
|
import { ShippingComponent } from '../shipping/shipping.component';
|
||||||
import { UserPreferencesService } from '../../core/services/user-preference.service';
|
import { UserPreferencesService } from '../../core/services/user-preference.service';
|
||||||
import { UserPreferences } from '../../core/models/user-preference';
|
import { UserPreferences } from '../../core/models/user-preference';
|
||||||
|
import { SearchComponent } from '../../holder/search/search.component';
|
||||||
|
import { CarnetStateStore } from '../../core/services/carnet/carnet-application.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-add-carnet',
|
selector: 'app-add-carnet',
|
||||||
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule,
|
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule,
|
||||||
ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent,
|
ApplicationComponent, SearchComponent, GoodsComponent, TravelPlanComponent,
|
||||||
ShippingComponent],
|
ShippingComponent],
|
||||||
templateUrl: './add-carnet.component.html',
|
templateUrl: './add-carnet.component.html',
|
||||||
styleUrl: './add-carnet.component.scss'
|
styleUrl: './add-carnet.component.scss'
|
||||||
})
|
})
|
||||||
export class AddCarnetComponent {
|
export class AddCarnetComponent {
|
||||||
|
store = inject(CarnetStateStore);
|
||||||
currentStep = 0;
|
currentStep = 0;
|
||||||
isLinear = true;
|
isLinear = true;
|
||||||
applicationType: 'new' | 'additional' | 'duplicate' | 'extend' | null = 'new';
|
applicationType: 'new' | 'additional' | 'duplicate' | 'extend' | null = 'new';
|
||||||
@ -44,8 +47,10 @@ export class AddCarnetComponent {
|
|||||||
this.currentStep = event.selectedIndex;
|
this.currentStep = event.selectedIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
onApplicationDetailCreated(headerid: number): void {
|
onApplicationDetailCreated(data: { HEADERID: number, APPLICATION_NAME: string }): void {
|
||||||
this.headerid = headerid;
|
this.store.headerid.set(data.HEADERID);
|
||||||
|
this.store.applicationName.set(data.APPLICATION_NAME);
|
||||||
|
this.headerid = data.HEADERID;
|
||||||
this.stepsCompleted.applicationDetail = true;
|
this.stepsCompleted.applicationDetail = true;
|
||||||
this.isLinear = false; // Disable linear mode after application detail is created
|
this.isLinear = false; // Disable linear mode after application detail is created
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,8 @@ export class ApplicationComponent {
|
|||||||
@Input() headerid: number = 0;
|
@Input() headerid: number = 0;
|
||||||
@Input() applicationName: string = '';
|
@Input() applicationName: string = '';
|
||||||
|
|
||||||
@Output() headerIdCreated = new EventEmitter<number>();
|
// @Output() headerIdCreated = new EventEmitter<number>();
|
||||||
|
@Output() headerIdCreated = new EventEmitter<{ HEADERID: number, APPLICATION_NAME: string }>();
|
||||||
|
|
||||||
applicationDetailsForm: FormGroup;
|
applicationDetailsForm: FormGroup;
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
@ -102,7 +103,7 @@ export class ApplicationComponent {
|
|||||||
this.applicationDetailService.createApplicationDetails(applicationDetailData).subscribe({
|
this.applicationDetailService.createApplicationDetails(applicationDetailData).subscribe({
|
||||||
next: (applicationData: any) => {
|
next: (applicationData: any) => {
|
||||||
this.notificationService.showSuccess(`Application details added successfully`);
|
this.notificationService.showSuccess(`Application details added successfully`);
|
||||||
this.headerIdCreated.emit(+applicationData.HEADERID);
|
this.headerIdCreated.emit({ HEADERID: +applicationData.HEADERID, APPLICATION_NAME: applicationDetailData.name });
|
||||||
this.applicationDetailsForm.get('name')?.disable();
|
this.applicationDetailsForm.get('name')?.disable();
|
||||||
this.disableSaveButton = true;
|
this.disableSaveButton = true;
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
|
|||||||
@ -15,8 +15,9 @@
|
|||||||
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.holderSelection"
|
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.holderSelection"
|
||||||
[editable]="stepsCompleted.applicationDetail">
|
[editable]="stepsCompleted.applicationDetail">
|
||||||
<ng-template matStepLabel>Holder Selection</ng-template>
|
<ng-template matStepLabel>Holder Selection</ng-template>
|
||||||
<app-holder (completed)="onHolderSelectionSaved($event)" [headerid]="headerid">
|
<!-- <app-holder (completed)="onHolderSelectionSaved($event)" [headerid]="headerid">
|
||||||
</app-holder>
|
</app-holder> -->
|
||||||
|
<app-search (selectHolderCompleted)="onHolderSelectionSaved($event)" [headerid]="headerid"></app-search>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<!-- Goods Section Step -->
|
<!-- Goods Section Step -->
|
||||||
|
|||||||
@ -11,11 +11,12 @@ import { ShippingComponent } from '../shipping/shipping.component';
|
|||||||
import { TravelPlanComponent } from '../travel-plan/travel-plan.component';
|
import { TravelPlanComponent } from '../travel-plan/travel-plan.component';
|
||||||
import { UserPreferences } from '../../core/models/user-preference';
|
import { UserPreferences } from '../../core/models/user-preference';
|
||||||
import { UserPreferencesService } from '../../core/services/user-preference.service';
|
import { UserPreferencesService } from '../../core/services/user-preference.service';
|
||||||
|
import { SearchComponent } from '../../holder/search/search.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-edit-carnet',
|
selector: 'app-edit-carnet',
|
||||||
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule,
|
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule,
|
||||||
ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent, ShippingComponent],
|
ApplicationComponent, SearchComponent, GoodsComponent, TravelPlanComponent, ShippingComponent],
|
||||||
templateUrl: './edit-carnet.component.html',
|
templateUrl: './edit-carnet.component.html',
|
||||||
styleUrl: './edit-carnet.component.scss'
|
styleUrl: './edit-carnet.component.scss'
|
||||||
})
|
})
|
||||||
|
|||||||
30
src/app/core/models/holder/contact.ts
Normal file
30
src/app/core/models/holder/contact.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
export interface HolderContact {
|
||||||
|
HOLDERCONTACTID: number;
|
||||||
|
HOLDERID: number;
|
||||||
|
SPID: number;
|
||||||
|
FIRSTNAME: string;
|
||||||
|
LASTNAME: string;
|
||||||
|
MIDDLEINITIAL: string | null;
|
||||||
|
TITLE: string;
|
||||||
|
PHONE: string;
|
||||||
|
MOBILE: string;
|
||||||
|
FAX: string | null;
|
||||||
|
EMAILADDRESS: string;
|
||||||
|
DATECREATED: string;
|
||||||
|
CREATEDBY: string;
|
||||||
|
INACTIVEFLAG: string;
|
||||||
|
INACTIVEDATE: string | null;
|
||||||
|
LASTUPDATEDBY: string | null;
|
||||||
|
LASTUPDATEDDATE: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ContactFormModel {
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
middleInitial: string;
|
||||||
|
title: string;
|
||||||
|
phone: string;
|
||||||
|
mobile: string;
|
||||||
|
fax: string;
|
||||||
|
email: string;
|
||||||
|
};
|
||||||
40
src/app/core/models/holder/holder-details.ts
Normal file
40
src/app/core/models/holder/holder-details.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
export interface HolderDetail {
|
||||||
|
HOLDERID?: number;
|
||||||
|
SPID: number;
|
||||||
|
LOCATIONID: number;
|
||||||
|
HOLDERNO: string;
|
||||||
|
HOLDERTYPE: string;
|
||||||
|
USCIBMEMBERFLAG: string;
|
||||||
|
GOVAGENCYFLAG: string;
|
||||||
|
HOLDERNAME: string;
|
||||||
|
NAMEQUALIFIER: string | null;
|
||||||
|
ADDLNAME: string | null;
|
||||||
|
ADDRESS1: string;
|
||||||
|
ADDRESS2: string | null;
|
||||||
|
CITY: string;
|
||||||
|
STATE: string;
|
||||||
|
ZIP: string;
|
||||||
|
COUNTRY: string;
|
||||||
|
DATECREATED: string;
|
||||||
|
CREATEDBY: string;
|
||||||
|
INACTIVEFLAG: string;
|
||||||
|
INACTIVEDATE: string | null;
|
||||||
|
LASTUPDATEDBY: string | null;
|
||||||
|
LASTUPDATEDDATE: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface HolderDetailFormType {
|
||||||
|
holderName: string;
|
||||||
|
DBAName: string;
|
||||||
|
HolderNumber: string;
|
||||||
|
holderType: string;
|
||||||
|
USCIBMember: string;
|
||||||
|
govAgency: string;
|
||||||
|
address1: string;
|
||||||
|
address2: string;
|
||||||
|
city: string;
|
||||||
|
state: string;
|
||||||
|
country: string;
|
||||||
|
zip: string;
|
||||||
|
}
|
||||||
16
src/app/core/services/carnet/carnet-application.service.ts
Normal file
16
src/app/core/services/carnet/carnet-application.service.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// appli.service.ts
|
||||||
|
import { Injectable, signal } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class CarnetStateStore {
|
||||||
|
headerid = signal<number>(0);
|
||||||
|
applicationName = signal<string>('');
|
||||||
|
|
||||||
|
resetState() {
|
||||||
|
this.headerid.set(0);
|
||||||
|
this.applicationName.set('');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
92
src/app/core/services/holder/contact.service.ts
Normal file
92
src/app/core/services/holder/contact.service.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { UserService } from '../common/user.service';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { environment } from '../../../../environments/environment';
|
||||||
|
import { map, Observable, of } from 'rxjs';
|
||||||
|
import { ContactFormModel, HolderContact } from '../../models/holder/contact';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ContactService {
|
||||||
|
private apiUrl = environment.apiUrl;
|
||||||
|
private apiDb = environment.apiDb;
|
||||||
|
|
||||||
|
constructor(private http: HttpClient, private userService: UserService) { }
|
||||||
|
|
||||||
|
getHolderContactsByHolderId(id: number): Observable<HolderContact[]> {
|
||||||
|
return this.http.get<any[]>(`${this.apiUrl}/${this.apiDb}/GetHolderContacts/${this.userService.getUserSpid()}/${id}`).pipe(
|
||||||
|
map(response => this.mapToContacts(response)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapToContacts(data: any[]): HolderContact[] {
|
||||||
|
return data.map(contact => ({
|
||||||
|
HOLDERCONTACTID: contact.HOLDERCONTACTID,
|
||||||
|
HOLDERID: contact.HOLDERID,
|
||||||
|
SPID: contact.SPID,
|
||||||
|
FIRSTNAME: contact.FIRSTNAME,
|
||||||
|
LASTNAME: contact.LASTNAME,
|
||||||
|
MIDDLEINITIAL: contact.MIDDLEINITIAL || null,
|
||||||
|
TITLE: contact.TITLE,
|
||||||
|
PHONE: contact.PHONE,
|
||||||
|
MOBILE: contact.MOBILE,
|
||||||
|
FAX: contact.FAX || null,
|
||||||
|
EMAILADDRESS: contact.EMAILADDRESS,
|
||||||
|
DATECREATED: contact.DATECREATED || null,
|
||||||
|
CREATEDBY: contact.CREATEDBY || null,
|
||||||
|
INACTIVEFLAG: contact.INACTIVEFLAG || 'N',
|
||||||
|
INACTIVEDATE: contact.INACTIVEDATE || null,
|
||||||
|
LASTUPDATEDBY: contact.LASTUPDATEDBY || null,
|
||||||
|
LASTUPDATEDDATE: contact.LASTUPDATEDDATE || null
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
createHolderContact(HOLDERID: number, data: ContactFormModel): Observable<any> {
|
||||||
|
const contact = {
|
||||||
|
P_SPID: this.userService.getUserSpid(),
|
||||||
|
P_HOLDERID: HOLDERID,
|
||||||
|
P_CONTACTSTABLE: [{
|
||||||
|
P_FIRSTNAME: data.firstName,
|
||||||
|
P_LASTNAME: data.lastName,
|
||||||
|
P_MIDDLEINITIAL: data.middleInitial,
|
||||||
|
P_TITLE: data.title,
|
||||||
|
P_EMAILADDRESS: data.email,
|
||||||
|
P_MOBILENO: data.mobile,
|
||||||
|
P_PHONENO: data.phone,
|
||||||
|
P_FAXNO: data.fax
|
||||||
|
}],
|
||||||
|
P_USERID: this.userService.getUser()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.http.post(`${this.apiUrl}/${this.apiDb}/CreateHoldercontact`, contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHolderContact(P_HOLDERCONTACTID: number, data: ContactFormModel): Observable<any> {
|
||||||
|
const contact = {
|
||||||
|
P_HOLDERCONTACTID,
|
||||||
|
P_SPID: this.userService.getUserSpid(),
|
||||||
|
P_FIRSTNAME: data.firstName,
|
||||||
|
P_LASTNAME: data.lastName,
|
||||||
|
P_MIDDLEINITIAL: data.middleInitial,
|
||||||
|
P_TITLE: data.title,
|
||||||
|
P_EMAILADDRESS: data.email,
|
||||||
|
P_MOBILENO: data.mobile,
|
||||||
|
P_PHONENO: data.phone,
|
||||||
|
P_FAXNO: data.fax,
|
||||||
|
P_USERID: this.userService.getUser()
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("update body : ", contact);
|
||||||
|
|
||||||
|
|
||||||
|
return this.http.put(`${this.apiUrl}/${this.apiDb}/UpdateHolderContact`, contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
InactivateHolderContact(HOLDERCONTACTID: number) {
|
||||||
|
return this.http.patch(`${this.apiUrl}/${this.apiDb}/InactivateHolderContact/${this.userService.getUserSpid()}/${HOLDERCONTACTID}/${this.userService.getSafeUser()}`, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactivateHolderContact(HOLDERCONTACTID: number) {
|
||||||
|
return this.http.patch(`${this.apiUrl}/${this.apiDb}/ReactivateHolderContact/${this.userService.getUserSpid()}/${HOLDERCONTACTID}/${this.userService.getSafeUser()}`, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
101
src/app/core/services/holder/holder-detail.service.ts
Normal file
101
src/app/core/services/holder/holder-detail.service.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { UserService } from '../common/user.service';
|
||||||
|
import { environment } from '../../../../environments/environment';
|
||||||
|
import { HolderDetail, HolderDetailFormType } from '../../models/holder/holder-details';
|
||||||
|
import { filter, map, Observable, of, tap } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class HolderDetailService {
|
||||||
|
private apiUrl = environment.apiUrl;
|
||||||
|
private apiDb = environment.apiDb;
|
||||||
|
|
||||||
|
constructor(private http: HttpClient, private userService: UserService) { }
|
||||||
|
|
||||||
|
getHolderDetailByHolderId(id: number): Observable<HolderDetail> {
|
||||||
|
return this.http.get<any[]>(`${this.apiUrl}/${this.apiDb}/GetHolderRecord/${this.userService.getUserSpid()}/${id}`).pipe(
|
||||||
|
tap(response => console.log('Raw response got is :', response)),
|
||||||
|
// filter(response => response.length > 0),
|
||||||
|
map(response => this.mapToBasicDetail(response)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapToBasicDetail(basicDetails: any): HolderDetail {
|
||||||
|
return {
|
||||||
|
HOLDERID: basicDetails.HOLDERID,
|
||||||
|
SPID: basicDetails.SPID,
|
||||||
|
LOCATIONID: basicDetails.LOCATIONID,
|
||||||
|
HOLDERNO: basicDetails.HOLDERNO,
|
||||||
|
HOLDERTYPE: basicDetails.HOLDERTYPE,
|
||||||
|
USCIBMEMBERFLAG: basicDetails.USCIBMEMBERFLAG,
|
||||||
|
GOVAGENCYFLAG: basicDetails.GOVAGENCYFLAG,
|
||||||
|
HOLDERNAME: basicDetails.HOLDERNAME,
|
||||||
|
NAMEQUALIFIER: basicDetails.NAMEQUALIFIER || null,
|
||||||
|
ADDLNAME: basicDetails.ADDLNAME || null,
|
||||||
|
ADDRESS1: basicDetails.ADDRESS1,
|
||||||
|
ADDRESS2: basicDetails.ADDRESS2 || null,
|
||||||
|
CITY: basicDetails.CITY,
|
||||||
|
STATE: basicDetails.STATE,
|
||||||
|
ZIP: basicDetails.ZIP,
|
||||||
|
COUNTRY: basicDetails.COUNTRY,
|
||||||
|
DATECREATED: basicDetails.DATECREATED,
|
||||||
|
CREATEDBY: basicDetails.CREATEDBY,
|
||||||
|
INACTIVEFLAG: basicDetails.INACTIVEFLAG,
|
||||||
|
INACTIVEDATE: basicDetails.INACTIVEDATE || null,
|
||||||
|
LASTUPDATEDBY: basicDetails.LASTUPDATEDBY || null,
|
||||||
|
LASTUPDATEDDATE: basicDetails.LASTUPDATEDDATE || null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
createHolderDetail(data: HolderDetailFormType): Observable<any> {
|
||||||
|
const holderDetail = {
|
||||||
|
P_SPID: this.userService.getUserSpid(),
|
||||||
|
P_CLIENTLOCATIONID: this.userService.getUserLocationid(),
|
||||||
|
P_HOLDERNO: data.HolderNumber,
|
||||||
|
P_HOLDERTYPE: data.holderType,
|
||||||
|
P_USCIBMEMBERFLAG: data.USCIBMember,
|
||||||
|
P_GOVAGENCYFLAG: data.govAgency,
|
||||||
|
P_HOLDERNAME: data.holderName,
|
||||||
|
P_NAMEQUALIFIER: null,
|
||||||
|
P_ADDLNAME: data.DBAName,
|
||||||
|
P_ADDRESS1: data.address1,
|
||||||
|
P_ADDRESS2: data.address2,
|
||||||
|
P_CITY: data.city,
|
||||||
|
P_STATE: data.state,
|
||||||
|
P_ZIP: data.zip,
|
||||||
|
P_COUNTRY: data.country,
|
||||||
|
P_USERID: this.userService.getUser()
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("body : ",holderDetail);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return this.http.post(`${this.apiUrl}/${this.apiDb}/CreateHolderData`, holderDetail);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHolderDetails(id: number, data: HolderDetailFormType): Observable<any> {
|
||||||
|
const holderDetail = {
|
||||||
|
P_HOLDERID: id,
|
||||||
|
P_SPID: this.userService.getUserSpid(),
|
||||||
|
P_LOCATIONID: this.userService.getUserLocationid(),
|
||||||
|
P_HOLDERNO: data.HolderNumber,
|
||||||
|
P_HOLDERTYPE: data.holderType,
|
||||||
|
P_USCIBMEMBERFLAG: data.USCIBMember,
|
||||||
|
P_GOVAGENCYFLAG: data.govAgency,
|
||||||
|
P_HOLDERNAME: data.holderName,
|
||||||
|
P_NAMEQUALIFIER: null,
|
||||||
|
P_ADDLNAME: data.DBAName,
|
||||||
|
P_ADDRESS1: data.address1,
|
||||||
|
P_ADDRESS2: data.address2,
|
||||||
|
P_CITY: data.city,
|
||||||
|
P_STATE: data.state,
|
||||||
|
P_ZIP: data.zip,
|
||||||
|
P_COUNTRY: data.country,
|
||||||
|
P_USERID: this.userService.getUser()
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.put(`${this.apiUrl}/${this.apiDb}/UpdateHolder`, holderDetail);
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/app/core/services/holder/holder.service.ts
Normal file
68
src/app/core/services/holder/holder.service.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { inject, Injectable } from '@angular/core';
|
||||||
|
import { environment } from '../../../../environments/environment';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { UserService } from '../common/user.service';
|
||||||
|
import { map, Observable } from 'rxjs';
|
||||||
|
import { HolderDetail } from '../../models/holder/holder-details';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class HolderService {
|
||||||
|
private apiUrl = environment.apiUrl;
|
||||||
|
private apiDb = environment.apiDb;
|
||||||
|
|
||||||
|
private http = inject(HttpClient);
|
||||||
|
private userService = inject(UserService);
|
||||||
|
|
||||||
|
searchHolders(filter: { holderName: string }): Observable<HolderDetail[]> {
|
||||||
|
return this.http.get<any[]>(`${this.apiUrl}/${this.apiDb}/SearchHolder/${this.userService.getUserSpid()}/${filter.holderName}`).pipe(
|
||||||
|
map(response => this.mapToHolders(response))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateApplicationHolder(headerId: number, holderId: number) {
|
||||||
|
const applicationDetail = {
|
||||||
|
P_HEADERID: headerId,
|
||||||
|
P_HOLDERID: holderId
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.http.patch(`${this.apiUrl}/${this.apiDb}/update-holder`, applicationDetail);
|
||||||
|
}
|
||||||
|
|
||||||
|
InactivateHolder(HOLDERID: number) {
|
||||||
|
return this.http.patch(`${this.apiUrl}/${this.apiDb}/InactivateHolder/${this.userService.getUserSpid()}/${HOLDERID}/${this.userService.getSafeUser()}`, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactivateHolder(HOLDERID: number) {
|
||||||
|
return this.http.patch(`${this.apiUrl}/${this.apiDb}/ReactivateHolder/${this.userService.getUserSpid()}/${HOLDERID}/${this.userService.getSafeUser()}`, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private mapToHolders(data: any[]): HolderDetail[] {
|
||||||
|
return data.map((holderDetail: HolderDetail) => ({
|
||||||
|
HOLDERID: holderDetail.HOLDERID,
|
||||||
|
SPID: holderDetail.SPID,
|
||||||
|
LOCATIONID: holderDetail.LOCATIONID,
|
||||||
|
HOLDERNO: holderDetail.HOLDERNO,
|
||||||
|
HOLDERTYPE: holderDetail.HOLDERTYPE,
|
||||||
|
USCIBMEMBERFLAG: holderDetail.USCIBMEMBERFLAG,
|
||||||
|
GOVAGENCYFLAG: holderDetail.GOVAGENCYFLAG,
|
||||||
|
HOLDERNAME: holderDetail.HOLDERNAME,
|
||||||
|
NAMEQUALIFIER: holderDetail.NAMEQUALIFIER,
|
||||||
|
ADDLNAME: holderDetail.ADDLNAME,
|
||||||
|
ADDRESS1: holderDetail.ADDRESS1,
|
||||||
|
ADDRESS2: holderDetail.ADDRESS2,
|
||||||
|
CITY: holderDetail.CITY,
|
||||||
|
STATE: holderDetail.STATE,
|
||||||
|
ZIP: holderDetail.ZIP,
|
||||||
|
COUNTRY: holderDetail.COUNTRY,
|
||||||
|
DATECREATED: holderDetail.DATECREATED,
|
||||||
|
CREATEDBY: holderDetail.CREATEDBY,
|
||||||
|
INACTIVEFLAG: holderDetail.INACTIVEFLAG,
|
||||||
|
INACTIVEDATE: holderDetail.INACTIVEDATE,
|
||||||
|
LASTUPDATEDBY: holderDetail.LASTUPDATEDBY,
|
||||||
|
LASTUPDATEDDATE: holderDetail.LASTUPDATEDDATE
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/app/holder/add/add.component.html
Normal file
26
src/app/holder/add/add.component.html
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<button mat-stroked-button color="accent" class="back-btn" (click)="goToEditCarnet()" [hidden]="!isEditMode">Back</button>
|
||||||
|
|
||||||
|
<div class="client-carnet-container">
|
||||||
|
<!-- Stepper Section (shown after questions are answered) -->
|
||||||
|
<mat-stepper orientation="vertical" [linear]="isLinear" (selectionChange)="onStepChange($event)"
|
||||||
|
[selectedIndex]="currentStep">
|
||||||
|
|
||||||
|
<!-- Holder Detail Step -->
|
||||||
|
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.holderDetails"
|
||||||
|
[editable]="stepsCompleted.holderDetails">
|
||||||
|
<ng-template matStepLabel>Holder Details</ng-template>
|
||||||
|
<!-- <app-application [isEditMode]="isEditMode" (headerIdCreated)="onApplicationDetailCreated($event)">
|
||||||
|
</app-application> -->
|
||||||
|
<app-holder-detail [isEditMode]="isEditMode" (holderIdCreated)="onHolderIdCreated($event)"></app-holder-detail>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<!-- Holder Contact Step -->
|
||||||
|
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.holderContacts"
|
||||||
|
[editable]="stepsCompleted.holderContacts">
|
||||||
|
<ng-template matStepLabel>Holder Contacts</ng-template>
|
||||||
|
<!-- <app-application [isEditMode]="isEditMode" (headerIdCreated)="onApplicationDetailCreated($event)">
|
||||||
|
</app-application> -->
|
||||||
|
<app-holder-contacts [holderid]="holderid" [isEditMode]="isEditMode" [userPreferences]="userPreferences"></app-holder-contacts>
|
||||||
|
</mat-step>
|
||||||
|
</mat-stepper>
|
||||||
|
</div>
|
||||||
4
src/app/holder/add/add.component.scss
Normal file
4
src/app/holder/add/add.component.scss
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.back-btn{
|
||||||
|
padding: 0 10px !important;
|
||||||
|
margin-bottom: 10px !important;
|
||||||
|
}
|
||||||
67
src/app/holder/add/add.component.ts
Normal file
67
src/app/holder/add/add.component.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { StepperSelectionEvent } from '@angular/cdk/stepper';
|
||||||
|
import { HolderDetailComponent } from '../holder-detail/holder-detail.component';
|
||||||
|
import { MatStepperModule } from '@angular/material/stepper';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { HolderContactsComponent } from '../holder-contacts/holder-contacts.component';
|
||||||
|
import { UserPreferences } from '../../core/models/user-preference';
|
||||||
|
import { UserPreferencesService } from '../../core/services/user-preference.service';
|
||||||
|
import { CarnetStateStore } from '../../core/services/carnet/carnet-application.service';
|
||||||
|
import { NavigationService } from '../../core/services/common/navigation.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-add',
|
||||||
|
imports: [
|
||||||
|
AngularMaterialModule,
|
||||||
|
CommonModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
HolderDetailComponent,
|
||||||
|
MatStepperModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
HolderContactsComponent
|
||||||
|
],
|
||||||
|
templateUrl: './add.component.html',
|
||||||
|
styleUrl: './add.component.scss'
|
||||||
|
})
|
||||||
|
export class AddComponent {
|
||||||
|
store = inject(CarnetStateStore);
|
||||||
|
currentStep = 0;
|
||||||
|
isLinear = true;
|
||||||
|
applicationType: 'new' | 'additional' | 'duplicate' | 'extend' | null = 'new';
|
||||||
|
isEditMode = false;
|
||||||
|
holderid: number = 0;
|
||||||
|
userPreferences: UserPreferences;
|
||||||
|
stepsCompleted = {
|
||||||
|
holderDetails: false,
|
||||||
|
holderContacts: false
|
||||||
|
};
|
||||||
|
constructor(
|
||||||
|
private userPrefenceService: UserPreferencesService,
|
||||||
|
private navigationService: NavigationService,
|
||||||
|
) {
|
||||||
|
this.userPreferences = this.userPrefenceService.getPreferences();
|
||||||
|
}
|
||||||
|
|
||||||
|
onStepChange(event: StepperSelectionEvent): void {
|
||||||
|
this.currentStep = event.selectedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
onHolderIdCreated(holderid: number): void {
|
||||||
|
this.holderid = holderid;
|
||||||
|
this.stepsCompleted.holderDetails = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
goToEditCarnet(): void {
|
||||||
|
this.navigationService.navigate(["edit-carnet", this.store.headerid()],
|
||||||
|
{
|
||||||
|
state: { isEditMode: true } ,
|
||||||
|
queryParams: { applicationname: this.store.applicationName() }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
24
src/app/holder/edit/edit.component.html
Normal file
24
src/app/holder/edit/edit.component.html
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<h2 *ngIf="this.holderName" class="page-header">Manage {{this.holderName}}</h2>
|
||||||
|
|
||||||
|
<div class="preparer-action-buttons">
|
||||||
|
<button mat-button (click)="accordion().openAll()">Expand All</button>
|
||||||
|
<button mat-button (click)="accordion().closeAll()">Collapse All</button>
|
||||||
|
</div>
|
||||||
|
<mat-accordion class="preparer-headers-align" multi>
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title> Basic Details </mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
|
||||||
|
<app-holder-detail [holderid]="holderid" [isEditMode]="isEditMode"
|
||||||
|
(clientName)="onClientNameUpdate($event)"></app-holder-detail>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title> holder Contacts </mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
|
||||||
|
<app-holder-contacts [userPreferences]="userPreferences" [holderid]="holderid" [isEditMode]="isEditMode" ></app-holder-contacts>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</mat-accordion>
|
||||||
18
src/app/holder/edit/edit.component.scss
Normal file
18
src/app/holder/edit/edit.component.scss
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
.page-header {
|
||||||
|
margin: 0.5rem 0px;
|
||||||
|
color: var(--mat-sys-primary);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preparer-action-buttons {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preparer-headers-align .mat-expansion-panel-header-description {
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preparer-headers-align .mat-mdc-form-field+.mat-mdc-form-field {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
39
src/app/holder/edit/edit.component.ts
Normal file
39
src/app/holder/edit/edit.component.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { afterNextRender, Component, viewChild } from '@angular/core';
|
||||||
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
||||||
|
import { MatAccordion } from '@angular/material/expansion';
|
||||||
|
import { UserPreferences } from '../../core/models/user-preference';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { UserPreferencesService } from '../../core/services/user-preference.service';
|
||||||
|
import { HolderDetailComponent } from '../holder-detail/holder-detail.component';
|
||||||
|
import { HolderContactsComponent } from '../holder-contacts/holder-contacts.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-edit',
|
||||||
|
imports: [AngularMaterialModule, CommonModule, HolderDetailComponent, HolderContactsComponent],
|
||||||
|
templateUrl: './edit.component.html',
|
||||||
|
styleUrl: './edit.component.scss'
|
||||||
|
})
|
||||||
|
export class EditComponent {
|
||||||
|
accordion = viewChild.required(MatAccordion);
|
||||||
|
isEditMode = true;
|
||||||
|
holderid = 0;
|
||||||
|
holderName: string | null = null;
|
||||||
|
userPreferences: UserPreferences;
|
||||||
|
|
||||||
|
constructor(private route: ActivatedRoute, private userPrefenceService: UserPreferencesService) {
|
||||||
|
this.userPreferences = userPrefenceService.getPreferences();
|
||||||
|
afterNextRender(() => {
|
||||||
|
this.accordion().openAll();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const idParam = this.route.snapshot.paramMap.get('holderid');
|
||||||
|
this.holderid = idParam ? parseInt(idParam, 10) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
onClientNameUpdate(event: string): void {
|
||||||
|
this.holderName = event;
|
||||||
|
}
|
||||||
|
}
|
||||||
264
src/app/holder/holder-contacts/holder-contacts.component.html
Normal file
264
src/app/holder/holder-contacts/holder-contacts.component.html
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
<div class="contacts-container">
|
||||||
|
<div class="actions-bar">
|
||||||
|
<mat-slide-toggle (change)="toggleShowInactiveContacts()">
|
||||||
|
Show Inactive Contacts
|
||||||
|
</mat-slide-toggle>
|
||||||
|
|
||||||
|
<button mat-raised-button color="primary" (click)="addNewContact()">
|
||||||
|
<mat-icon>add</mat-icon> Add New Contact
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container mat-elevation-z8">
|
||||||
|
<div class="loading-shade" *ngIf="isLoading">
|
||||||
|
<mat-spinner diameter="50"></mat-spinner>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table mat-table [dataSource]="dataSource" matSort>
|
||||||
|
<!-- First Name Column -->
|
||||||
|
<ng-container matColumnDef="firstName">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>First Name</th>
|
||||||
|
<td mat-cell *matCellDef="let contact">{{ contact.FIRSTNAME }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Last Name Column -->
|
||||||
|
<ng-container matColumnDef="lastName">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Last Name</th>
|
||||||
|
<td mat-cell *matCellDef="let contact">{{ contact.LASTNAME }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Title Column -->
|
||||||
|
<ng-container matColumnDef="title">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Title</th>
|
||||||
|
<td mat-cell *matCellDef="let contact">{{ contact.TITLE }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Phone Column -->
|
||||||
|
<ng-container matColumnDef="phone">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Phone</th>
|
||||||
|
<td mat-cell *matCellDef="let contact">{{ contact.PHONE | phone }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Mobile Column -->
|
||||||
|
<ng-container matColumnDef="mobile">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Mobile</th>
|
||||||
|
<td mat-cell *matCellDef="let contact">{{ contact.MOBILE | phone }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Email Column -->
|
||||||
|
<ng-container matColumnDef="email">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Email</th>
|
||||||
|
<td mat-cell *matCellDef="let contact">{{ contact.EMAILADDRESS }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Default Contact Column -->
|
||||||
|
<!-- <ng-container matColumnDef="defaultContact">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Default</th>
|
||||||
|
<td mat-cell *matCellDef="let contact">
|
||||||
|
<mat-icon [color]="contact.defaultContact ? 'primary' : ''">
|
||||||
|
{{ contact.defaultContact ? 'star' : 'star_border' }}
|
||||||
|
</mat-icon>
|
||||||
|
</td>
|
||||||
|
</ng-container> -->
|
||||||
|
|
||||||
|
<!-- Actions Column -->
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Actions</th>
|
||||||
|
<td mat-cell *matCellDef="let contact">
|
||||||
|
<div style="display: flex; justify-content: center; align-items: center;">
|
||||||
|
<button mat-icon-button color="primary" (click)="editContact(contact)" matTooltip="Edit">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
<!-- <button mat-icon-button color="primary" (click)="createLogin()" matTooltip="Login">
|
||||||
|
<mat-icon>person</mat-icon>
|
||||||
|
</button> -->
|
||||||
|
<button mat-icon-button color="warn" *ngIf="!contact.isInactive"
|
||||||
|
(click)="InactivateHolderContact(contact.HOLDERCONTACTID)" matTooltip="Inactivate">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button color="warn" *ngIf="contact.isInactive"
|
||||||
|
(click)="ReactivateHolderContact(contact.HOLDERCONTACTID)" matTooltip="Reactivate">
|
||||||
|
<mat-icon>delete_outline</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- <button mat-icon-button (click)="setDefaultContact(contact.contactId)"
|
||||||
|
[color]="contact.defaultContact ? 'primary' : ''" matTooltip="Set as default">
|
||||||
|
<mat-icon>star</mat-icon>
|
||||||
|
</button> -->
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
|
||||||
|
<tr matNoDataRow *matNoDataRow>
|
||||||
|
<td [colSpan]="displayedColumns.length" class="no-data-message">
|
||||||
|
<mat-icon>info</mat-icon>
|
||||||
|
<span>No records available</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator [length]="dataSource.data.length" [pageSizeOptions]="[userPreferences.pageSize || 1]"
|
||||||
|
[hidePageSize]="true" showFirstLastButtons></mat-paginator>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Contact Form -->
|
||||||
|
<div class="form-container" *ngIf="showForm">
|
||||||
|
<form [formGroup]="contactForm" (ngSubmit)="saveContact()">
|
||||||
|
<div class="form-header">
|
||||||
|
<h3>{{ isEditing ? 'Edit Contact' : 'Add New Contact' }}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>First Name</mat-label>
|
||||||
|
<input matInput formControlName="firstName" required>
|
||||||
|
<mat-icon matSuffix>person</mat-icon>
|
||||||
|
<mat-error *ngIf="contactForm.get('firstName')?.errors?.['required']">
|
||||||
|
First name is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="contactForm.get('firstName')?.errors?.['maxlength']">
|
||||||
|
Maximum 50 characters allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="small-field">
|
||||||
|
<mat-label>Middle Initial</mat-label>
|
||||||
|
<input matInput formControlName="middleInitial" maxlength="1">
|
||||||
|
<mat-error *ngIf="contactForm.get('middleInitial')?.errors?.['maxlength']">
|
||||||
|
Only 1 character allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Last Name</mat-label>
|
||||||
|
<input matInput formControlName="lastName" required>
|
||||||
|
<mat-icon matSuffix>person</mat-icon>
|
||||||
|
<mat-error *ngIf="contactForm.get('lastName')?.errors?.['required']">
|
||||||
|
Last name is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="contactForm.get('lastName')?.errors?.['maxlength']">
|
||||||
|
Maximum 50 characters allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Title</mat-label>
|
||||||
|
<input matInput formControlName="title" required>
|
||||||
|
<mat-icon matSuffix>work</mat-icon>
|
||||||
|
<mat-error *ngIf="contactForm.get('title')?.errors?.['required']">
|
||||||
|
Title is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="contactForm.get('title')?.errors?.['maxlength']">
|
||||||
|
Maximum 100 characters allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Phone</mat-label>
|
||||||
|
<input matInput formControlName="phone" required>
|
||||||
|
<mat-icon matSuffix>phone</mat-icon>
|
||||||
|
<mat-error *ngIf="contactForm.get('phone')?.errors?.['required']">
|
||||||
|
Phone is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="contactForm.get('phone')?.errors?.['pattern']">
|
||||||
|
Please enter a valid phone number (10-15 digits)
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Mobile</mat-label>
|
||||||
|
<input matInput formControlName="mobile">
|
||||||
|
<mat-icon matSuffix>smartphone</mat-icon>
|
||||||
|
<mat-error *ngIf="contactForm.get('mobile')?.errors?.['required']">
|
||||||
|
Mobile is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="contactForm.get('mobile')?.errors?.['pattern']">
|
||||||
|
Please enter a valid mobile number (10-15 digits)
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Fax</mat-label>
|
||||||
|
<input matInput formControlName="fax">
|
||||||
|
<mat-icon matSuffix>fax</mat-icon>
|
||||||
|
<mat-error *ngIf="contactForm.get('fax')?.errors?.['pattern']">
|
||||||
|
Please enter a valid fax number (10-15 digits)
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Email</mat-label>
|
||||||
|
<input matInput formControlName="email" required>
|
||||||
|
<mat-icon matSuffix>email</mat-icon>
|
||||||
|
<mat-error *ngIf="contactForm.get('email')?.errors?.['required']">
|
||||||
|
Email is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="contactForm.get('email')?.errors?.['email']">
|
||||||
|
Please enter a valid email address
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="contactForm.get('email')?.errors?.['maxlength']">
|
||||||
|
Maximum 100 characters allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<!--
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-checkbox formControlName="defaultContact">Default Contact</mat-checkbox>
|
||||||
|
</div> -->
|
||||||
|
<div *ngIf="isEditing" class="readonly-section">
|
||||||
|
<div class="readonly-fields">
|
||||||
|
<div class="field-column">
|
||||||
|
<!-- Last Changed By -->
|
||||||
|
<div class="readonly-field">
|
||||||
|
<label>Last Changed By</label>
|
||||||
|
<div class="readonly-value">
|
||||||
|
{{contactReadOnlyFields.lastChangedBy || 'N/A'}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Inactive status -->
|
||||||
|
<div class="readonly-field">
|
||||||
|
<label>Inactive Status </label>
|
||||||
|
<div class="readonly-value">
|
||||||
|
{{contactReadOnlyFields.isInactive === true ? 'Yes' : 'No' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field-column">
|
||||||
|
|
||||||
|
<!-- Last Changed Date -->
|
||||||
|
<div class="readonly-field">
|
||||||
|
<label>Last Changed Date</label>
|
||||||
|
<div class="readonly-value">
|
||||||
|
{{(contactReadOnlyFields.lastChangedDate | date:'mediumDate':'UTC') || 'N/A'}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Inactivated Date -->
|
||||||
|
<div class="readonly-field">
|
||||||
|
<label>Inactivated Date</label>
|
||||||
|
<div class="readonly-value">
|
||||||
|
{{(contactReadOnlyFields.inactivatedDate | date:'mediumDate':'UTC') || 'N/A'}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<button mat-button type="button" (click)="cancelEdit()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" type="submit" [disabled]="contactForm.invalid">
|
||||||
|
{{ isEditing ? 'Update' : 'Save' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
354
src/app/holder/holder-contacts/holder-contacts.component.scss
Normal file
354
src/app/holder/holder-contacts/holder-contacts.component.scss
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
.contacts-container {
|
||||||
|
padding: 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
|
||||||
|
.actions-bar {
|
||||||
|
clear: both;
|
||||||
|
margin-bottom: -16px;
|
||||||
|
|
||||||
|
mat-slide-toggle {
|
||||||
|
transform: scale(0.8);
|
||||||
|
margin-left: -0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
position: relative;
|
||||||
|
overflow: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.loading-shade {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(255, 255, 255, 0.7);
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-table {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-actions {
|
||||||
|
width: 180px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-defaultContact {
|
||||||
|
width: 80px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data-message {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.9rem;
|
||||||
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
font-size: 1rem;
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
margin-bottom: -3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-paginator {
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
background-color: white;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
.form-header {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--mat-sys-primary);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
mat-form-field {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-field {
|
||||||
|
max-width: 120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readonly-section {
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
|
||||||
|
.readonly-fields {
|
||||||
|
display: flex;
|
||||||
|
gap: 2rem;
|
||||||
|
|
||||||
|
.field-column {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.readonly-field {
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readonly-value {
|
||||||
|
padding: 0.25rem;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Responsive adjustments
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.contacts-container {
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px !important;
|
||||||
|
|
||||||
|
.small-field {
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contacts-container {
|
||||||
|
padding: 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
|
||||||
|
.actions-bar {
|
||||||
|
clear: both;
|
||||||
|
margin-bottom: -16px;
|
||||||
|
|
||||||
|
mat-slide-toggle {
|
||||||
|
transform: scale(0.8);
|
||||||
|
margin-left: -0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
position: relative;
|
||||||
|
overflow: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.loading-shade {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(255, 255, 255, 0.7);
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-table {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.rowActions {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-actions {
|
||||||
|
width: 180px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-defaultContact {
|
||||||
|
width: 80px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data-message {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.9rem;
|
||||||
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
font-size: 1rem;
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
margin-bottom: -3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-paginator {
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
background-color: white;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
.form-header {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--mat-sys-primary);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
mat-form-field {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-field {
|
||||||
|
max-width: 120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readonly-section {
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
|
||||||
|
.readonly-fields {
|
||||||
|
display: flex;
|
||||||
|
gap: 2rem;
|
||||||
|
|
||||||
|
.field-column {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.readonly-field {
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readonly-value {
|
||||||
|
padding: 0.25rem;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Responsive adjustments
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.contacts-container {
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px !important;
|
||||||
|
|
||||||
|
.small-field {
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
203
src/app/holder/holder-contacts/holder-contacts.component.ts
Normal file
203
src/app/holder/holder-contacts/holder-contacts.component.ts
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||||
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
||||||
|
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
|
import { PhonePipe } from '../../shared/pipes/phone.pipe';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
|
import { MatSort } from '@angular/material/sort';
|
||||||
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
|
import { UserPreferences } from '../../core/models/user-preference';
|
||||||
|
import { NotificationService } from '../../core/services/common/notification.service';
|
||||||
|
import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service';
|
||||||
|
import { ContactFormModel, HolderContact } from '../../core/models/holder/contact';
|
||||||
|
import { ContactService } from '../../core/services/holder/contact.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-holder-contacts',
|
||||||
|
imports: [AngularMaterialModule, ReactiveFormsModule, PhonePipe, CommonModule],
|
||||||
|
templateUrl: './holder-contacts.component.html',
|
||||||
|
styleUrl: './holder-contacts.component.scss'
|
||||||
|
})
|
||||||
|
export class HolderContactsComponent {
|
||||||
|
@Input() isEditMode: boolean = false;
|
||||||
|
@Input() holderid: number = 0;
|
||||||
|
@Input() userPreferences: UserPreferences = {};
|
||||||
|
|
||||||
|
@Output() hasContacts = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||||
|
@ViewChild(MatSort) sort!: MatSort;
|
||||||
|
|
||||||
|
displayedColumns: string[] = ['firstName', 'lastName', 'title', 'phone', 'mobile', 'email', 'actions'];
|
||||||
|
dataSource = new MatTableDataSource<any>();
|
||||||
|
contactForm: FormGroup;
|
||||||
|
|
||||||
|
isEditing = false;
|
||||||
|
currentContactId: number | null = null;
|
||||||
|
isLoading = false;
|
||||||
|
showForm = false;
|
||||||
|
showInactiveContacts = false;
|
||||||
|
contacts: HolderContact[] = [];
|
||||||
|
|
||||||
|
contactReadOnlyFields: any = {
|
||||||
|
lastChangedDate: null,
|
||||||
|
lastChangedBy: null,
|
||||||
|
isInactive: null,
|
||||||
|
inactivatedDate: null
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private contactService: ContactService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private errorHandler: ApiErrorHandlerService
|
||||||
|
) {
|
||||||
|
this.contactForm = 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)]],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
if (this.holderid > 0) {
|
||||||
|
this.loadContacts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InactivateHolderContact(HOLDERCONTACTID: number): void {
|
||||||
|
this.contactService.InactivateHolderContact(HOLDERCONTACTID).subscribe(
|
||||||
|
{
|
||||||
|
next: (basicData: any) => {
|
||||||
|
this.notificationService.showSuccess(`HolderContact Inactivated successfully`);
|
||||||
|
this.loadContacts()
|
||||||
|
},
|
||||||
|
error: (error: any) => {
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, `Failed to Inactivate HolderContact`);
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
console.error('Error Inactivating HolderContact:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactivateHolderContact(HOLDERCONTACTID: number): void {
|
||||||
|
this.contactService.ReactivateHolderContact(HOLDERCONTACTID).subscribe(
|
||||||
|
{
|
||||||
|
next: (basicData: any) => {
|
||||||
|
this.notificationService.showSuccess(`HolderContact Reactivated successfully`);
|
||||||
|
this.loadContacts()
|
||||||
|
},
|
||||||
|
error: (error: any) => {
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, `Failed to Reactivate HolderContact`);
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
console.error('Error Reactivating HolderContact:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadContacts(): void {
|
||||||
|
this.isLoading = true;
|
||||||
|
|
||||||
|
this.contactService.getHolderContactsByHolderId(this.holderid).subscribe({
|
||||||
|
next: (contacts: HolderContact[]) => {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addNewContact(): void {
|
||||||
|
this.showForm = true;
|
||||||
|
this.isEditing = false;
|
||||||
|
this.currentContactId = null;
|
||||||
|
this.contactForm.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
editContact(contact: HolderContact): void {
|
||||||
|
this.showForm = true;
|
||||||
|
this.isEditing = true;
|
||||||
|
this.currentContactId = contact.HOLDERCONTACTID;
|
||||||
|
|
||||||
|
this.contactForm.patchValue({
|
||||||
|
firstName: contact.FIRSTNAME,
|
||||||
|
lastName: contact.LASTNAME,
|
||||||
|
middleInitial: contact.MIDDLEINITIAL,
|
||||||
|
title: contact.TITLE,
|
||||||
|
phone: contact.PHONE,
|
||||||
|
mobile: contact.MOBILE,
|
||||||
|
fax: contact.FAX,
|
||||||
|
email: contact.EMAILADDRESS
|
||||||
|
});
|
||||||
|
|
||||||
|
this.contactReadOnlyFields.lastChangedDate = contact.LASTUPDATEDDATE ?? contact.DATECREATED;
|
||||||
|
this.contactReadOnlyFields.lastChangedBy = contact.LASTUPDATEDBY ?? contact.CREATEDBY;
|
||||||
|
this.contactReadOnlyFields.isInactive = contact.INACTIVEFLAG === 'Y';
|
||||||
|
this.contactReadOnlyFields.inactivatedDate = contact.INACTIVEDATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveContact(): void {
|
||||||
|
if (this.contactForm.invalid && !(this.holderid > 0)) {
|
||||||
|
this.contactForm.markAllAsTouched();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const contactData: ContactFormModel = this.contactForm.value;
|
||||||
|
|
||||||
|
const saveObservable = this.isEditing && (this.currentContactId! > 0)
|
||||||
|
? this.contactService.updateHolderContact(this.currentContactId!, contactData)
|
||||||
|
: this.contactService.createHolderContact(this.holderid, contactData);
|
||||||
|
|
||||||
|
saveObservable.subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.notificationService.showSuccess(`Contact ${this.isEditing ? 'updated' : 'added'} successfully`);
|
||||||
|
this.loadContacts();
|
||||||
|
this.cancelEdit();
|
||||||
|
this.hasContacts.emit(true);
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, `Failed to ${this.isEditing ? 'update' : 'add'} contact`);
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
console.error('Error saving contact:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleShowInactiveContacts(): void {
|
||||||
|
this.showInactiveContacts = !this.showInactiveContacts;
|
||||||
|
this.renderContacts();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContacts(): void {
|
||||||
|
if (this.showInactiveContacts) {
|
||||||
|
this.dataSource.data = this.contacts.filter(contact => contact.INACTIVEFLAG === 'Y');
|
||||||
|
} else {
|
||||||
|
this.dataSource.data = this.contacts.filter(contact => contact.INACTIVEFLAG === 'N');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelEdit(): void {
|
||||||
|
this.showForm = false;
|
||||||
|
this.isEditing = false;
|
||||||
|
this.currentContactId = null;
|
||||||
|
this.contactForm.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
166
src/app/holder/holder-detail/holder-detail.component.html
Normal file
166
src/app/holder/holder-detail/holder-detail.component.html
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<div class="basic-details-container">
|
||||||
|
<mat-card class="details-card mat-elevation-z4">
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="loading-shade" *ngIf="isLoading">
|
||||||
|
<mat-spinner diameter="50"></mat-spinner>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form [formGroup]="holderDetailsForm" class="details-form"
|
||||||
|
(ngSubmit)="saveHolderDetails()">
|
||||||
|
|
||||||
|
<!-- Client Information -->
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline" class="name">
|
||||||
|
<mat-label>Holder Name</mat-label>
|
||||||
|
<input matInput formControlName="holderName" required>
|
||||||
|
<mat-error *ngIf="f['holderName'].errors?.['required']">
|
||||||
|
Name is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="f['holderName'].errors?.['maxlength']">
|
||||||
|
Maximum 100 characters allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="lookup-code">
|
||||||
|
<mat-label>DBA Name</mat-label>
|
||||||
|
<input matInput formControlName="DBAName">
|
||||||
|
<mat-error *ngIf="f['DBAName'].errors?.['required']">
|
||||||
|
Lookup code is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="f['DBAName'].errors?.['maxlength']">
|
||||||
|
Maximum 20 characters allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline" class="HolderNumber">
|
||||||
|
<mat-label>Tax ID No</mat-label>
|
||||||
|
<input matInput formControlName="HolderNumber" required>
|
||||||
|
<mat-error *ngIf="f['HolderNumber'].errors?.['required']">
|
||||||
|
Lookup code is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="f['HolderNumber'].errors?.['maxlength']">
|
||||||
|
Maximum 20 characters allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="question-row">
|
||||||
|
<mat-radio-group formControlName="holderType">
|
||||||
|
<mat-label>Holder Type : </mat-label>
|
||||||
|
<mat-radio-button value="CORP">Corporation</mat-radio-button>
|
||||||
|
<mat-radio-button value="IND">Individual</mat-radio-button>
|
||||||
|
<mat-radio-button value="GOV ">Government Agency </mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="question-row">
|
||||||
|
<mat-radio-group formControlName="USCIBMember">
|
||||||
|
<mat-label>Are you a member of USCIB ?</mat-label>
|
||||||
|
<mat-radio-button [value]="'Y'">Yes</mat-radio-button>
|
||||||
|
<mat-radio-button [value]="'N'">No</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="question-row">
|
||||||
|
<mat-radio-group formControlName="govAgency">
|
||||||
|
<mat-label>Are you belong to Government Agency ?</mat-label>
|
||||||
|
<mat-radio-button [value]="'Y'">Yes</mat-radio-button>
|
||||||
|
<mat-radio-button [value]="'N'">No</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Address Information -->
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline" class="address1">
|
||||||
|
<mat-label>Address Line 1</mat-label>
|
||||||
|
<input matInput formControlName="address1" required>
|
||||||
|
<mat-error *ngIf="f['address1'].errors?.['required']">
|
||||||
|
Address is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="f['address1'].errors?.['maxlength']">
|
||||||
|
Maximum 100 characters allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline" class="address2">
|
||||||
|
<mat-label>Address Line 2 (Optional)</mat-label>
|
||||||
|
<input matInput formControlName="address2">
|
||||||
|
<mat-error *ngIf="f['address2'].errors?.['maxlength']">
|
||||||
|
Maximum 100 characters allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Location Information -->
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline" class="city">
|
||||||
|
<mat-label>City</mat-label>
|
||||||
|
<input matInput formControlName="city" required>
|
||||||
|
<mat-error *ngIf="f['city'].errors?.['required']">
|
||||||
|
City is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="f['city'].errors?.['maxlength']">
|
||||||
|
Maximum 50 characters allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="country">
|
||||||
|
<mat-label>Country</mat-label>
|
||||||
|
<mat-select formControlName="country" required
|
||||||
|
(selectionChange)="onCountryChange($event.value)">
|
||||||
|
<mat-option *ngFor="let country of countries" [value]="country.value">
|
||||||
|
{{ country.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="f['country'].errors?.['required']">
|
||||||
|
Country is required
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="state">
|
||||||
|
<mat-label>State/Province</mat-label>
|
||||||
|
<mat-select formControlName="state" required>
|
||||||
|
<mat-option *ngFor="let state of states" [value]="state.value">
|
||||||
|
{{ state.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="f['state'].errors?.['required']">
|
||||||
|
State is required
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="zip">
|
||||||
|
<mat-label>ZIP/Postal Code</mat-label>
|
||||||
|
<input matInput formControlName="zip" required>
|
||||||
|
<mat-error *ngIf="f['zip'].errors?.['required']">
|
||||||
|
ZIP/Postal code is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error
|
||||||
|
*ngIf="f['country']?.value === 'US' && f['zip']?.touched && f['zip']?.errors?.['invalidUSZip']">
|
||||||
|
Please enter a valid 5-digit US ZIP code
|
||||||
|
</mat-error>
|
||||||
|
<mat-error
|
||||||
|
*ngIf="f['country']?.value === 'CA' && f['zip']?.touched && f['zip']?.errors?.['invalidCanadaPostal']">
|
||||||
|
Please enter a valid postal code (e.g., A1B2C3)
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="form-actions">
|
||||||
|
<button mat-raised-button color="primary" type="submit"
|
||||||
|
[disabled]="holderDetailsForm.invalid || !holderDetailsForm.dirty">
|
||||||
|
{{ isEditMode ? 'Update' : 'Save' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
125
src/app/holder/holder-detail/holder-detail.component.scss
Normal file
125
src/app/holder/holder-detail/holder-detail.component.scss
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
.basic-details-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.details-card {
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
background: none;
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
.loading-shade {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(255, 255, 255, 0.7);
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
align-items: start;
|
||||||
|
|
||||||
|
.question-row {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
// padding: 1rem;
|
||||||
|
// background: #ffff;
|
||||||
|
border-radius: 4px;
|
||||||
|
// box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
mat-radio-group {
|
||||||
|
display: flex;
|
||||||
|
// flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
mat-radio-button {
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lookup-code {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.HolderNumber{
|
||||||
|
grid-column: span 1;
|
||||||
|
// background-color: azure;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address1,
|
||||||
|
.address2 {
|
||||||
|
grid-column: span 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.city,
|
||||||
|
.state,
|
||||||
|
.country,
|
||||||
|
.zip {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carnet-issuing-region,
|
||||||
|
.revenue-location {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 960px) {
|
||||||
|
.basic-details-container {
|
||||||
|
.details-card {
|
||||||
|
.form-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
|
||||||
|
.name,
|
||||||
|
.lookup-code,
|
||||||
|
.address1,
|
||||||
|
.address2,
|
||||||
|
.city,
|
||||||
|
.state,
|
||||||
|
.zip,
|
||||||
|
.country,
|
||||||
|
.carnet-issuing-region,
|
||||||
|
.revenue-location {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
205
src/app/holder/holder-detail/holder-detail.component.ts
Normal file
205
src/app/holder/holder-detail/holder-detail.component.ts
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||||
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
||||||
|
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { State } from '../../core/models/state';
|
||||||
|
import { Region } from '../../core/models/region';
|
||||||
|
import { NotificationService } from '../../core/services/common/notification.service';
|
||||||
|
import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service';
|
||||||
|
import { ZipCodeValidator } from '../../shared/validators/zipcode-validator';
|
||||||
|
import { HolderDetail, HolderDetailFormType } from '../../core/models/holder/holder-details';
|
||||||
|
import { HolderDetailService } from '../../core/services/holder/holder-detail.service';
|
||||||
|
import { CommonService } from '../../core/services/common/common.service';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
import { Country } from '../../core/models/country';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-holder-detail',
|
||||||
|
imports: [AngularMaterialModule, ReactiveFormsModule, CommonModule],
|
||||||
|
templateUrl: './holder-detail.component.html',
|
||||||
|
styleUrl: './holder-detail.component.scss'
|
||||||
|
})
|
||||||
|
export class HolderDetailComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
@Input() isEditMode = false;
|
||||||
|
@Input() holderid: number = 0;
|
||||||
|
|
||||||
|
@Output() holderIdCreated = new EventEmitter<number>();
|
||||||
|
@Output() clientName = new EventEmitter<string>();
|
||||||
|
|
||||||
|
holderDetailsForm: FormGroup;
|
||||||
|
countries: Country[] = [];
|
||||||
|
regions: Region[] = [];
|
||||||
|
states: State[] = [];
|
||||||
|
|
||||||
|
isLoading = false;
|
||||||
|
countriesHasStates = ['US', 'CA', 'MX'];
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private holderDetailService: HolderDetailService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private commonService: CommonService,
|
||||||
|
private errorHandler: ApiErrorHandlerService) {
|
||||||
|
this.holderDetailsForm = this.createForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
createForm(): FormGroup {
|
||||||
|
return this.fb.group({
|
||||||
|
holderName: ['', [Validators.required, Validators.maxLength(100)]],
|
||||||
|
DBAName: ['', [Validators.maxLength(20)]],
|
||||||
|
HolderNumber: ['', [Validators.required, Validators.maxLength(20)]],
|
||||||
|
holderType: ['', [Validators.required, Validators.maxLength(20)]],
|
||||||
|
USCIBMember: ['', [Validators.required]],
|
||||||
|
govAgency: ['', [Validators.required]],
|
||||||
|
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')]]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadLookupData();
|
||||||
|
|
||||||
|
if (this.holderid > 0) {
|
||||||
|
this.isLoading = true;
|
||||||
|
this.holderDetailService.getHolderDetailByHolderId(this.holderid).subscribe({
|
||||||
|
next: (basicDetail: HolderDetail) => {
|
||||||
|
this.patchFormData(basicDetail);
|
||||||
|
this.clientName.emit(basicDetail.HOLDERNAME);
|
||||||
|
this.isLoading = false;
|
||||||
|
},
|
||||||
|
error: (error: any) => {
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load holder details');
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
this.isLoading = false;
|
||||||
|
console.error('Error loading holder details:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
patchFormData(data: any): void {
|
||||||
|
|
||||||
|
this.holderDetailsForm.patchValue({
|
||||||
|
holderName: data.HOLDERNAME,
|
||||||
|
DBAName: data.ADDLNAME,
|
||||||
|
HolderNumber: data.HOLDERNO,
|
||||||
|
holderType: data.HOLDERTYPE,
|
||||||
|
USCIBMember: data.USCIBMEMBERFLAG,
|
||||||
|
govAgency: data.GOVAGENCYFLAG,
|
||||||
|
address1: data.ADDRESS1,
|
||||||
|
address2: data.ADDRESS2,
|
||||||
|
city: data.CITY,
|
||||||
|
state: data.STATE,
|
||||||
|
country: data.COUNTRY,
|
||||||
|
zip: data.ZIP
|
||||||
|
})
|
||||||
|
|
||||||
|
if (data.COUNTRY) {
|
||||||
|
this.loadStates(data.COUNTRY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get f() {
|
||||||
|
return this.holderDetailsForm.controls;
|
||||||
|
}
|
||||||
|
|
||||||
|
onCountryChange(country: string): void {
|
||||||
|
this.holderDetailsForm.get('state')?.reset();
|
||||||
|
|
||||||
|
if (country) {
|
||||||
|
this.loadStates(country);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.holderDetailsForm.get('zip')?.updateValueAndValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
saveHolderDetails() {
|
||||||
|
if (this.holderDetailsForm.invalid) {
|
||||||
|
this.holderDetailsForm.markAllAsTouched();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const holderDetailData: HolderDetailFormType = this.holderDetailsForm.value;
|
||||||
|
|
||||||
|
const saveObservable = this.isEditMode && this.holderid > 0
|
||||||
|
? this.holderDetailService.updateHolderDetails(this.holderid, holderDetailData)
|
||||||
|
: this.holderDetailService.createHolderDetail(holderDetailData);
|
||||||
|
|
||||||
|
saveObservable.subscribe({
|
||||||
|
next: (basicData: any) => {
|
||||||
|
this.notificationService.showSuccess(`Holder details ${this.isEditMode ? 'updated' : 'added'} successfully`);
|
||||||
|
|
||||||
|
if (!this.isEditMode) {
|
||||||
|
this.holderIdCreated.emit(basicData.HOLDERID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isEditMode) {
|
||||||
|
this.clientName.emit(holderDetailData.holderName);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (error: any) => {
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, `Failed to ${this.isEditMode ? 'update' : 'add'} Holder details`);
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
console.error('Error saving basic details:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStateControl(controlName: string, country: string): void {
|
||||||
|
const stateControl = this.holderDetailsForm.get(controlName);
|
||||||
|
if (this.countriesHasStates.includes(country)) {
|
||||||
|
stateControl?.enable();
|
||||||
|
} else {
|
||||||
|
stateControl?.disable();
|
||||||
|
stateControl?.setValue('FN');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadLookupData(): void {
|
||||||
|
|
||||||
|
this.commonService.getCountries(0)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
|
next: (countries) => {
|
||||||
|
this.countries = countries;
|
||||||
|
this.isLoading = false;
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('Failed to load countries', error);
|
||||||
|
this.isLoading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadStates(country: string): void {
|
||||||
|
this.isLoading = true;
|
||||||
|
country = this.countriesHasStates.includes(country) ? country : 'FN';
|
||||||
|
this.commonService.getStates(country, this.holderid)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
|
next: (states) => {
|
||||||
|
this.states = states;
|
||||||
|
this.updateStateControl('state', country);
|
||||||
|
this.isLoading = false;
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('Failed to load states', error);
|
||||||
|
this.isLoading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
131
src/app/holder/search/search.component.html
Normal file
131
src/app/holder/search/search.component.html
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
<div style="margin-top: 16px;" class="manage-preparers-container">
|
||||||
|
<h2 class="page-header">Search Holders</h2>
|
||||||
|
|
||||||
|
<div class="search-section">
|
||||||
|
<form class="search-form" [formGroup]="searchForm" (ngSubmit)="onSearch()">
|
||||||
|
<div class="search-fields">
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline" class="name">
|
||||||
|
<mat-label>Holder Name</mat-label>
|
||||||
|
<input matInput formControlName="holderName" placeholder="Enter holder name">
|
||||||
|
<mat-icon matSuffix>search</mat-icon>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-actions">
|
||||||
|
<button mat-raised-button color="primary" type="submit" [disabled]="HolderSaved">
|
||||||
|
<mat-icon>search</mat-icon>
|
||||||
|
Search
|
||||||
|
</button>
|
||||||
|
<button mat-raised-button type="button" (click)="onClearSearch()" [disabled]="HolderSaved">
|
||||||
|
<mat-icon>clear</mat-icon>
|
||||||
|
Clear Search
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button mat-raised-button color="primary" (click)="addNewHolder()" [disabled]="HolderSaved">
|
||||||
|
<mat-icon>add</mat-icon>
|
||||||
|
Add New Holder
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="results-section">
|
||||||
|
<div class="loading-shade" *ngIf="isLoading">
|
||||||
|
<mat-spinner diameter="50"></mat-spinner>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="actions-bar" style="margin-bottom: 10px;">
|
||||||
|
<mat-slide-toggle (change)="toggleShowInactiveHolders()" [disabled]="holdersSearched.length === 0">
|
||||||
|
Show Inactive Holders
|
||||||
|
</mat-slide-toggle>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table mat-table [dataSource]="dataSource" class="results-table" matSort>
|
||||||
|
|
||||||
|
<!-- Name Column -->
|
||||||
|
<ng-container matColumnDef="HolderName">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Holder Name</th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{ client.HOLDERNAME }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Address Column -->
|
||||||
|
<ng-container matColumnDef="DBAName">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>DBA Name</th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{ client.ADDLNAME || '--'}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- City Column -->
|
||||||
|
<ng-container matColumnDef="Address">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Address</th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{ client.ADDRESS1 }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- State Column -->
|
||||||
|
<ng-container matColumnDef="USCIBMember">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>USCIB Member</th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{ client.USCIBMEMBERFLAG === 'Y' ? 'Yes' : 'No' }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Country Column -->
|
||||||
|
<ng-container matColumnDef="HolderType">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Holder Type</th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{ client.HOLDERTYPE }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Actions Column -->
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef class="actions-header">Actions</th>
|
||||||
|
<td mat-cell *matCellDef="let client" class="actions-cell">
|
||||||
|
<button mat-icon-button color="primary" (click)="onEdit(client.HOLDERID)" matTooltip="Edit"
|
||||||
|
[disabled]="HolderSaved">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button mat-icon-button color="warn" *ngIf="client.INACTIVEFLAG === 'N'" matTooltip="Inactivate"
|
||||||
|
(click)="InactivateHolder(client.HOLDERID)">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button color="warn" *ngIf="client.INACTIVEFLAG === 'Y'" matTooltip="Reactivate"
|
||||||
|
(click)="ReactivateHolder(client.HOLDERID)">
|
||||||
|
<mat-icon>delete_outline</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<mat-radio-button style="position: absolute; margin-left: 10px" matTooltip="Select Holder"
|
||||||
|
class="selectHolder"
|
||||||
|
[value]="client.HOLDERID"
|
||||||
|
[checked]="selectedHolderId === client.HOLDERID"
|
||||||
|
(change)="onRadioSelect(client)" aria-label="Select row"
|
||||||
|
[hidden]="client.INACTIVEFLAG === 'Y'">
|
||||||
|
</mat-radio-button>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
|
||||||
|
<tr matNoDataRow *matNoDataRow>
|
||||||
|
<td [attr.colspan]="displayedColumns.length" class="no-data-message">
|
||||||
|
<mat-icon>info</mat-icon>
|
||||||
|
<span>No records found matching your criteria</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator [length]="dataSource.data.length" [pageSizeOptions]="[userPreferences.pageSize || 2]"
|
||||||
|
[hidePageSize]="true" showFirstLastButtons></mat-paginator>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<button mat-button type="button" (click)="cancelEdit()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" type="submit" [disabled]="selectedHolderId && HolderSaved"
|
||||||
|
(click)="completeSelection()">
|
||||||
|
{{ 'Save' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
135
src/app/holder/search/search.component.scss
Normal file
135
src/app/holder/search/search.component.scss
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
.page-header {
|
||||||
|
margin: 0.5rem 0px;
|
||||||
|
color: var(--mat-sys-primary);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-preparers-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.search-fields {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
align-items: start;
|
||||||
|
|
||||||
|
.name,
|
||||||
|
.address {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.city,
|
||||||
|
.state,
|
||||||
|
.lookup-code {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-section {
|
||||||
|
position: relative;
|
||||||
|
overflow: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.loading-shade {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(255, 255, 255, 0.7);
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-table {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-actions {
|
||||||
|
width: 180px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-defaultContact {
|
||||||
|
width: 80px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data-message {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.9rem;
|
||||||
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
font-size: 1rem;
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
margin-bottom: -3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-paginator {
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 960px) {
|
||||||
|
.manage-preparers-container {
|
||||||
|
.search-form {
|
||||||
|
.search-fields {
|
||||||
|
.form-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
|
||||||
|
.name,
|
||||||
|
.address,
|
||||||
|
.city,
|
||||||
|
.state,
|
||||||
|
.lookup-code {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
201
src/app/holder/search/search.component.ts
Normal file
201
src/app/holder/search/search.component.ts
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
import { Component, EventEmitter, inject, Input, Output, ViewChild } from '@angular/core';
|
||||||
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
||||||
|
import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { HolderDetail } from '../../core/models/holder/holder-details';
|
||||||
|
import { NavigationService } from '../../core/services/common/navigation.service';
|
||||||
|
import { UserPreferencesService } from '../../core/services/user-preference.service';
|
||||||
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
|
import { NotificationService } from '../../core/services/common/notification.service';
|
||||||
|
import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service';
|
||||||
|
import { UserPreferences } from '../../core/models/user-preference';
|
||||||
|
import { MatSort } from '@angular/material/sort';
|
||||||
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
|
import { HolderService } from '../../core/services/holder/holder.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-search',
|
||||||
|
imports: [AngularMaterialModule, ReactiveFormsModule, CommonModule],
|
||||||
|
templateUrl: './search.component.html',
|
||||||
|
styleUrl: './search.component.scss'
|
||||||
|
})
|
||||||
|
export class SearchComponent {
|
||||||
|
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||||
|
@ViewChild(MatSort) sort!: MatSort;
|
||||||
|
|
||||||
|
@Output() selectHolderCompleted = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
@Input() headerid: number = 0;
|
||||||
|
@Input() HOLDERID: number = 0
|
||||||
|
|
||||||
|
selectedHolder: any = null;
|
||||||
|
selectedHolderId: number = 0;
|
||||||
|
HolderSaved: boolean = false;
|
||||||
|
showInactiveHolders: boolean = false;
|
||||||
|
holdersSearched: any = []
|
||||||
|
isLoading: boolean = false;
|
||||||
|
|
||||||
|
userPreferences: UserPreferences;
|
||||||
|
searchForm: FormGroup;
|
||||||
|
|
||||||
|
private holderService = inject(HolderService);
|
||||||
|
private errorHandler = inject(ApiErrorHandlerService);
|
||||||
|
private notificationService = inject(NotificationService);
|
||||||
|
dataSource = new MatTableDataSource<any>([]);
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
private fb = inject(FormBuilder);
|
||||||
|
|
||||||
|
displayedColumns: string[] = ['HolderName', 'DBAName', 'Address', 'USCIBMember', 'HolderType', 'actions'];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private userPrefenceService: UserPreferencesService,
|
||||||
|
private navigationService: NavigationService,
|
||||||
|
) {
|
||||||
|
this.userPreferences = this.userPrefenceService.getPreferences();
|
||||||
|
this.searchForm = this.createSearchForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
createSearchForm(): FormGroup {
|
||||||
|
return this.fb.group({
|
||||||
|
holderName: ['']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
if (this.HOLDERID > 0) {
|
||||||
|
this.selectedHolderId = this.HOLDERID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
searchHolders(): void {
|
||||||
|
|
||||||
|
this.isLoading = true;
|
||||||
|
|
||||||
|
const filterData: { holderName: string } = this.searchForm.value;
|
||||||
|
|
||||||
|
this.holderService.searchHolders(filterData).subscribe({
|
||||||
|
next: (holders: HolderDetail[]) => {
|
||||||
|
this.holdersSearched = holders
|
||||||
|
this.dataSource.data = this.holdersSearched;
|
||||||
|
this.renderHolders()
|
||||||
|
this.isLoading = false;
|
||||||
|
},
|
||||||
|
error: (error: any) => {
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, 'Failed to search preparers');
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
this.isLoading = false;
|
||||||
|
console.error('Error loading preparers:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
isSearchCriteriaProvided(): boolean {
|
||||||
|
const values = this.searchForm.value;
|
||||||
|
return !!values.holderName
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearch(): void {
|
||||||
|
if (this.searchForm.invalid || !this.isSearchCriteriaProvided()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.searchHolders();
|
||||||
|
}
|
||||||
|
|
||||||
|
completeSelection() {
|
||||||
|
this.saveApplication();
|
||||||
|
}
|
||||||
|
|
||||||
|
saveApplication(): void {
|
||||||
|
const saveObservable = this.holderService.updateApplicationHolder(this.headerid, this.selectedHolderId ? Number(this.selectedHolderId) : 0);
|
||||||
|
|
||||||
|
saveObservable.subscribe({
|
||||||
|
next: (basicData: any) => {
|
||||||
|
this.notificationService.showSuccess(`Holder updated successfully`);
|
||||||
|
this.selectHolderCompleted.emit(true);
|
||||||
|
},
|
||||||
|
error: (error: any) => {
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, `Failed to update holder details`);
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
console.error('Error saving holder details:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleShowInactiveHolders(): void {
|
||||||
|
this.showInactiveHolders = !this.showInactiveHolders;
|
||||||
|
this.renderHolders();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHolders() {
|
||||||
|
if (this.showInactiveHolders) {
|
||||||
|
this.dataSource.data = this.holdersSearched.filter((holder: any) => holder?.INACTIVEFLAG === 'Y');
|
||||||
|
} else {
|
||||||
|
this.dataSource.data = this.holdersSearched.filter((holder: any) => holder?.INACTIVEFLAG === 'N');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addNewHolder(): void {
|
||||||
|
this.navigationService.navigate(["add-holder"], { state: { isEditMode: false } })
|
||||||
|
}
|
||||||
|
|
||||||
|
onEdit(id: string) {
|
||||||
|
this.navigationService.navigate(['edit-holder', id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelEdit() {
|
||||||
|
this.clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelection(): void {
|
||||||
|
this.selectedHolder = null;
|
||||||
|
this.selectedHolderId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
InactivateHolder(HOLDERID: number): void {
|
||||||
|
this.holderService.InactivateHolder(HOLDERID).subscribe(
|
||||||
|
{
|
||||||
|
next: (basicData: any) => {
|
||||||
|
this.notificationService.showSuccess(`Holder Inactivated successfully`);
|
||||||
|
this.searchHolders();
|
||||||
|
},
|
||||||
|
error: (error: any) => {
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, `Failed to Inactivate Holder`);
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
console.error('Error Inactivating Holder:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactivateHolder(HOLDERID: number): void {
|
||||||
|
this.holderService.ReactivateHolder(HOLDERID).subscribe(
|
||||||
|
{
|
||||||
|
next: (basicData: any) => {
|
||||||
|
this.notificationService.showSuccess(`Holder Reactivated successfully`);
|
||||||
|
this.searchHolders();
|
||||||
|
},
|
||||||
|
error: (error: any) => {
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, `Failed to Reactivate Holder`);
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
console.error('Error Reactivating Holder:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onClearSearch(): void {
|
||||||
|
this.searchForm.reset();
|
||||||
|
this.dataSource.data = []
|
||||||
|
this.holdersSearched = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
onRadioSelect(holder: any): void {
|
||||||
|
this.selectedHolder = holder;
|
||||||
|
this.selectedHolderId = holder.HOLDERID;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,6 +16,7 @@ import { NotificationService } from '../core/services/common/notification.servic
|
|||||||
import { NavigationService } from '../core/services/common/navigation.service';
|
import { NavigationService } from '../core/services/common/navigation.service';
|
||||||
import { MatRadioChange } from '@angular/material/radio';
|
import { MatRadioChange } from '@angular/material/radio';
|
||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from 'xlsx';
|
||||||
|
import { CarnetStateStore } from '../core/services/carnet/carnet-application.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
@ -25,6 +26,7 @@ import * as XLSX from 'xlsx';
|
|||||||
providers: [{ provide: MatPaginatorIntl, useClass: CustomPaginator }],
|
providers: [{ provide: MatPaginatorIntl, useClass: CustomPaginator }],
|
||||||
})
|
})
|
||||||
export class HomeComponent {
|
export class HomeComponent {
|
||||||
|
store = inject(CarnetStateStore);
|
||||||
carnetData: any[] = [];
|
carnetData: any[] = [];
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
showTable = false;
|
showTable = false;
|
||||||
@ -149,6 +151,7 @@ export class HomeComponent {
|
|||||||
|
|
||||||
newCarnet(event: MatRadioChange): void {
|
newCarnet(event: MatRadioChange): void {
|
||||||
if (event.value) {
|
if (event.value) {
|
||||||
|
this.store.resetState();
|
||||||
this.navigateTo(['add-carnet']);
|
this.navigateTo(['add-carnet']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user