import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ViewChild, ViewChildren, QueryList, TrackByFunction, inject, } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { ApplicationService } from '@core/application'; import { BreadcrumbService } from '@core/breadcrumb'; import { Config } from '@core/config'; import { RemissionListItem } from '@domain/remission'; import { SupplierDTO } from '@generated/swagger/inventory-api'; import { Subject, combineLatest, BehaviorSubject } from 'rxjs'; import { debounceTime, first, map, shareReplay, takeUntil, withLatestFrom } from 'rxjs/operators'; import { RemissionListItemComponent } from './remission-list-item'; import { RemissionListComponentStore } from './remission-list.component-store'; import { RemissionComponentStore } from './remission.component-store'; import { ShellService } from '@shared/shell'; @Component({ selector: 'page-remission-list', templateUrl: 'remission-list.component.html', styleUrls: ['remission-list.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, providers: [RemissionComponentStore], standalone: false, }) export class RemissionListComponent implements OnInit, OnDestroy { shellService = inject(ShellService); @ViewChildren(RemissionListItemComponent) listItems: QueryList; @ViewChild('scrollContainer', { static: true }) scrollContainer: CdkVirtualScrollViewport; private _onDestroy$ = new Subject(); get processId() { return this._config.get('process.ids.remission'); } get suppliers$() { return this._remissionListStore.suppliers$; } get selectedSupplier$() { return this._remissionListStore.selectedSupplier$; } get selectedSupplierId$() { return this._remissionListStore.selectedSupplier$.pipe(map((s) => s?.id)); } get sources$() { return this._remissionListStore.sources$; } get selectedSource$() { return this._remissionListStore.selectedSource$; } get items$() { return this._remissionListStore.items$; } get requiredCapacities$() { return this._remissionListStore.requiredCapacities$; } get hits$() { return this._remissionListStore.hits$; } get fetching$() { return this._remissionListStore.fetching$; } get return$() { return this._remissionStore.return$; } get filter$() { return this._remissionListStore.filter$; } showSelectDepartmenttext$ = combineLatest([this.filter$, this.selectedSource$]).pipe( map(([filter, source]) => { if (source !== 'Abteilungsremission') { return false; } if (filter?.getQueryToken()?.filter?.abteilungen) { return false; } return true; }), ); listEmpty$ = combineLatest([this.fetching$, this.hits$]).pipe( map(([loading, hits]) => !loading && hits === 0), shareReplay(), ); get queryParams$() { return this._activatedRoute.queryParams.pipe( withLatestFrom(this._remissionListStore.filter$, this.selectedSupplierId$, this.selectedSource$), map(([params, filter, supplier, source]) => { let queryParams = params; if (filter) { queryParams = { ...filter.getQueryParams(), ...params, supplier, source }; } return queryParams; }), ); } get returnCount$() { return this._remissionStore.returnCount$; } showStartRemissionAction$ = combineLatest([this.listEmpty$, this.return$]).pipe(map(([empty, r]) => !empty && !r)); filteredSuppliers$ = combineLatest([this._remissionStore.uncompleted$, this.suppliers$, this.selectedSupplier$]).pipe( map(([uncompleted, suppliers, selectedSupplier]) => { if (!uncompleted) { return suppliers; } return suppliers.filter((supplier) => supplier?.id === selectedSupplier?.id); }), ); trackByItemId: TrackByFunction = (_, item) => item.dto.id; showScrollArrow$ = new BehaviorSubject(false); remittingItem$ = new BehaviorSubject(false); constructor( private readonly _remissionListStore: RemissionListComponentStore, private readonly _remissionStore: RemissionComponentStore, private readonly _router: Router, private readonly _activatedRoute: ActivatedRoute, private readonly _breadcrumb: BreadcrumbService, private readonly _applicationService: ApplicationService, private readonly _config: Config, ) {} ngOnInit() { this._activatedRoute.queryParams .pipe(takeUntil(this._onDestroy$), debounceTime(0)) .subscribe(async (queryParams) => { const { supplier, source } = queryParams; if (supplier) { this._remissionListStore.setSelectedSupplierId(+supplier); } if (source) { this._remissionListStore.setSelectedSource(source); } const data = await this._remissionListStore.getCachedData(); if (data.items?.length !== 0) { this._remissionListStore.setItems(data.items); this._remissionListStore.setHits(data.hits); this.scrollTop(Number(queryParams?.scroll_position ?? 0)); } await this.updateBreadcrumb(queryParams); await this.removeBreadcrumbs(); }); this._remissionListStore.filter$ .pipe(takeUntil(this._onDestroy$), withLatestFrom(this._remissionListStore.selectedSource$)) .subscribe(([_, source]) => { if (source === 'Abteilungsremission') { this._remissionListStore.loadRequiredCapacities(); } }); this._activatedRoute.params.pipe(takeUntil(this._onDestroy$)).subscribe((params) => { const id = +params.returnId; if (id) { // Remission wurde gestartet this._remissionStore.getReturn(id); } else { // Für die Anzahl der Warenbegleitscheine, wenn keine Remission gestartet wurde this._remissionStore.getReturns(false); } }); this._remissionStore.getReturnCompleted.pipe(takeUntil(this._onDestroy$)).subscribe((returnDto) => { if (returnDto) { this._remissionListStore.setSelectedSupplierId(returnDto.supplier.id); } if (!returnDto || !!returnDto.completed) { this._applicationService.patchProcessData(this._remissionListStore.processId, { active: undefined, }); this._router.navigate(['./'], { relativeTo: this._activatedRoute.parent }); } }); } async ngOnDestroy() { this._onDestroy$.next(); this._onDestroy$.complete(); if (this._remissionStore.return) { this._remissionListStore.cacheCurrentData(); const params = await this._activatedRoute.queryParams.pipe(first()).toPromise(); await this.updateBreadcrumb(params); } } async updateBreadcrumb(queryParams: Record = {}) { const scroll_position = this.scrollContainer.measureScrollOffset('top'); const returnId = this._activatedRoute?.snapshot?.params?.returnId; const packageNumber = this._activatedRoute?.snapshot?.params?.packageNumber; const crumbs = await this._breadcrumb .getBreadcrumbsByKeyAndTags$(this._remissionListStore.processId, ['remission']) .pipe(first()) .toPromise(); const params = { ...queryParams, scroll_position }; for (const crumb of crumbs) { this._breadcrumb.patchBreadcrumb(crumb.id, { params, path: `/filiale/remission/${returnId ? returnId + '/' : ''}${packageNumber ? packageNumber + '/' : ''}list`, }); } } async scrolledIndexChange(index: number) { const items = await this.items$.pipe(first()).toPromise(); const hits = await this.hits$.pipe(first()).toPromise(); if (index > 0) { this.showScrollArrow$.next(true); } else { this.showScrollArrow$.next(false); } if (items.length >= hits) { return; } if (this._activatedRoute.snapshot.fragment === 'shipping-document') { return; } if (index >= items.length - 10 && items.length - 10 > 0 && !this._remissionListStore.fetching) { this._remissionListStore.search({}); } } scrollTop(scrollPos: number) { setTimeout(() => this.scrollContainer.scrollTo({ top: scrollPos, behavior: 'smooth' }), 0); } setSupplier(supplier: SupplierDTO) { this._remissionListStore.setSupplier(supplier); } setSource(source: string) { this._remissionListStore.setSource(source); } async removeBreadcrumbs() { await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this._remissionListStore.processId, [ 'remission', 'shipping-documents', ]); await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this._remissionListStore.processId, [ 'remission', 'add-product', ]); await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this._remissionListStore.processId, ['remission', 'create']); await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this._remissionListStore.processId, [ 'remission', 'finish-shipping-document', ]); await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this._remissionListStore.processId, [ 'remission', 'finish-remission', ]); } shippingDocumentDeleted() { this._router.navigate(['/filiale', 'remission', 'list']); } }