red-ui/apps/red-ui/src/app/modules/dossier-overview/screen/dossier-overview-screen.component.ts
2022-03-15 16:17:30 +02:00

243 lines
9.8 KiB
TypeScript

import {
ChangeDetectionStrategy,
Component,
ElementRef,
forwardRef,
HostListener,
Injector,
OnDestroy,
OnInit,
TemplateRef,
ViewChild,
} from '@angular/core';
import { Dossier, DossierAttributeWithValue, File, IFileAttributeConfig, WorkflowFileStatus } from '@red/domain';
import { FileDropOverlayService } from '@upload-download/services/file-drop-overlay.service';
import { FileUploadModel } from '@upload-download/model/file-upload.model';
import { FileUploadService } from '@upload-download/services/file-upload.service';
import { StatusOverlayService } from '@upload-download/services/status-overlay.service';
import { Observable } from 'rxjs';
import { filter, skip, switchMap, tap } from 'rxjs/operators';
import { convertFiles, Files, handleFileDrop } from '@utils/index';
import {
CircleButtonTypes,
CustomError,
DefaultListingServices,
ErrorService,
ListingComponent,
ListingModes,
LoadingService,
NestedFilter,
OnAttach,
TableColumnConfig,
TableComponent,
WorkflowConfig,
} from '@iqser/common-ui';
import { DossierAttributesService } from '@shared/services/controller-wrappers/dossier-attributes.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { PermissionsService } from '@services/permissions.service';
import { ActivatedRoute, Router } from '@angular/router';
import { FileAttributesService } from '@services/entity-services/file-attributes.service';
import { ConfigService } from '../config.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { UserPreferenceService } from '@services/user-preference.service';
import { FilesMapService } from '@services/entity-services/files-map.service';
import { FilesService } from '@services/entity-services/files.service';
import { DOSSIER_ID } from '@utils/constants';
import { BulkActionsService } from '../services/bulk-actions.service';
import { DossiersService } from '@services/dossiers/dossiers.service';
import { dossiersServiceProvider } from '@services/entity-services/dossiers.service.provider';
@Component({
templateUrl: './dossier-overview-screen.component.html',
styleUrls: ['./dossier-overview-screen.component.scss'],
providers: [
...DefaultListingServices,
ConfigService,
BulkActionsService,
{ provide: ListingComponent, useExisting: forwardRef(() => DossierOverviewScreenComponent) },
dossiersServiceProvider,
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DossierOverviewScreenComponent extends ListingComponent<File> implements OnInit, OnDestroy, OnAttach {
readonly listingModes = ListingModes;
readonly circleButtonTypes = CircleButtonTypes;
readonly tableHeaderLabel = _('dossier-overview.table-header.title');
collapsedDetails = false;
dossierAttributes: DossierAttributeWithValue[] = [];
tableColumnConfigs: readonly TableColumnConfig<File>[];
displayedInFileListAttributes: IFileAttributeConfig[] = [];
displayedAttributes: IFileAttributeConfig[] = [];
readonly workflowConfig: WorkflowConfig<File, WorkflowFileStatus> = this.configService.workflowConfig;
readonly dossier$: Observable<Dossier>;
readonly dossierId: string;
currentDossier: Dossier;
dossierTemplateId: string;
@ViewChild('needsWorkFilterTemplate', { read: TemplateRef, static: true })
private readonly _needsWorkFilterTemplate: TemplateRef<unknown>;
@ViewChild('fileInput', { static: true }) private readonly _fileInput: ElementRef;
@ViewChild(TableComponent) private readonly _tableComponent: TableComponent<Dossier>;
private _fileAttributeConfigs: IFileAttributeConfig[];
constructor(
protected readonly _injector: Injector,
private readonly _router: Router,
private readonly _dossiersService: DossiersService,
private readonly _loadingService: LoadingService,
private readonly _dossierTemplatesService: DossierTemplatesService,
private readonly _fileUploadService: FileUploadService,
private readonly _filesService: FilesService,
private readonly _statusOverlayService: StatusOverlayService,
private readonly _fileDropOverlayService: FileDropOverlayService,
private readonly _dossierAttributesService: DossierAttributesService,
private readonly _fileAttributesService: FileAttributesService,
private readonly _userPreferenceService: UserPreferenceService,
private readonly _fileMapService: FilesMapService,
private readonly _errorService: ErrorService,
private readonly _route: ActivatedRoute,
readonly permissionsService: PermissionsService,
readonly configService: ConfigService,
) {
super(_injector);
this.dossierId = _route.snapshot.paramMap.get(DOSSIER_ID);
this.dossier$ = this._dossiersService
.getEntityChanged$(this.dossierId)
.pipe(tap(dossier => (this.dossierTemplateId = dossier.dossierTemplateId)));
this.currentDossier = this._dossiersService.find(this.dossierId);
this._updateFileAttributes();
}
get checkedRequiredFilters(): NestedFilter[] {
return this.filterService.getGroup('quickFilters')?.filters.filter(f => f.required && f.checked);
}
get checkedNotRequiredFilters(): NestedFilter[] {
return this.filterService.getGroup('quickFilters')?.filters.filter(f => !f.required && f.checked);
}
disabledFn = (file: File) => file.excluded;
lastOpenedFn = (file: File) => this._userPreferenceService.getLastOpenedFileForDossier(file.dossierId) === file.id;
async ngOnInit(): Promise<void> {
this._loadEntitiesFromState();
this._setRemovableSubscriptions();
this.addSubscription = this._fileMapService
.get$(this.dossierId)
.pipe(
tap(files => this.entitiesService.setEntities(files)),
tap(() => this._computeAllFilters()),
)
.subscribe();
if (this.currentDossier.isActive) {
this._fileDropOverlayService.initFileDropHandling(this.dossierId);
}
this.addSubscription = this.configService.listingMode$.subscribe(() => {
this._computeAllFilters();
});
this.addSubscription = this._dossiersService.dossierFileChanges$
.pipe(
filter(dossierId => dossierId === this.dossierId),
switchMap(dossierId => this._filesService.loadAll(dossierId, this._dossiersService.routerPath)),
)
.subscribe();
this.addSubscription = this._dossierTemplatesService
.getEntityChanged$(this.currentDossier.dossierTemplateId)
.pipe(
skip(1),
tap(() => {
this._updateFileAttributes();
}),
)
.subscribe();
try {
this.dossierAttributes = await this._dossierAttributesService.getWithValues(this.currentDossier);
} catch (e) {
console.log('Error from dossier overview screen: ', e);
}
this._loadingService.stop();
}
ngOnDestroy(): void {
this._fileDropOverlayService.cleanupFileDropHandling();
super.ngOnDestroy();
}
ngOnAttach() {
this._fileDropOverlayService.initFileDropHandling(this.dossierId);
this._setRemovableSubscriptions();
this._tableComponent?.scrollToLastIndex();
}
@HostListener('drop', ['$event'])
onDrop(event: DragEvent): void {
const currentDossier = this._dossiersService.find(this.dossierId);
handleFileDrop(event, currentDossier, this._uploadFiles.bind(this));
}
@HostListener('dragover', ['$event'])
onDragOver(event): void {
event.stopPropagation();
event.preventDefault();
}
async uploadFiles(files: Files): Promise<void> {
await this._uploadFiles(convertFiles(files, this.currentDossier));
(this._fileInput as any).nativeElement.value = null;
}
private _setRemovableSubscriptions(): void {
this.addActiveScreenSubscription = this._dossiersService
.getEntityDeleted$(this.dossierId)
.pipe(tap(() => this._handleDeletedDossier()))
.subscribe();
}
private _handleDeletedDossier(): void {
this._errorService.set(
new CustomError(_('error.deleted-entity.dossier.label'), _('error.deleted-entity.dossier.action'), 'iqser:expand'),
);
}
private _updateFileAttributes(): void {
this._fileAttributeConfigs =
this._fileAttributesService.getFileAttributeConfig(this.currentDossier.dossierTemplateId)?.fileAttributeConfigs || [];
this.displayedInFileListAttributes = this._fileAttributeConfigs.filter(config => config.displayedInFileList);
this.displayedAttributes = this.displayedInFileListAttributes.filter(c => c.displayedInFileList);
this.tableColumnConfigs = this.configService.tableConfig(this.displayedAttributes);
this._computeAllFilters();
}
private _loadEntitiesFromState() {
this.currentDossier = this._dossiersService.find(this.dossierId);
this._computeAllFilters();
}
private async _uploadFiles(files: FileUploadModel[]) {
const fileCount = await this._fileUploadService.uploadFiles(files, this.dossierId);
if (fileCount) {
this._statusOverlayService.openUploadStatusOverlay();
}
}
private _computeAllFilters() {
const filterGroups = this.configService.filterGroups(
this.entitiesService.all,
this._fileAttributeConfigs,
this._needsWorkFilterTemplate,
() => this.checkedRequiredFilters,
() => this.checkedNotRequiredFilters,
);
this.filterService.addFilterGroups(filterGroups, true);
}
}