Files
ISA-Frontend/apps/page/package-inspection/src/lib/package-result/package-result.component.ts
2023-04-18 14:09:36 +02:00

261 lines
8.2 KiB
TypeScript

import { Component, ChangeDetectionStrategy, OnInit, ViewChild, OnDestroy, AfterViewInit } from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
import { CacheService } from '@core/cache';
import { Config } from '@core/config';
import { provideComponentStore } from '@ngrx/component-store';
import { ArrivalStatus, ListResponseArgsOfPackageDTO2 } from '@swagger/wws';
import { UiFilter } from '@ui/filter';
import moment from 'moment';
import { combineLatest, Subject, Subscription } from 'rxjs';
import { filter, first, map } from 'rxjs/operators';
import { PackageResultCacheData } from './package-result-cache-data';
import { PackageResultComponentStore } from './package-result.component.store';
import { SharedFilterOverlayComponent } from '@shared/components/filter-overlay';
import { PackageListComponent } from '@shared/components/package-inspection/package-list';
@Component({
selector: 'page-package-result',
templateUrl: 'package-result.component.html',
styleUrls: ['package-result.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [provideComponentStore(PackageResultComponentStore)],
})
export class PackageResultComponent implements OnInit, AfterViewInit, OnDestroy {
private _subscription = new Subscription();
get breadcrumbKey(): string {
return this._config.get('process.ids.packageInspection');
}
hint$ = new Subject<string>();
@ViewChild(SharedFilterOverlayComponent)
filterOverlay: SharedFilterOverlayComponent;
/**
* Zeigt die liste an, wenn entweder keine packages geladen werden oder wenn packages geladen wurden
* und mindestens ein package vorhanden ist.
*/
showList$ = combineLatest([this.store.fetching$, this.store.packages$]).pipe(
map(([fetching, packages]) => fetching || packages.length > 0)
);
@ViewChild(PackageListComponent, { static: true, read: PackageListComponent })
packageList: PackageListComponent;
initialScrollIndex = 0;
constructor(
public store: PackageResultComponentStore,
private _activatedRoute: ActivatedRoute,
private _config: Config,
private _breadcrumb: BreadcrumbService,
private _router: Router,
private _cache: CacheService
) {}
ngOnInit(): void {
this.removeBreadcrumbs();
}
ngAfterViewInit(): void {
this.initFilterSubscription();
this.initFetchResponseSubscription();
}
hasUpdate(): { arrivalStatus: ArrivalStatus; packageId: string } | undefined {
const packageId = this._activatedRoute.snapshot.queryParams['updated_packageId'];
const arrivalStatus = this._activatedRoute.snapshot.queryParams['updated_arrivalStatus'];
if (!!packageId && !!arrivalStatus) {
return { arrivalStatus: Number(arrivalStatus) as ArrivalStatus, packageId: String(packageId) };
}
}
initFilterSubscription() {
const initialFilter$ = this.store.filter$.pipe(
filter((f) => f instanceof UiFilter),
first()
);
const queryParams$ = this._activatedRoute.queryParams;
const filterSub = combineLatest([initialFilter$, queryParams$]).subscribe(([filter, queryParams]) => {
const restoredFilter = this.restoreFilterFromQueryParams(filter, queryParams);
const restoredData = this.restoreResultsFromCache(restoredFilter);
this.createBreadcrumbIfNotExists(this.store.filter);
this.fetchPackages(restoredFilter, { keep: true, take: restoredData?.packages?.length });
});
this._subscription.add(filterSub);
}
initFetchResponseSubscription() {
const onFetchPackageResponseSub = this.store.onFetchPackagesResponse$.subscribe(this.onFetchPackagesResponse);
this._subscription.add(onFetchPackageResponseSub);
}
ngOnDestroy(): void {
this._subscription.unsubscribe();
}
restoreFilterFromQueryParams(filter: UiFilter, queryParams: Params): UiFilter {
const nextFilter = UiFilter.create(filter);
nextFilter.fromQueryParams(queryParams);
this.store.setFilter(nextFilter);
this.store.setPendingFilter(nextFilter);
return nextFilter;
}
restoreResultsFromCache(filter: UiFilter): PackageResultCacheData | undefined {
const data = this._cache.get<PackageResultCacheData>(filter.getQueryParams());
if (data) {
const update = this.hasUpdate();
if (update) {
const packageIndex = data.packages.findIndex((p) => p.id === update.packageId);
if (packageIndex > -1) {
data.packages[packageIndex].arrivalStatus = update.arrivalStatus;
}
}
this.store.setPackages(data.packages);
this.store.setTotal(data.total);
this.store.setFetching(false);
if (data.scrollIndex) {
this.initialScrollIndex = data.scrollIndex;
}
}
return data;
}
applyFilter() {
this.store.applyPendingFilterToFilter();
this.fetchPackages(this.store.filter);
}
fetchPackages(filter: UiFilter, options: { keep?: boolean; take?: number } = {}) {
this.hint$.next('');
this.store.fetchPackages(options);
}
onFetchPackagesResponse = (response: ListResponseArgsOfPackageDTO2) => {
this.patchLocation(this.store.filter);
this.createBreadcrumbIfNotExists(this.store.filter);
if (response.error) {
console.error(response);
return;
}
if (response.result.length === 0) {
this.hint$.next('Keine Pakete gefunden');
return;
}
this.cacheData({});
this.closeFilterOverlay();
};
openFilter() {
this.store.cancelFetchPackages();
this.filterOverlay.open();
}
resetFilter() {
this.store.resetPendingFilter();
this.store.cancelFetchPackages();
}
async patchLocation(filter: UiFilter): Promise<void> {
this._router.navigate([], {
queryParams: filter.getQueryParams(),
});
}
getBreadcrumbName(filter: UiFilter): string {
const params = filter.getQueryParams();
const mainQs = params['main_qs'];
let name: string[] = [];
if (mainQs) {
name.push(mainQs);
}
const filterLieferant = params['filter_lieferant'];
if (filterLieferant) {
name.push(filterLieferant.split(';').join(' & '));
}
if (name.length > 0) {
return name.join(' - ');
}
const filterZeitraum = params['filter_zeitraum'];
if (filterZeitraum) {
const range = filterZeitraum.split('"-"').map((s) => s.replace('"', ''));
if (range[0] && range[1]) {
const start = moment(range[0]).format('DD.MM.YYYY');
const end = moment(range[1]).format('DD.MM.YYYY');
return `${start} - ${end}`;
} else if (filterZeitraum.endsWith('"-')) {
const dateString = filterZeitraum.replace('"-', '').replace('"', '');
return `Ab ${moment(dateString).format('DD.MM.YYYY')}`;
} else if (filterZeitraum.startsWith('-"')) {
const dateString = filterZeitraum.replace('-"', '').replace('"', '');
return `Bis ${moment(dateString).format('DD.MM.YYYY')}`;
}
}
return 'Paket-Übersicht';
}
async createBreadcrumbIfNotExists(filter: UiFilter): Promise<void> {
const crumb: Breadcrumb = {
key: this.breadcrumbKey,
name: this.getBreadcrumbName(filter),
path: '/filiale/package-inspection',
section: 'branch',
params: filter.getQueryParams(),
tags: ['filter'],
};
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists(crumb);
}
async removeBreadcrumbs(): Promise<void> {
const detailsCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTag$(this.breadcrumbKey, 'details').pipe(first()).toPromise();
const filterCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTag$(this.breadcrumbKey, 'filter').pipe(first()).toPromise();
const crumbs = [...detailsCrumbs, ...filterCrumbs];
for (let crumb of crumbs) {
await this._breadcrumb.removeBreadcrumb(crumb.id);
}
}
closeFilterOverlay() {
this.store.restorePendingFilter();
this.filterOverlay.close();
}
allItemsRendered() {
this.store.paginatePackages();
}
scrollIndexChange($event: number) {
this.cacheData({ scrollIndex: $event });
}
cacheData(partial: Partial<PackageResultCacheData>) {
this._cache.set(this.store.filter.getQueryParams(), {
packages: this.store.packages,
total: this.store.total,
...partial,
} as PackageResultCacheData);
}
}