|  | /******************************************************************************** | 
|  | * Copyright (c) 2020 Contributors to the Eclipse Foundation | 
|  | * | 
|  | * See the NOTICE file(s) distributed with this work for additional | 
|  | * information regarding copyright ownership. | 
|  | * | 
|  | * This program and the accompanying materials are made available under the | 
|  | * terms of the Eclipse Public License 2.0 which is available at | 
|  | * http://www.eclipse.org/legal/epl-2.0 | 
|  | * | 
|  | * SPDX-License-Identifier: EPL-2.0 | 
|  | ********************************************************************************/ | 
|  |  | 
|  | import {Component, Input, OnDestroy, OnInit} from "@angular/core"; | 
|  | import {select, Store} from "@ngrx/store"; | 
|  | import {combineLatest, Subject} from "rxjs"; | 
|  | import {filter, take, takeUntil} from "rxjs/operators"; | 
|  | import {AUTO_SELECTED_TAGS, IAPIAttachmentModel} from "../../../../core/api/attachments"; | 
|  | import {startAttachmentDownloadAction} from "../../../../store/attachments/actions"; | 
|  | import {IAttachmentControlValue} from "../../../../store/attachments/model"; | 
|  | import { | 
|  | getAllStatementAttachments, | 
|  | getAttachmentControlValueSelector, | 
|  | getFilteredAttachmentTagsSelector | 
|  | } from "../../../../store/attachments/selectors"; | 
|  | import {queryParamsIdSelector} from "../../../../store/root/selectors"; | 
|  | import {filterDistinctValues} from "../../../../util/store"; | 
|  | import {getMailAttachment} from "../../../forms/attachments/util/mail-attachments.util"; | 
|  |  | 
|  | /** | 
|  | * This component displays the list of attachments saved with the statement. | 
|  | * It's split up into 3 different categories: | 
|  | * mail-text, attachments manually added to the statement and the attachments copied from the initial email. | 
|  | * | 
|  | * The attachment lists can be filtered to only show attachments with specific tags. | 
|  | * The available tags for filtering are all the used tags on the statements attachments. | 
|  | */ | 
|  |  | 
|  | @Component({ | 
|  | selector: "app-statement-details-attachments", | 
|  | templateUrl: "./statement-details-attachments.component.html", | 
|  | styleUrls: ["./statement-details-attachments.component.scss"] | 
|  | }) | 
|  | export class StatementDetailsAttachmentsComponent implements OnInit, OnDestroy { | 
|  |  | 
|  | @Input() | 
|  | public appCollapsed = false; | 
|  |  | 
|  | public allAttachments$ = this.store.pipe(select(getAllStatementAttachments)); | 
|  |  | 
|  | public allAttachments: IAttachmentControlValue[] = []; | 
|  |  | 
|  | public statementAttachments$ = this.store.pipe(select(getAttachmentControlValueSelector, {forbiddenTagIds: AUTO_SELECTED_TAGS})); | 
|  |  | 
|  | public statementAttachments: IAttachmentControlValue[] = []; | 
|  |  | 
|  | public availableTags: { label: string, id: string, isSelected: boolean }[] = []; | 
|  |  | 
|  | public tags$ = this.store.pipe(select(getFilteredAttachmentTagsSelector, {without: AUTO_SELECTED_TAGS})); | 
|  |  | 
|  | public statementId$ = this.store.pipe(select(queryParamsIdSelector)); | 
|  |  | 
|  | public mailTextAttachment: IAPIAttachmentModel; | 
|  |  | 
|  | private destroy$ = new Subject(); | 
|  |  | 
|  | public constructor(public store: Store) { | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Subscribing to the attachment observables to apply the filtering for tags when changes to the statement attachments happen. | 
|  | */ | 
|  |  | 
|  | public ngOnInit() { | 
|  | combineLatest([this.allAttachments$, this.tags$]).pipe( | 
|  | takeUntil(this.destroy$) | 
|  | ).subscribe(([attachments, tags]) => { | 
|  | const allTags = filterDistinctValues(attachments.map((attachment) => attachment.tagIds).reduce((_, x) => x.concat(_), [])); | 
|  | this.availableTags = tags.filter((_) => allTags.find((a) => a === _.id)) | 
|  | .map((_) => ({..._, isSelected: false})); | 
|  | }); | 
|  | this.statementAttachments$.pipe( | 
|  | takeUntil(this.destroy$) | 
|  | ).subscribe((attachments) => { | 
|  | this.statementAttachments = this.filterBySelectedTags(attachments); | 
|  | }); | 
|  | this.allAttachments$.pipe( | 
|  | filter((attachments) => attachments != null) | 
|  | ).subscribe(async (attachments) => { | 
|  | const mailAttachments = this.filterForEmailAttachments(attachments); | 
|  | this.mailTextAttachment = getMailAttachment(attachments); | 
|  | this.allAttachments = this.filterBySelectedTags(mailAttachments); | 
|  | }); | 
|  | } | 
|  |  | 
|  | public ngOnDestroy() { | 
|  | this.destroy$.next(); | 
|  | this.destroy$.complete(); | 
|  | } | 
|  |  | 
|  | public async toggleTag(tag, state?: boolean) { | 
|  | tag.isSelected = state != null ? state : !tag.isSelected; | 
|  | const sAttachments = await this.statementAttachments$.pipe(take(1)).toPromise(); | 
|  | this.statementAttachments = this.filterBySelectedTags(sAttachments); | 
|  | const aAttachments = await this.allAttachments$.pipe(take(1)).toPromise(); | 
|  | const mailAttachments = this.filterForEmailAttachments(aAttachments); | 
|  | this.allAttachments = this.filterBySelectedTags(mailAttachments); | 
|  | } | 
|  |  | 
|  | public filterForEmailAttachments(attachments: IAPIAttachmentModel[]) { | 
|  | return attachments.filter((attachment) => { | 
|  | return attachment.tagIds.find((_) => _ === "email") != null && | 
|  | attachment.tagIds.find((_) => _ === "email-text") == null; | 
|  | }); | 
|  | } | 
|  |  | 
|  | public deselectAllTags() { | 
|  | for (const tag of this.availableTags) { | 
|  | this.toggleTag(tag, false); | 
|  | } | 
|  | } | 
|  |  | 
|  | public async downloadAttachment(attachmentId: number) { | 
|  | const statementId = await this.statementId$.pipe(take(1)).toPromise(); | 
|  | this.store.dispatch(startAttachmentDownloadAction({statementId, attachmentId})); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Filters the input list of attachments to only return the ones that have the isSelected property set to true. | 
|  | */ | 
|  |  | 
|  | public filterBySelectedTags(attachments: IAttachmentControlValue[]) { | 
|  | return attachments.filter((attachment) => { | 
|  | const selectedTags = this.availableTags?.filter((_) => _.isSelected); | 
|  | if (selectedTags?.length === 0) { | 
|  | return true; | 
|  | } | 
|  | for (const tagId of attachment?.tagIds) { | 
|  | const tagIsSelected = this.availableTags.find((_) => _.id === tagId)?.isSelected; | 
|  | if (tagIsSelected) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | }); | 
|  | } | 
|  | } |