import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { SelectItem } from 'primeng/api'; import { Table } from 'primeng/table'; import { Customer } from '../models/customer.model'; import * as fromCustomers from '../reducers'; import * as customerActions from '../actions/customer.actions'; import { globals, OperationalStatus } from '@app/shared/global'; import { BaseComp } from '@app/shared/base/base.component'; import { CustomerCacheService } from '@app/domain/services/customer-cache.service'; import { ListReturnCacheService } from '@app/domain/services/list-return-cache.service'; import { FilterDefinition, FilterChangeEvent } from '@app/shared/dynamic-filter/dynamic-filter.component'; @Component({ selector: 'agm-customer-list', templateUrl: './customer-list.component.html', styleUrls: ['./customer-list.component.css'] }) export class CustomerListComponent extends BaseComp implements OnInit, OnDestroy { readonly CREATED = 'createdAt'; readonly ACTIVE = OperationalStatus.ACTIVE; readonly BILLABLE = 'billable'; readonly PARTNER = 'partner'; readonly PARTNER_NAME = 'partnerName'; customers: Array; curCust: Customer; @ViewChild("dt") dt: Table; statuses: SelectItem[]; partners: SelectItem[]; cols: any[]; totalItems; isSelfSignup = false; searchAccordionOpen = sessionStorage.getItem('customers-list-accordion') === 'true'; private lastFiltersQuery: Record | undefined; private useCacheOnReturn = false; cacheTtlSeconds: number; customerFilterDefinitions: FilterDefinition[]; constructor( private readonly route: ActivatedRoute, private readonly customerCache: CustomerCacheService, private readonly listReturnCache: ListReturnCacheService, ) { super(); this.cacheTtlSeconds = Math.round(this.customerCache.getTtlMs() / 1000); this.totalItems = { '=0': '', '=1': '1 ' + $localize`:@@customer:customer`.toLocaleLowerCase(), 'other': $localize`:@@total#Customers:Total: # customers` }; this.statuses = [ { label: globals.all, value: null }, { label: globals.active, value: true }, { label: globals.notActive, value: false } ]; this.cols = [ { field: "name", header: globals.name, filtered: true, filterMatchMode: 'contains' }, { field: "username", header: globals.userName, filtered: true, filterMatchMode: 'contains' }, { field: "contact", header: globals.contact }, { field: "totalJobs", header: globals.jobs, width: '5%', filtered: false }, { field: this.CREATED, header: globals.from, width: '6%' }, { field: this.BILLABLE, header: "Billable", width: '9%' }, { field: this.ACTIVE, header: globals.active, width: '9%' }, { field: this.PARTNER_NAME, header: globals.partner, width: '9%' } ]; this.customerFilterDefinitions = [ { key: 'name', label: globals.name, dataType: 'text' }, { key: 'username', label: globals.userName, dataType: 'text' }, { key: 'email', label: globals.email, dataType: 'text' }, { key: 'contact', label: globals.contact, dataType: 'text' }, { key: 'createdAt', label: globals.from, dataType: 'date-preset' }, ]; } ngOnInit() { const saved = localStorage.getItem('isSelfSignup'); this.isSelfSignup = saved === 'true'; this.sub$ = this.store.select(fromCustomers.getAllCustomers).subscribe(customers => { this.setCustomersAndPartners(customers); }); this.sub$.add(this.store.select(fromCustomers.getSelectedCustomer).subscribe(cust => { this.curCust = cust; })); this.useCacheOnReturn = this.listReturnCache.startVisit('customers'); const savedFilters = sessionStorage.getItem('customers-list-last-filters'); if (savedFilters) { try { this.lastFiltersQuery = JSON.parse(savedFilters); } catch (_err) { this.lastFiltersQuery = undefined; } } this.store.dispatch(savedFilters ? new customerActions.Fetch({ filters: savedFilters, useCache: this.useCacheOnReturn }) : new customerActions.Fetch({ useCache: this.useCacheOnReturn }) ); } private setCustomersAndPartners(customers: Customer[]) { const filtered = this.isSelfSignup ? customers.filter(c => c.selfSignup) : customers; this.customers = filtered.map(c => ({ ...c, partnerName: c.partner?.name || null })); this.partners = [ { label: globals.all, value: null }, ...customers .filter(c => c.partner) .map(c => c.partner.name) .filter((v, i, a) => a.indexOf(v) === i) .map(name => ({ label: name, value: name })) ]; } onToggle(event: any): void { this.isSelfSignup = event.checked; localStorage.setItem('isSelfSignup', String(this.isSelfSignup)); this.store.select(fromCustomers.getAllCustomers).subscribe(customers => { this.setCustomersAndPartners(customers); }); } onRowSelect(event) { this.store.dispatch(new customerActions.Select(event.data)); } onAccordionToggle(expanded: boolean) { sessionStorage.setItem('customers-list-accordion', String(expanded)); } updateCacheTtl(): void { const ttlMs = this.customerCache.setTtlMs(Number(this.cacheTtlSeconds || 0) * 1000); this.cacheTtlSeconds = Math.round(ttlMs / 1000); } onFiltersSubmit(event: FilterChangeEvent) { const q = { ...event.query }; const filtersStr = JSON.stringify(q); const prevFilters = sessionStorage.getItem('customers-list-last-filters'); if (filtersStr !== prevFilters) { this.customerCache.invalidate(); this.useCacheOnReturn = false; } this.lastFiltersQuery = q; sessionStorage.setItem('customers-list-last-filters', filtersStr); this.store.dispatch(new customerActions.Fetch({ filters: filtersStr, useCache: this.useCacheOnReturn })); } get canEdit() { return (this.curCust && this.curCust._id !== '0'); } newCustomer() { this.router.navigate(['customer', '0'], { relativeTo: this.route }); } editCustomer() { this.listReturnCache.markPending('customers'); this.router.navigate(['customer', this.curCust._id], { relativeTo: this.route }); } deleteCustomer() { if (!this.curCust) { return; } this.confirmSvc.confirm({ message: globals.confirmDeleteThing.replace('#thing#', globals.customer), accept: () => { this.store.dispatch(new customerActions.Delete(this.curCust)); this.curCust = null; } }); } ngOnDestroy() { super.ngOnDestroy(); } }