manage preparer changes
This commit is contained in:
parent
fadfa87cdb
commit
12be0fb8c7
@ -6,6 +6,9 @@ import { HomeComponent } from './home/home.component';
|
|||||||
import { AppIdGuard } from './guards/appid.guard';
|
import { AppIdGuard } from './guards/appid.guard';
|
||||||
import { EditServiceProviderComponent } from './service-provider/edit/edit-service-provider.component';
|
import { EditServiceProviderComponent } from './service-provider/edit/edit-service-provider.component';
|
||||||
import { UserSettingsComponent } from './user-settings/user-settings.component';
|
import { UserSettingsComponent } from './user-settings/user-settings.component';
|
||||||
|
import { ManagePreparerComponent } from './preparer/manage/manage-preparer.component';
|
||||||
|
import { EditPreparerComponent } from './preparer/edit/edit-preparer.component';
|
||||||
|
import { AddPreparerComponent } from './preparer/add/add-preparer.component';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{ path: 'login', component: LoginComponent },
|
{ path: 'login', component: LoginComponent },
|
||||||
@ -16,6 +19,9 @@ export const routes: Routes = [
|
|||||||
{ path: 'home', component: HomeComponent },
|
{ path: 'home', component: HomeComponent },
|
||||||
{ path: 'usersettings', component: UserSettingsComponent },
|
{ path: 'usersettings', component: UserSettingsComponent },
|
||||||
{ path: 'service-provider/:id', component: EditServiceProviderComponent },
|
{ path: 'service-provider/:id', component: EditServiceProviderComponent },
|
||||||
|
{ path: 'preparer', component: ManagePreparerComponent },
|
||||||
|
{ path: 'preparer/:id', component: EditPreparerComponent },
|
||||||
|
{ path: 'add-preparer', component: AddPreparerComponent },
|
||||||
{ path: '', redirectTo: 'home', pathMatch: 'full' }
|
{ path: '', redirectTo: 'home', pathMatch: 'full' }
|
||||||
],
|
],
|
||||||
canActivate: [AuthGuard, AppIdGuard]
|
canActivate: [AuthGuard, AppIdGuard]
|
||||||
|
|||||||
@ -1,10 +1,17 @@
|
|||||||
export interface Location {
|
export interface Location {
|
||||||
id: number;
|
locationid: number;
|
||||||
clientId: number;
|
clientid: number;
|
||||||
locationName: string;
|
name: string;
|
||||||
address1: string;
|
address1: string;
|
||||||
address2?: string | null;
|
address2?: string | null;
|
||||||
city: string;
|
city: string;
|
||||||
state: string;
|
state: string;
|
||||||
country: string;
|
country: string;
|
||||||
|
zip: string;
|
||||||
|
dateCreated?: Date | null;
|
||||||
|
createdBy?: string | null;
|
||||||
|
lastUpdatedBy?: string | null;
|
||||||
|
lastUpdatedDate?: Date | null;
|
||||||
|
isInactive?: boolean | null; // TODO
|
||||||
|
inactivatedDate?: Date | null; // TODO
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,18 +39,18 @@ export class BasicDetailService {
|
|||||||
|
|
||||||
createBasicDetails(data: BasicDetail): Observable<any> {
|
createBasicDetails(data: BasicDetail): Observable<any> {
|
||||||
const basicDetails = {
|
const basicDetails = {
|
||||||
p_spid: this.userService.getUserSpid(),
|
P_SPID: this.userService.getUserSpid(),
|
||||||
p_clientname: data.name,
|
P_CLIENTNAME: data.name,
|
||||||
p_lookupcode: data.lookupCode,
|
P_LOOKUPCODE: data.lookupCode,
|
||||||
p_address1: data.address1,
|
P_ADDRESS1: data.address1,
|
||||||
p_address2: data.address2,
|
P_ADDRESS2: data.address2,
|
||||||
p_city: data.city,
|
P_CITY: data.city,
|
||||||
p_state: data.state,
|
P_STATE: data.state,
|
||||||
p_country: data.country,
|
P_COUNTRY: data.country,
|
||||||
p_zip: data.zip,
|
P_ZIP: data.zip,
|
||||||
p_issuingregion: data.carnetIssuingRegion,
|
P_ISSUINGREGION: data.carnetIssuingRegion,
|
||||||
p_revenuelocation: data.revenueLocation,
|
P_REVENUELOCATION: data.revenueLocation,
|
||||||
p_userid: this.userService.getUser(),
|
P_USERID: this.userService.getUser(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.http.post(`${this.apiUrl}/${this.apiDb}/CreateNewClients`, basicDetails);
|
return this.http.post(`${this.apiUrl}/${this.apiDb}/CreateNewClients`, basicDetails);
|
||||||
@ -58,18 +58,18 @@ export class BasicDetailService {
|
|||||||
|
|
||||||
updateBasicDetails(id: number, data: BasicDetail): Observable<any> {
|
updateBasicDetails(id: number, data: BasicDetail): Observable<any> {
|
||||||
const basicDetails = {
|
const basicDetails = {
|
||||||
p_spid: this.userService.getUserSpid(),
|
P_SPID: this.userService.getUserSpid(),
|
||||||
p_clientid: id,
|
P_CLIENTID: id,
|
||||||
p_clientname: data.name,
|
P_PREPARERNAME: data.name,
|
||||||
p_lookupcode: data.lookupCode,
|
// P_LOOKUPCODE: data.lookupCode,
|
||||||
p_address1: data.address1,
|
P_ADDRESS1: data.address1,
|
||||||
p_address2: data.address2,
|
P_ADDRESS2: data.address2,
|
||||||
p_city: data.city,
|
P_CITY: data.city,
|
||||||
p_state: data.state,
|
P_STATE: data.state,
|
||||||
p_country: data.country,
|
P_COUNTRY: data.country,
|
||||||
p_zip: data.zip,
|
P_ZIP: data.zip,
|
||||||
p_revenuelocation: data.revenueLocation,
|
P_REVENUELOCATION: data.revenueLocation,
|
||||||
p_userid: this.userService.getUser(),
|
P_USERID: this.userService.getUser(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.http.put(`${this.apiUrl}/${this.apiDb}/UpdateClient`, basicDetails);
|
return this.http.put(`${this.apiUrl}/${this.apiDb}/UpdateClient`, basicDetails);
|
||||||
|
|||||||
@ -1,9 +1,46 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
import { environment } from '../../../../environments/environment';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { UserService } from '../common/user.service';
|
||||||
|
import { BasicDetail } from '../../models/preparer/basic-detail';
|
||||||
|
import { map, Observable } from 'rxjs';
|
||||||
|
import { PreparerFilter } from '../../models/preparer/preparer-filter';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class ClientService {
|
export class ClientService {
|
||||||
|
private apiUrl = environment.apiUrl;
|
||||||
|
private apiDb = environment.apiDb;
|
||||||
|
|
||||||
|
constructor(private http: HttpClient, private userService: UserService) { }
|
||||||
|
|
||||||
|
getPreparers(filter: PreparerFilter): Observable<BasicDetail[]> {
|
||||||
|
return this.http.get<any[]>(`${this.apiUrl}/${this.apiDb}/GetPreparers?P_SPID=${this.userService.getUserSpid()}&P_STATUS=ACTIVE&P_NAME=${filter.name}&P_LOOKUPCODE=${filter.lookupCode}&P_CITY=${filter.city}&P_STATE=${filter.state}`).pipe(
|
||||||
|
map(response => this.mapToClients(response)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapToClients(data: any[]): BasicDetail[] {
|
||||||
|
return data.map(basicDetails => ({
|
||||||
|
clientid: basicDetails.CLIENTID,
|
||||||
|
spid: basicDetails.SPID,
|
||||||
|
name: basicDetails.PREPARERNAME,
|
||||||
|
lookupCode: basicDetails.LOOKUPCODE,
|
||||||
|
address1: basicDetails.ADDRESS1,
|
||||||
|
address2: basicDetails.ADDRESS2,
|
||||||
|
city: basicDetails.CITY,
|
||||||
|
state: basicDetails.STATE,
|
||||||
|
country: basicDetails.COUNTRY,
|
||||||
|
carnetIssuingRegion: basicDetails.ISSUINGREGION,
|
||||||
|
revenueLocation: basicDetails.REVENUELOCATION,
|
||||||
|
zip: basicDetails.ZIP,
|
||||||
|
// createdBy: basicDetails.CREATEDBY || null,
|
||||||
|
// dateCreated: basicDetails.DATECREATED || null,
|
||||||
|
// lastUpdatedBy: basicDetails.LASTUPDATEDBY || null,
|
||||||
|
// lastUpdatedDate: basicDetails.LASTUPDATEDDATE || null,
|
||||||
|
// isInactive: basicDetails.INACTIVEFLAG === 'Y' || false,
|
||||||
|
// inactivatedDate: basicDetails.INACTIVEDATE || null
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,20 +44,20 @@ export class ContactService {
|
|||||||
|
|
||||||
createContact(clientid: number, data: Contact): Observable<any> {
|
createContact(clientid: number, data: Contact): Observable<any> {
|
||||||
const contact = {
|
const contact = {
|
||||||
p_spid: this.userService.getUserSpid(),
|
P_SPID: this.userService.getUserSpid(),
|
||||||
p_clientid: clientid,
|
P_CLIENTID: clientid,
|
||||||
p_defcontactflag: data.defaultContact ? 'Y' : 'N',
|
P_DEFCONTACTFLAG: data.defaultContact ? 'Y' : 'N',
|
||||||
p_contactstable: [{
|
P_CONTACTSTABLE: [{
|
||||||
FirstName: data.firstName,
|
P_FIRSTNAME: data.firstName,
|
||||||
LastName: data.lastName,
|
P_LASTNAME: data.lastName,
|
||||||
MiddleInitial: data.middleInitial,
|
P_MIDDLEINITIAL: data.middleInitial,
|
||||||
Title: data.title,
|
P_TITLE: data.title,
|
||||||
EmailAddress: data.email,
|
P_EMAILADDRESS: data.email,
|
||||||
MobileNo: data.mobile,
|
P_MOBILENO: data.mobile,
|
||||||
PhoneNo: data.phone,
|
P_PHONENO: data.phone,
|
||||||
FaxNo: data.fax
|
P_FAXNO: data.fax
|
||||||
}],
|
}],
|
||||||
p_user_id: this.userService.getUser()
|
P_USERID: this.userService.getUser()
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.http.post(`${this.apiUrl}/${this.apiDb}/CreateClientContacts`, contact);
|
return this.http.post(`${this.apiUrl}/${this.apiDb}/CreateClientContacts`, contact);
|
||||||
@ -65,17 +65,17 @@ export class ContactService {
|
|||||||
|
|
||||||
updateContact(spContactId: number, data: Contact): Observable<any> {
|
updateContact(spContactId: number, data: Contact): Observable<any> {
|
||||||
const contact = {
|
const contact = {
|
||||||
p_spid: this.userService.getUserSpid(),
|
P_SPID: this.userService.getUserSpid(),
|
||||||
p_clientcontactid: spContactId,
|
P_CLIENTCONTACTID: spContactId,
|
||||||
p_firstname: data.firstName,
|
P_FIRSTNAME: data.firstName,
|
||||||
p_lastname: data.lastName,
|
P_LASTNAME: data.lastName,
|
||||||
P_middleinitial: data.middleInitial,
|
P_MIDDLEINITIAL: data.middleInitial,
|
||||||
p_title: data.title,
|
P_TITLE: data.title,
|
||||||
p_phone: data.phone,
|
P_EMAILADDRESS: data.email,
|
||||||
p_mobileno: data.mobile,
|
P_MOBILENO: data.mobile,
|
||||||
p_fax: data.fax,
|
P_PHONENO: data.phone,
|
||||||
p_emailaddress: data.email,
|
P_FAXNO: data.fax,
|
||||||
p_user_id: this.userService.getUser()
|
P_USERID: this.userService.getUser()
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.http.put(`${this.apiUrl}/${this.apiDb}/UpdateClientContacts`, contact);
|
return this.http.put(`${this.apiUrl}/${this.apiDb}/UpdateClientContacts`, contact);
|
||||||
|
|||||||
@ -1,9 +1,82 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { 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 { Location } from '../../models/preparer/location';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class LocationService {
|
export class LocationService {
|
||||||
|
private apiUrl = environment.apiUrl;
|
||||||
|
private apiDb = environment.apiDb;
|
||||||
|
|
||||||
constructor() { }
|
constructor(private http: HttpClient, private userService: UserService) { }
|
||||||
|
|
||||||
|
getLocationsById(id: number): Observable<Location[]> {
|
||||||
|
return this.http.get<any[]>(`${this.apiUrl}/${this.apiDb}/GetPreparerLocByClientid?p_spid=${this.userService.getUserSpid()}&p_clientid=${id}`).pipe(
|
||||||
|
map(response => this.mapToLocations(response)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapToLocations(data: any[]): Location[] {
|
||||||
|
return data.map(location => ({
|
||||||
|
locationid: location.LOCATIONID,
|
||||||
|
spid: location.SPID,
|
||||||
|
clientid: location.CLIENTID,
|
||||||
|
name: location.NAMEOF,
|
||||||
|
address1: location.ADDRESS1,
|
||||||
|
address2: location.ADDRESS2,
|
||||||
|
city: location.CITY,
|
||||||
|
state: location.STATE,
|
||||||
|
country: location.COUNTRY,
|
||||||
|
zip: location.ZIP,
|
||||||
|
createdBy: location.CREATEDBY || null,
|
||||||
|
dateCreated: location.DATECREATED || null,
|
||||||
|
lastUpdatedBy: location.LASTUPDATEDBY || null,
|
||||||
|
lastUpdatedDate: location.LASTUPDATEDDATE || null,
|
||||||
|
isInactive: location.INACTIVEFLAG === 'Y' || false,
|
||||||
|
inactivatedDate: location.INACTIVEDATE || null
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
createLocation(clientid: number, data: Location): Observable<any> {
|
||||||
|
const location = {
|
||||||
|
P_SPID: this.userService.getUserSpid(),
|
||||||
|
P_CLIENTID: clientid,
|
||||||
|
P_CLIENTLOCADDRESSTABLE: [{
|
||||||
|
P_NAMEOF: data.name,
|
||||||
|
P_ADDRESS1: data.address1,
|
||||||
|
P_ADDRESS2: data.address2,
|
||||||
|
P_CITY: data.city,
|
||||||
|
P_STATE: data.state,
|
||||||
|
P_COUNTRY: data.country,
|
||||||
|
P_ZIP: data.zip,
|
||||||
|
}],
|
||||||
|
P_USERID: this.userService.getUser()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.http.post(`${this.apiUrl}/${this.apiDb}/CreateClientLocations`, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLocation(locationId: number, data: Location): Observable<any> {
|
||||||
|
const location = {
|
||||||
|
P_SPID: this.userService.getUserSpid(),
|
||||||
|
P_CLIENTLOCATIONID: locationId,
|
||||||
|
P_LOCATIONNAME: data.name,
|
||||||
|
P_ADDRESS1: data.address1,
|
||||||
|
P_ADDRESS2: data.address2,
|
||||||
|
P_CITY: data.city,
|
||||||
|
P_STATE: data.state,
|
||||||
|
P_COUNTRY: data.country,
|
||||||
|
P_ZIP: data.zip,
|
||||||
|
P_USERID: this.userService.getUser()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.http.put(`${this.apiUrl}/${this.apiDb}/UpdateClientLocations`, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
// deleteLocation(clientContactId: string): Observable<any> {
|
||||||
|
// return this.http.post(`${this.apiUrl}/${this.apiDb}/InactivateSPContact?p_clientcontactid=${clientContactId}`, null);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,13 +20,13 @@
|
|||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<!-- Location Step -->
|
<!-- Location Step -->
|
||||||
<!-- <mat-step [completed]="locationCompleted" [editable]="!!clientid && contactsCompleted">
|
<mat-step [completed]="locationCompleted" [editable]="!!clientid && contactsCompleted">
|
||||||
<ng-template matStepLabel>Locations</ng-template>
|
<ng-template matStepLabel>Locations</ng-template>
|
||||||
|
|
||||||
<app-location *ngIf="clientid" [clientid]="clientid" (hasLocation)="onLocationSaved($event)"
|
<app-location *ngIf="clientid" [clientid]="clientid" (hasLocations)="onLocationSaved($event)"
|
||||||
[userPreferences]="userPreferences">
|
[userPreferences]="userPreferences">
|
||||||
</app-location>
|
</app-location>
|
||||||
</mat-step> -->
|
</mat-step>
|
||||||
|
|
||||||
</mat-stepper>
|
</mat-stepper>
|
||||||
</div>
|
</div>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||||
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
import { Subject, takeUntil, zip } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Country } from '../../core/models/country';
|
import { Country } from '../../core/models/country';
|
||||||
@ -75,10 +75,10 @@ export class BasicDetailsComponent implements OnInit, OnDestroy {
|
|||||||
createForm(): FormGroup {
|
createForm(): FormGroup {
|
||||||
return this.fb.group({
|
return this.fb.group({
|
||||||
name: ['', [Validators.required, Validators.maxLength(100)]],
|
name: ['', [Validators.required, Validators.maxLength(100)]],
|
||||||
lookupCode: ['', Validators.required, Validators.maxLength(20)],
|
lookupCode: ['', [Validators.required, Validators.maxLength(20)]],
|
||||||
address1: ['', Validators.required, Validators.maxLength(100)],
|
address1: ['', [Validators.required, Validators.maxLength(100)]],
|
||||||
address2: ['', [Validators.maxLength(100)]],
|
address2: ['', Validators.maxLength(100)],
|
||||||
city: ['', Validators.required, Validators.maxLength(50)],
|
city: ['', [Validators.required, Validators.maxLength(50)]],
|
||||||
state: ['', Validators.required],
|
state: ['', Validators.required],
|
||||||
country: ['', Validators.required],
|
country: ['', Validators.required],
|
||||||
zip: ['', [Validators.required, ZipCodeValidator('country')]],
|
zip: ['', [Validators.required, ZipCodeValidator('country')]],
|
||||||
@ -88,7 +88,7 @@ export class BasicDetailsComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadLookupData(): void {
|
loadLookupData(): void {
|
||||||
this.commonService.getCountries(this.clientid)
|
this.commonService.getCountries(0)
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntil(this.destroy$))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (countries) => {
|
next: (countries) => {
|
||||||
@ -126,13 +126,8 @@ export class BasicDetailsComponent implements OnInit, OnDestroy {
|
|||||||
.subscribe({
|
.subscribe({
|
||||||
next: (states) => {
|
next: (states) => {
|
||||||
this.states = states;
|
this.states = states;
|
||||||
const stateControl = this.basicDetailsForm.get('state');
|
this.updateStateControl('state', country);
|
||||||
if (this.countriesHasStates.includes(country)) {
|
this.updateStateControl('revenueLocation', country);
|
||||||
stateControl?.enable();
|
|
||||||
} else {
|
|
||||||
stateControl?.disable();
|
|
||||||
stateControl?.setValue('FN');
|
|
||||||
}
|
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
@ -142,6 +137,16 @@ export class BasicDetailsComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateStateControl(controlName: string, country: string): void {
|
||||||
|
const stateControl = this.basicDetailsForm.get(controlName);
|
||||||
|
if (this.countriesHasStates.includes(country)) {
|
||||||
|
stateControl?.enable();
|
||||||
|
} else {
|
||||||
|
stateControl?.disable();
|
||||||
|
stateControl?.setValue('FN');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
patchFormData(data: BasicDetail): void {
|
patchFormData(data: BasicDetail): void {
|
||||||
this.basicDetailsForm.patchValue({
|
this.basicDetailsForm.patchValue({
|
||||||
name: data.name,
|
name: data.name,
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
<div class="contacts-container">
|
<div class="contacts-container">
|
||||||
<div class="actions-bar">
|
<div class="actions-bar">
|
||||||
|
<mat-slide-toggle (change)="toggleShowInactiveContacts()">
|
||||||
|
Show Inactive Contacts
|
||||||
|
</mat-slide-toggle>
|
||||||
|
|
||||||
<button mat-raised-button color="primary" (click)="addNewContact()">
|
<button mat-raised-button color="primary" (click)="addNewContact()">
|
||||||
<mat-icon>add</mat-icon> Add New Contact
|
<mat-icon>add</mat-icon> Add New Contact
|
||||||
</button>
|
</button>
|
||||||
@ -35,6 +39,12 @@
|
|||||||
<td mat-cell *matCellDef="let contact">{{ contact.phone | phone }}</td>
|
<td mat-cell *matCellDef="let contact">{{ contact.phone | phone }}</td>
|
||||||
</ng-container>
|
</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 -->
|
<!-- Email Column -->
|
||||||
<ng-container matColumnDef="email">
|
<ng-container matColumnDef="email">
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Email</th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Email</th>
|
||||||
@ -59,13 +69,17 @@
|
|||||||
<mat-icon>edit</mat-icon>
|
<mat-icon>edit</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button color="primary" (click)="createLogin()" matTooltip="Login">
|
<button mat-icon-button color="primary" (click)="createLogin()" matTooltip="Login">
|
||||||
<mat-icon>passkey</mat-icon>
|
<mat-icon>person</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button color="warn" *ngIf="!contact.defaultContact || !contact.isInactive" (click)="
|
<button mat-icon-button color="warn" *ngIf="!contact.defaultContact || !contact.isInactive" (click)="
|
||||||
deleteContact(contact.clientContactid)" [hidden]="contact.defaultContact || contact.isInactive"
|
deleteContact(contact.clientContactid)" [hidden]="contact.defaultContact || contact.isInactive"
|
||||||
matTooltip="Inactivate">
|
matTooltip="Inactivate">
|
||||||
<mat-icon>delete</mat-icon>
|
<mat-icon>delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
<button mat-icon-button color="warn" *ngIf="!contact.isInactive" (click)="
|
||||||
|
deleteContact(contact.clientContactid)" [hidden]="contact.isInactive" matTooltip="Inactivate">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
<!-- <button mat-icon-button (click)="setDefaultContact(contact.contactId)"
|
<!-- <button mat-icon-button (click)="setDefaultContact(contact.contactId)"
|
||||||
[color]="contact.defaultContact ? 'primary' : ''" matTooltip="Set as default">
|
[color]="contact.defaultContact ? 'primary' : ''" matTooltip="Set as default">
|
||||||
<mat-icon>star</mat-icon>
|
<mat-icon>star</mat-icon>
|
||||||
|
|||||||
@ -8,6 +8,11 @@
|
|||||||
clear: both;
|
clear: both;
|
||||||
margin-bottom: -16px;
|
margin-bottom: -16px;
|
||||||
|
|
||||||
|
mat-slide-toggle {
|
||||||
|
transform: scale(0.8);
|
||||||
|
margin-left: -0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,14 +26,15 @@ export class ContactsComponent {
|
|||||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||||
@ViewChild(MatSort) sort!: MatSort;
|
@ViewChild(MatSort) sort!: MatSort;
|
||||||
|
|
||||||
displayedColumns: string[] = ['firstName', 'lastName', 'title', 'phone', 'email', 'defaultContact', 'actions'];
|
displayedColumns: string[] = ['firstName', 'lastName', 'title', 'phone', 'mobile', 'email', 'defaultContact', 'actions'];
|
||||||
dataSource = new MatTableDataSource<any>();
|
dataSource = new MatTableDataSource<any>();
|
||||||
contactForm: FormGroup;
|
contactForm: FormGroup;
|
||||||
isEditing = false;
|
isEditing = false;
|
||||||
currentContactId: number | null = null;
|
currentContactId: number | null = null;
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
showForm = false;
|
showForm = false;
|
||||||
|
showInactiveContacts = false;
|
||||||
|
contacts: Contact[] = [];
|
||||||
contactReadOnlyFields: any = {
|
contactReadOnlyFields: any = {
|
||||||
lastChangedDate: null,
|
lastChangedDate: null,
|
||||||
lastChangedBy: null,
|
lastChangedBy: null,
|
||||||
@ -79,7 +80,8 @@ export class ContactsComponent {
|
|||||||
|
|
||||||
this.contactService.getContactsById(this.clientid).subscribe({
|
this.contactService.getContactsById(this.clientid).subscribe({
|
||||||
next: (contacts: Contact[]) => {
|
next: (contacts: Contact[]) => {
|
||||||
this.dataSource.data = contacts;
|
this.contacts = contacts;
|
||||||
|
this.renderContacts();
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
},
|
},
|
||||||
error: (error: any) => {
|
error: (error: any) => {
|
||||||
@ -91,15 +93,6 @@ export class ContactsComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyFilter(event: Event): void {
|
|
||||||
// const filterValue = (event.target as HTMLInputElement).value;
|
|
||||||
// this.dataSource.filter = filterValue.trim().toLowerCase();
|
|
||||||
|
|
||||||
// if (this.dataSource.paginator) {
|
|
||||||
// this.dataSource.paginator.firstPage();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
addNewContact(): void {
|
addNewContact(): void {
|
||||||
this.showForm = true;
|
this.showForm = true;
|
||||||
this.isEditing = false;
|
this.isEditing = false;
|
||||||
@ -159,6 +152,19 @@ export class ContactsComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleShowInactiveContacts(): void {
|
||||||
|
this.showInactiveContacts = !this.showInactiveContacts;
|
||||||
|
this.renderContacts();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContacts(): void {
|
||||||
|
if (this.showInactiveContacts) {
|
||||||
|
this.dataSource.data = this.contacts;
|
||||||
|
} else {
|
||||||
|
this.dataSource.data = this.contacts.filter(contact => !contact.isInactive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
deleteContact(contactId: string): void {
|
deleteContact(contactId: string): void {
|
||||||
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
||||||
width: '350px',
|
width: '350px',
|
||||||
|
|||||||
@ -19,12 +19,11 @@
|
|||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<app-contacts [clientid]="clientid" [userPreferences]="userPreferences"></app-contacts>
|
<app-contacts [clientid]="clientid" [userPreferences]="userPreferences"></app-contacts>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
<!--
|
|
||||||
<mat-expansion-panel>
|
<mat-expansion-panel>
|
||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
<mat-panel-title> Locations </mat-panel-title>
|
<mat-panel-title> Locations </mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<app-location [clientid]="clientid" [isEditMode]="isEditMode"
|
<app-location [clientid]="clientid" [userPreferences]="userPreferences"></app-location>
|
||||||
[userPreferences]="userPreferences"></app-location>
|
</mat-expansion-panel>
|
||||||
</mat-expansion-panel> -->
|
|
||||||
</mat-accordion>
|
</mat-accordion>
|
||||||
@ -7,10 +7,11 @@ import { UserPreferences } from '../../core/models/user-preference';
|
|||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { UserPreferencesService } from '../../core/services/user-preference.service';
|
import { UserPreferencesService } from '../../core/services/user-preference.service';
|
||||||
import { LocationComponent } from '../location/location.component';
|
import { LocationComponent } from '../location/location.component';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-edit-preparer',
|
selector: 'app-edit-preparer',
|
||||||
imports: [AngularMaterialModule, BasicDetailsComponent, ContactsComponent, LocationComponent],
|
imports: [AngularMaterialModule, CommonModule, BasicDetailsComponent, ContactsComponent, LocationComponent],
|
||||||
templateUrl: './edit-preparer.component.html',
|
templateUrl: './edit-preparer.component.html',
|
||||||
styleUrl: './edit-preparer.component.scss'
|
styleUrl: './edit-preparer.component.scss'
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1 +1,221 @@
|
|||||||
<p>location works!</p>
|
<div class="locations-container">
|
||||||
|
<div class="actions-bar">
|
||||||
|
<button mat-raised-button color="primary" (click)="addNewLocation()">
|
||||||
|
<mat-icon>add</mat-icon> Add New Location
|
||||||
|
</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>
|
||||||
|
<!-- Name Column -->
|
||||||
|
<ng-container matColumnDef="name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Location Name</th>
|
||||||
|
<td mat-cell *matCellDef="let location">{{ location.name }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Address1 Column -->
|
||||||
|
<ng-container matColumnDef="address">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Address</th>
|
||||||
|
<td mat-cell *matCellDef="let location">{{ getAddressLabel(location.address1, location.address2,
|
||||||
|
location.zip) }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- City Column -->
|
||||||
|
<ng-container matColumnDef="city">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>City</th>
|
||||||
|
<td mat-cell *matCellDef="let location">{{ location.city }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- State Column -->
|
||||||
|
<ng-container matColumnDef="state">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>State</th>
|
||||||
|
<td mat-cell *matCellDef="let location">{{ location.state }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Country Column -->
|
||||||
|
<ng-container matColumnDef="country">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Country</th>
|
||||||
|
<td mat-cell *matCellDef="let location">{{ location.country }}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Actions Column -->
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Actions</th>
|
||||||
|
<td mat-cell *matCellDef="let location">
|
||||||
|
<button mat-icon-button color="primary" (click)="editLocation(location)" matTooltip="Edit">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
<!--
|
||||||
|
<button mat-icon-button color="warn" *ngIf="!location.defaultLocation || !location.isInactive"
|
||||||
|
(click)="
|
||||||
|
deleteLocation(location.clientLocationid)"
|
||||||
|
[hidden]="location.defaultLocation || location.isInactive" matTooltip="Inactivate">
|
||||||
|
<mat-icon>delete</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!]"
|
||||||
|
[hidePageSize]="true" showFirstLastButtons></mat-paginator>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Location Form -->
|
||||||
|
<div class="form-container" *ngIf="showForm">
|
||||||
|
<form [formGroup]="locationForm" (ngSubmit)="saveLocation()">
|
||||||
|
<div class="form-header">
|
||||||
|
<h3>{{ isEditing ? 'Edit Location' : 'Add New Location' }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline" class="name">
|
||||||
|
<mat-label>Name</mat-label>
|
||||||
|
<input matInput formControlName="name" required>
|
||||||
|
<mat-error *ngIf="locationForm.get('name')?.errors?.['required']">
|
||||||
|
Name is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="locationForm.get('name')?.errors?.['maxlength']">
|
||||||
|
Maximum 100 characters allowed
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</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="locationForm.get('address1')?.errors?.['required']">
|
||||||
|
Address is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="locationForm.get('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="locationForm.get('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="locationForm.get('city')?.errors?.['required']">
|
||||||
|
City is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="locationForm.get('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="locationForm.get('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="locationForm.get('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="locationForm.get('zip')?.errors?.['required']">
|
||||||
|
ZIP/Postal code is required
|
||||||
|
</mat-error>
|
||||||
|
<mat-error
|
||||||
|
*ngIf="locationForm.get('country')?.value === 'US' && locationForm.get('zip')?.touched && locationForm.get('zip')?.errors?.['invalidUSZip']">
|
||||||
|
Please enter a valid 5-digit US ZIP code
|
||||||
|
</mat-error>
|
||||||
|
<mat-error
|
||||||
|
*ngIf="locationForm.get('country')?.value === 'CA' && locationForm.get('zip')?.touched && locationForm.get('zip')?.errors?.['invalidCanadaPostal']">
|
||||||
|
Please enter a valid postal code (e.g., A1B2C3)
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</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">
|
||||||
|
{{locationReadOnlyFields.lastChangedBy || 'N/A'}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Inactive status -->
|
||||||
|
<div class="readonly-field">
|
||||||
|
<label>Inactive Status </label>
|
||||||
|
<div class="readonly-value">
|
||||||
|
{{locationReadOnlyFields.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">
|
||||||
|
{{(locationReadOnlyFields.lastChangedDate | date:'mediumDate':'UTC') || 'N/A'}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Inactivated Date -->
|
||||||
|
<div class="readonly-field">
|
||||||
|
<label>Inactivated Date</label>
|
||||||
|
<div class="readonly-value">
|
||||||
|
{{(locationReadOnlyFields.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]="locationForm.invalid">
|
||||||
|
{{ isEditing ? 'Update' : 'Save' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,163 @@
|
|||||||
|
.locations-container {
|
||||||
|
padding: 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
|
||||||
|
.actions-bar {
|
||||||
|
clear: both;
|
||||||
|
margin-bottom: -16px;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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) {
|
||||||
|
.location-container {
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px !important;
|
||||||
|
|
||||||
|
.small-field {
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,267 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||||
|
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
|
import { MatPaginator, MatPaginatorIntl } from '@angular/material/paginator';
|
||||||
|
import { MatSort } from '@angular/material/sort';
|
||||||
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
|
import { UserPreferences } from '../../core/models/user-preference';
|
||||||
|
import { Location } from '../../core/models/preparer/location';
|
||||||
|
import { LocationService } from '../../core/services/preparer/location.service';
|
||||||
|
import { NotificationService } from '../../core/services/common/notification.service';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service';
|
||||||
|
import { CustomPaginator } from '../../shared/custom-paginator';
|
||||||
|
import { ConfirmDialogComponent } from '../../shared/components/confirm-dialog/confirm-dialog.component';
|
||||||
|
import { ZipCodeValidator } from '../../shared/validators/zipcode-validator';
|
||||||
|
import { Country } from '../../core/models/country';
|
||||||
|
import { Region } from '../../core/models/region';
|
||||||
|
import { State } from '../../core/models/state';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
import { CommonService } from '../../core/services/common/common.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-location',
|
selector: 'app-location',
|
||||||
imports: [],
|
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule],
|
||||||
templateUrl: './location.component.html',
|
templateUrl: './location.component.html',
|
||||||
styleUrl: './location.component.scss'
|
styleUrl: './location.component.scss',
|
||||||
|
providers: [{ provide: MatPaginatorIntl, useClass: CustomPaginator }],
|
||||||
})
|
})
|
||||||
export class LocationComponent {
|
export class LocationComponent {
|
||||||
|
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||||
|
@ViewChild(MatSort) sort!: MatSort;
|
||||||
|
|
||||||
|
displayedColumns: string[] = ['name', 'address', 'city', 'state', 'country', 'actions'];
|
||||||
|
dataSource = new MatTableDataSource<any>();
|
||||||
|
locationForm: FormGroup;
|
||||||
|
isEditing = false;
|
||||||
|
currentLocationId: number | null = null;
|
||||||
|
isLoading = false;
|
||||||
|
showForm = false;
|
||||||
|
countries: Country[] = [];
|
||||||
|
states: State[] = [];
|
||||||
|
|
||||||
|
locationReadOnlyFields: any = {
|
||||||
|
lastChangedDate: null,
|
||||||
|
lastChangedBy: null,
|
||||||
|
isInactive: null,
|
||||||
|
inactivatedDate: null
|
||||||
|
};
|
||||||
|
|
||||||
|
@Input() clientid: number = 0;
|
||||||
|
@Input() userPreferences: UserPreferences = {};
|
||||||
|
@Output() hasLocations = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
countriesHasStates = ['US', 'CA', 'MX'];
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private locationService: LocationService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private dialog: MatDialog,
|
||||||
|
private errorHandler: ApiErrorHandlerService,
|
||||||
|
private commonService: CommonService
|
||||||
|
) {
|
||||||
|
this.locationForm = this.fb.group({
|
||||||
|
name: ['', [Validators.required, Validators.maxLength(100)]],
|
||||||
|
address1: ['', [Validators.required, Validators.maxLength(100)]],
|
||||||
|
address2: ['', [Validators.maxLength(100)]],
|
||||||
|
city: ['', [Validators.required, Validators.maxLength(50)]],
|
||||||
|
state: ['', Validators.required],
|
||||||
|
country: ['', Validators.required],
|
||||||
|
zip: ['', [Validators.required, ZipCodeValidator('country')]],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadCountries();
|
||||||
|
this.loadLocations();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadLocations(): void {
|
||||||
|
this.isLoading = true;
|
||||||
|
|
||||||
|
this.locationService.getLocationsById(this.clientid).subscribe({
|
||||||
|
next: (locations: Location[]) => {
|
||||||
|
this.dataSource.data = locations;
|
||||||
|
this.isLoading = false;
|
||||||
|
},
|
||||||
|
error: (error: any) => {
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load locations');
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
this.isLoading = false;
|
||||||
|
console.error('Error loading locations:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onCountryChange(country: string): void {
|
||||||
|
this.locationForm.get('state')?.reset();
|
||||||
|
|
||||||
|
if (country) {
|
||||||
|
this.loadStates(country);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.locationForm.get('zip')?.updateValueAndValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
addNewLocation(): void {
|
||||||
|
this.showForm = true;
|
||||||
|
this.isEditing = false;
|
||||||
|
this.currentLocationId = null;
|
||||||
|
this.locationForm.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
editLocation(location: Location): void {
|
||||||
|
this.showForm = true;
|
||||||
|
this.isEditing = true;
|
||||||
|
this.currentLocationId = location.locationid;
|
||||||
|
this.locationForm.patchValue({
|
||||||
|
name: location.name,
|
||||||
|
address1: location.address1,
|
||||||
|
address2: location.address2,
|
||||||
|
city: location.city,
|
||||||
|
country: location.country,
|
||||||
|
state: location.state,
|
||||||
|
zip: location.zip,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (location.country) {
|
||||||
|
this.loadStates(location.country);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.locationReadOnlyFields.lastChangedDate = location.lastUpdatedDate ?? location.dateCreated;
|
||||||
|
this.locationReadOnlyFields.lastChangedBy = location.lastUpdatedBy ?? location.createdBy;
|
||||||
|
this.locationReadOnlyFields.isInactive = location.isInactive;
|
||||||
|
this.locationReadOnlyFields.inactivatedDate = location.inactivatedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveLocation(): void {
|
||||||
|
if (this.locationForm.invalid) {
|
||||||
|
this.locationForm.markAllAsTouched();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default the first location
|
||||||
|
const locationData: Location = this.locationForm.value;
|
||||||
|
|
||||||
|
const saveObservable = this.isEditing && (this.currentLocationId! > 0)
|
||||||
|
? this.locationService.updateLocation(this.currentLocationId!, locationData)
|
||||||
|
: this.locationService.createLocation(this.clientid, locationData);
|
||||||
|
|
||||||
|
saveObservable.subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.notificationService.showSuccess(`Location ${this.isEditing ? 'updated' : 'added'} successfully`);
|
||||||
|
this.loadLocations();
|
||||||
|
this.cancelEdit();
|
||||||
|
this.hasLocations.emit(true);
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
let errorMessage = this.errorHandler.handleApiError(error, `Failed to ${this.isEditing ? 'update' : 'add'} location`);
|
||||||
|
this.notificationService.showError(errorMessage);
|
||||||
|
console.error('Error saving location:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadCountries(): void {
|
||||||
|
this.commonService.getCountries(this.clientid)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
|
next: (countries) => {
|
||||||
|
this.countries = countries;
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('Failed to load countries', error);
|
||||||
|
this.isLoading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadStates(country: string): void {
|
||||||
|
this.isLoading = true;
|
||||||
|
country = this.countriesHasStates.includes(country) ? country : 'FN';
|
||||||
|
this.commonService.getStates(country, this.clientid)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
|
next: (states) => {
|
||||||
|
this.states = states;
|
||||||
|
const stateControl = this.locationForm.get('state');
|
||||||
|
if (this.countriesHasStates.includes(country)) {
|
||||||
|
stateControl?.enable();
|
||||||
|
} else {
|
||||||
|
stateControl?.disable();
|
||||||
|
stateControl?.setValue('FN');
|
||||||
|
}
|
||||||
|
this.isLoading = false;
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('Failed to load states', error);
|
||||||
|
this.isLoading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// deleteLocation(locationId: string): void {
|
||||||
|
// const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
||||||
|
// width: '350px',
|
||||||
|
// data: {
|
||||||
|
// title: 'Confirm Delete',
|
||||||
|
// message: 'Are you sure you want to delete this location?',
|
||||||
|
// confirmText: 'Delete',
|
||||||
|
// cancelText: 'Cancel'
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// dialogRef.afterClosed().subscribe(result => {
|
||||||
|
// if (result) {
|
||||||
|
// this.locationService.deleteLocation(locationId).subscribe({
|
||||||
|
// next: () => {
|
||||||
|
// this.notificationService.showSuccess('Location deleted successfully');
|
||||||
|
// this.loadLocations();
|
||||||
|
// },
|
||||||
|
// error: (error) => {
|
||||||
|
// let errorMessage = this.errorHandler.handleApiError(error, 'Failed to delete location');
|
||||||
|
// this.notificationService.showError(errorMessage);
|
||||||
|
// console.error('Error deleting location:', error);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
getAddressLabel(address1: string, address2?: string, zip?: string): string {
|
||||||
|
let addressLabel = address1;
|
||||||
|
if (address2) {
|
||||||
|
addressLabel += `, ${address2}`;
|
||||||
|
}
|
||||||
|
if (zip) {
|
||||||
|
addressLabel += `, ${zip}`;
|
||||||
|
}
|
||||||
|
return addressLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCountryLabel(value: string): string {
|
||||||
|
const country = this.countries.find(c => c.value === value);
|
||||||
|
return country ? country.name : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelEdit(): void {
|
||||||
|
this.showForm = false;
|
||||||
|
this.isEditing = false;
|
||||||
|
this.currentLocationId = null;
|
||||||
|
this.locationForm.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
133
src/app/preparer/manage/manage-preparer.component.html
Normal file
133
src/app/preparer/manage/manage-preparer.component.html
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<div class="manage-preparers-container">
|
||||||
|
<h2 class="page-header">Manage Preparers</h2>
|
||||||
|
|
||||||
|
<div class="search-section">
|
||||||
|
<form [formGroup]="searchForm" class="search-form" (ngSubmit)="onSearch()">
|
||||||
|
<div class="search-fields">
|
||||||
|
<!-- Search Criteria Row 1 -->
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline" class="name">
|
||||||
|
<mat-label>Name</mat-label>
|
||||||
|
<input matInput formControlName="name" placeholder="Enter company name">
|
||||||
|
<mat-icon matSuffix>search</mat-icon>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="address">
|
||||||
|
<mat-label>Address</mat-label>
|
||||||
|
<input matInput formControlName="address" placeholder="Enter address">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Search Criteria Row 2 -->
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline" class="city">
|
||||||
|
<mat-label>City</mat-label>
|
||||||
|
<input matInput formControlName="city" placeholder="Enter city">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="state">
|
||||||
|
<mat-label>State</mat-label>
|
||||||
|
<input matInput formControlName="state" placeholder="Enter state">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="lookup-code">
|
||||||
|
<mat-label>Lookup Code</mat-label>
|
||||||
|
<input matInput formControlName="lookupCode" placeholder="Enter lookup code">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-actions">
|
||||||
|
<button mat-raised-button color="primary" type="submit"
|
||||||
|
[disabled]="searchForm.invalid || !isSearchCriteriaProvided()">
|
||||||
|
<mat-icon>search</mat-icon>
|
||||||
|
Search
|
||||||
|
</button>
|
||||||
|
<button mat-raised-button type="button" (click)="onClear()">
|
||||||
|
<mat-icon>clear</mat-icon>
|
||||||
|
Clear Filters
|
||||||
|
</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="navigateTo('add-preparer')">
|
||||||
|
<mat-icon>add</mat-icon>
|
||||||
|
Add New Preparer
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="results-section" *ngIf="showResults">
|
||||||
|
|
||||||
|
<div class="loading-shade" *ngIf="isLoading">
|
||||||
|
<mat-spinner diameter="50"></mat-spinner>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table mat-table matSort [dataSource]="dataSource"
|
||||||
|
*ngIf="!isLoading && dataSource && dataSource.data.length > 0" class="results-table">
|
||||||
|
<!-- Name Column -->
|
||||||
|
<ng-container matColumnDef="name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Name</th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{client.name}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Address Column -->
|
||||||
|
<ng-container matColumnDef="address">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Address</th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{ getAddressLabel(client.address1, client.address2, client.zip)}}
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- City Column -->
|
||||||
|
<ng-container matColumnDef="city">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>City</th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{client.city}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- State Column -->
|
||||||
|
<ng-container matColumnDef="state">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>State</th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{client.state}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Country Column -->
|
||||||
|
<ng-container matColumnDef="country">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Country</th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{client.country}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Carnet Issuing region Column -->
|
||||||
|
<ng-container matColumnDef="carnetIssuingRegion">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Carnet Issuing region </th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{getRegionLabel(client.carnetIssuingRegion)}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Revenue Location Column -->
|
||||||
|
<ng-container matColumnDef="revenueLocation">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Revenue Location</th>
|
||||||
|
<td mat-cell *matCellDef="let client">{{client.revenueLocation}}</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.clientid)" matTooltip="Edit">
|
||||||
|
<mat-icon>edit</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 found matching your criteria</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator [length]="dataSource.data.length" [pageSizeOptions]="[userPreferences.pageSize!]"
|
||||||
|
[hidePageSize]="true" showFirstLastButtons></mat-paginator>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
128
src/app/preparer/manage/manage-preparer.component.scss
Normal file
128
src/app/preparer/manage/manage-preparer.component.scss
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
.page-header {
|
||||||
|
margin: 0.5rem 0px;
|
||||||
|
color: var(--mat-sys-primary);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
183
src/app/preparer/manage/manage-preparer.component.ts
Normal file
183
src/app/preparer/manage/manage-preparer.component.ts
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
import { AfterViewInit, Component, OnDestroy, OnInit, 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 { MatPaginator, MatPaginatorIntl } from '@angular/material/paginator';
|
||||||
|
import { MatSort } from '@angular/material/sort';
|
||||||
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
import { BasicDetail } from '../../core/models/preparer/basic-detail';
|
||||||
|
import { NotificationService } from '../../core/services/common/notification.service';
|
||||||
|
import { NavigationService } from '../../core/services/common/navigation.service';
|
||||||
|
import { UserPreferencesService } from '../../core/services/user-preference.service';
|
||||||
|
import { UserPreferences } from '../../core/models/user-preference';
|
||||||
|
import { ClientService } from '../../core/services/preparer/client.service';
|
||||||
|
import { PreparerFilter } from '../../core/models/preparer/preparer-filter';
|
||||||
|
import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service';
|
||||||
|
import { CustomPaginator } from '../../shared/custom-paginator';
|
||||||
|
import { CommonService } from '../../core/services/common/common.service';
|
||||||
|
import { Region } from '../../core/models/region';
|
||||||
|
import { Country } from '../../core/models/country';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-manage',
|
||||||
|
imports: [AngularMaterialModule, ReactiveFormsModule, CommonModule],
|
||||||
|
templateUrl: './manage-preparer.component.html',
|
||||||
|
styleUrl: './manage-preparer.component.scss',
|
||||||
|
providers: [{ provide: MatPaginatorIntl, useClass: CustomPaginator }]
|
||||||
|
})
|
||||||
|
export class ManagePreparerComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
|
|
||||||
|
@ViewChild(MatPaginator, { static: false })
|
||||||
|
set paginator(value: MatPaginator) {
|
||||||
|
this.dataSource.paginator = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewChild(MatSort, { static: false })
|
||||||
|
set sort(value: MatSort) {
|
||||||
|
this.dataSource.sort = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchForm: FormGroup;
|
||||||
|
showResults = false;
|
||||||
|
isLoading = false;
|
||||||
|
userPreferences: UserPreferences;
|
||||||
|
countries: Country[] = [];
|
||||||
|
regions: Region[] = [];
|
||||||
|
|
||||||
|
displayedColumns: string[] = ['name', 'address', 'city', 'state', 'country', 'carnetIssuingRegion', 'revenueLocation', 'actions'];
|
||||||
|
dataSource = new MatTableDataSource<any>([]);
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private userPrefenceService: UserPreferencesService,
|
||||||
|
private navigationService: NavigationService,
|
||||||
|
private clientService: ClientService,
|
||||||
|
private errorHandler: ApiErrorHandlerService,
|
||||||
|
private commonService: CommonService
|
||||||
|
) {
|
||||||
|
this.userPreferences = userPrefenceService.getPreferences();
|
||||||
|
this.searchForm = this.createSearchForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadCountries();
|
||||||
|
this.loadRegions();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
createSearchForm(): FormGroup {
|
||||||
|
return this.fb.group({
|
||||||
|
name: [''],
|
||||||
|
address: [''],
|
||||||
|
city: [''],
|
||||||
|
state: [''],
|
||||||
|
lookupCode: ['']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
isSearchCriteriaProvided(): boolean {
|
||||||
|
const values = this.searchForm.value;
|
||||||
|
return !!values.name || !!values.address || !!values.city || !!values.state || !!values.lookupCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearch(): void {
|
||||||
|
if (this.searchForm.invalid || !this.isSearchCriteriaProvided()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isLoading = true;
|
||||||
|
this.showResults = true;
|
||||||
|
const filterData: PreparerFilter = this.searchForm.value;
|
||||||
|
|
||||||
|
this.clientService.getPreparers(filterData).subscribe({
|
||||||
|
next: (clients: BasicDetail[]) => {
|
||||||
|
this.dataSource.data = clients;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onClear(): void {
|
||||||
|
this.searchForm.reset();
|
||||||
|
this.showResults = false;
|
||||||
|
this.dataSource.data = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateTo(route: string): void {
|
||||||
|
this.navigationService.navigate([route]);
|
||||||
|
}
|
||||||
|
|
||||||
|
onEdit(clientid: number): void {
|
||||||
|
this.navigationService.navigate(['preparer', clientid]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
loadRegions(): void {
|
||||||
|
this.commonService.getRegions()
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
|
next: (regions) => {
|
||||||
|
this.regions = regions;
|
||||||
|
this.isLoading = false;
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('Failed to load regions', error);
|
||||||
|
this.isLoading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadCountries(): void {
|
||||||
|
this.commonService.getCountries(0)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
|
next: (countries) => {
|
||||||
|
this.countries = countries;
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('Failed to load countries', error);
|
||||||
|
this.isLoading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getAddressLabel(address1: string, address2?: string, zip?: string): string {
|
||||||
|
let addressLabel = address1;
|
||||||
|
if (address2) {
|
||||||
|
addressLabel += `, ${address2}`;
|
||||||
|
}
|
||||||
|
if (zip) {
|
||||||
|
addressLabel += `, ${zip}`;
|
||||||
|
}
|
||||||
|
return addressLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRegionLabel(value: string): string {
|
||||||
|
const region = this.regions.find(r => r.region === value);
|
||||||
|
return region ? region.regionname : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCountryLabel(value: string): string {
|
||||||
|
const country = this.countries.find(c => c.value === value);
|
||||||
|
return country ? country.name : value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,6 +24,7 @@ import { MatToolbarModule } from '@angular/material/toolbar';
|
|||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { MatAccordion, MatExpansionModule } from '@angular/material/expansion';
|
import { MatAccordion, MatExpansionModule } from '@angular/material/expansion';
|
||||||
import { MatStepperModule } from '@angular/material/stepper';
|
import { MatStepperModule } from '@angular/material/stepper';
|
||||||
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||||
import { MAT_MOMENT_DATE_ADAPTER_OPTIONS, MatMomentDateModule } from '@angular/material-moment-adapter';
|
import { MAT_MOMENT_DATE_ADAPTER_OPTIONS, MatMomentDateModule } from '@angular/material-moment-adapter';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -53,7 +54,8 @@ import { MAT_MOMENT_DATE_ADAPTER_OPTIONS, MatMomentDateModule } from '@angular/m
|
|||||||
MatExpansionModule,
|
MatExpansionModule,
|
||||||
MatAccordion,
|
MatAccordion,
|
||||||
MatStepperModule,
|
MatStepperModule,
|
||||||
MatMomentDateModule
|
MatMomentDateModule,
|
||||||
|
MatSlideToggleModule
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
@ -79,7 +81,8 @@ import { MAT_MOMENT_DATE_ADAPTER_OPTIONS, MatMomentDateModule } from '@angular/m
|
|||||||
MatExpansionModule,
|
MatExpansionModule,
|
||||||
MatAccordion,
|
MatAccordion,
|
||||||
MatStepperModule,
|
MatStepperModule,
|
||||||
MatMomentDateModule
|
MatMomentDateModule,
|
||||||
|
MatSlideToggleModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } }
|
{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user