From ebc3ea82273832c7f52a1284710e543a6695fcde Mon Sep 17 00:00:00 2001
From: Alex ORLUC <alex.orluc@maarch.org>
Date: Mon, 24 Feb 2020 09:42:23 +0100
Subject: [PATCH] FEAT #13119 TIME 1:30 front printed folder

---
 src/frontend/app/app.module.ts                |   8 +-
 .../summarySheet/summary-sheet.component.html |   5 +-
 .../summarySheet/summary-sheet.component.ts   |  60 ++--
 .../printed-folder-modal.component.html       |  84 ++++++
 .../printed-folder-modal.component.scss       |  63 ++++
 .../printed-folder-modal.component.ts         | 285 ++++++++++++++++++
 .../app/process/process.component.html        |   3 +
 src/frontend/app/process/process.component.ts |   5 +
 src/frontend/lang/lang-en.ts                  |   6 +
 src/frontend/lang/lang-fr.ts                  |   6 +
 src/frontend/lang/lang-nl.ts                  |   6 +
 11 files changed, 507 insertions(+), 24 deletions(-)
 create mode 100644 src/frontend/app/printedFolder/printed-folder-modal.component.html
 create mode 100644 src/frontend/app/printedFolder/printed-folder-modal.component.scss
 create mode 100644 src/frontend/app/printedFolder/printed-folder-modal.component.ts

diff --git a/src/frontend/app/app.module.ts b/src/frontend/app/app.module.ts
index ec28b337b78..1aa75ff148f 100755
--- a/src/frontend/app/app.module.ts
+++ b/src/frontend/app/app.module.ts
@@ -34,6 +34,8 @@ import { FolderActionListComponent }                 from './folder/folder-actio
 import { FollowedDocumentListComponent }                 from './home/followed-list/followed-document-list.component';
 import { FollowedActionListComponent }                 from './home/followed-action-list/followed-action-list.component';
 
+import { PrintedFolderModalComponent }                 from './printedFolder/printed-folder-modal.component';
+
 /*ACTIONS PAGES */
 import { ConfirmActionComponent }               from './actions/confirm-action/confirm-action.component';
 import { DisabledBasketPersistenceActionComponent } from './actions/disabled-basket-persistence-action/disabled-basket-persistence-action.component';
@@ -207,7 +209,8 @@ import { SendedResourcePageComponent } from './sendedResource/sended-resource-pa
         LinkResourceModalComponent,
         DocumentViewerModalComponent,
         SendedResourceListComponent,
-        SendedResourcePageComponent
+        SendedResourcePageComponent,
+        PrintedFolderModalComponent
     ],
     entryComponents: [
         ConfirmModalComponent,
@@ -254,7 +257,8 @@ import { SendedResourcePageComponent } from './sendedResource/sended-resource-pa
         AddAvisModelModalComponent,
         LinkResourceModalComponent,
         DocumentViewerModalComponent,
-        SendedResourcePageComponent
+        SendedResourcePageComponent,
+        PrintedFolderModalComponent
     ],
     providers: [ FiltersListService, FoldersService, ActionsService, PrivilegeService ],
     bootstrap: [ AppComponent ]
diff --git a/src/frontend/app/list/summarySheet/summary-sheet.component.html b/src/frontend/app/list/summarySheet/summary-sheet.component.html
index 786caa3f710..9d60e3afd7d 100644
--- a/src/frontend/app/list/summarySheet/summary-sheet.component.html
+++ b/src/frontend/app/list/summarySheet/summary-sheet.component.html
@@ -55,14 +55,15 @@
         </div>
     </div>
 </div>
-<div *ngIf="data.selectedRes.length > 500" mat-dialog-actions class="actions">
+<div *ngIf="!functions.empty(data.selectedRes) && data.selectedRes.length > 500 && !paramMode" mat-dialog-actions class="actions">
     <span style="color: #d24747; font-style: italic">{{lang.firstSummarySheetsGenerated}}</span>
 </div>
 <div style="padding: 10px">
     <span class="alert-message alert-message-info">{{lang.arGenWithModelMessage}}</span>
 </div>
 <div mat-dialog-actions class="actions">
-    <button mat-raised-button mat-button color="primary" (click)="genSummarySheets();">{{lang.genSummarySheets}}</button>
+    <button *ngIf="paramMode" mat-raised-button mat-button color="primary" (click)="closeModalWithParams();">{{lang.validate}}</button>
+    <button *ngIf="!paramMode" mat-raised-button mat-button color="primary" (click)="genSummarySheets();">{{lang.genSummarySheets}}</button>
     <button mat-raised-button mat-button [mat-dialog-close]="">{{lang.cancel}}</button>
     <button mat-mini-fab color="primary" (click)="addCustomUnit()" style="position: absolute;right: 30px;" title="{{lang.addCustomUnit}}">
         <mat-icon fontSet="fas" fontIcon="fa-plus" style="height: auto;"></mat-icon>
diff --git a/src/frontend/app/list/summarySheet/summary-sheet.component.ts b/src/frontend/app/list/summarySheet/summary-sheet.component.ts
index 3e3b49aafe3..ecbd9d761f9 100644
--- a/src/frontend/app/list/summarySheet/summary-sheet.component.ts
+++ b/src/frontend/app/list/summarySheet/summary-sheet.component.ts
@@ -3,8 +3,9 @@ import { HttpClient } from '@angular/common/http';
 import { LANG } from '../../translate.component';
 import { NotificationService } from '../../notification.service';
 import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
-import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
 import { formatDate } from '@angular/common';
+import { FunctionsService } from '../../../service/functions.service';
 
 declare function $j(selector: any): any;
 
@@ -21,6 +22,8 @@ export class SummarySheetComponent implements OnInit {
 
     withQrcode: boolean = true;
 
+    paramMode: boolean = false;
+
     dataAvailable: any[] = [
         {
             id: 'primaryInformations',
@@ -111,9 +114,16 @@ export class SummarySheetComponent implements OnInit {
         }
     ];
 
-    constructor(public http: HttpClient, private notify: NotificationService, @Inject(MAT_DIALOG_DATA) public data: any) { }
+    constructor(
+        public http: HttpClient, 
+        private notify: NotificationService, 
+        public dialogRef: MatDialogRef<SummarySheetComponent>,
+        @Inject(MAT_DIALOG_DATA) public data: any,
+        public functions: FunctionsService) { }
 
-    ngOnInit(): void { }
+    ngOnInit(): void { 
+        this.paramMode = !this.functions.empty(this.data.paramMode);
+    }
 
     drop(event: CdkDragDrop<string[]>) {
         if (event.previousContainer === event.container) {
@@ -123,24 +133,9 @@ export class SummarySheetComponent implements OnInit {
 
     genSummarySheets() {
         this.loading = true;
-        let currElemData: any[] = [];
-
-        if (this.withQrcode) {
-            currElemData.push({
-                unit: 'qrcode',
-                label: '',
-            });
-        }
-        this.dataAvailable.forEach((element: any) => {
-            if (element.enabled) {
-                currElemData.push({
-                    unit: element.unit,
-                    label: element.label,
-                });
-            }
-        });
+        
 
-        this.http.post('../../rest/resourcesList/users/' + this.data.ownerId + '/groups/' + this.data.groupId + '/baskets/' + this.data.basketId + '/summarySheets', { units: currElemData, resources: this.data.selectedRes }, { responseType: "blob" })
+        this.http.post('../../rest/resourcesList/users/' + this.data.ownerId + '/groups/' + this.data.groupId + '/baskets/' + this.data.basketId + '/summarySheets', { units: this.formatSummarySheet(), resources: this.data.selectedRes }, { responseType: "blob" })
             .subscribe((data) => {
                 if (data.type !== 'text/html') {
                     let downloadLink = document.createElement('a');
@@ -176,6 +171,27 @@ export class SummarySheetComponent implements OnInit {
             });
     }
 
+    formatSummarySheet() {
+        let currElemData: any[] = [];
+
+        if (this.withQrcode) {
+            currElemData.push({
+                unit: 'qrcode',
+                label: '',
+            });
+        }
+        this.dataAvailable.forEach((element: any) => {
+            if (element.enabled) {
+                currElemData.push({
+                    unit: element.unit,
+                    label: element.label,
+                });
+            }
+        });
+
+        return currElemData;
+    }
+
     toggleQrcode() {
         this.withQrcode = !this.withQrcode;
     }
@@ -196,4 +212,8 @@ export class SummarySheetComponent implements OnInit {
     removeCustomUnit(i: number) {
         this.dataAvailable.splice(i, 1);
     }
+
+    closeModalWithParams() {
+        this.dialogRef.close(this.formatSummarySheet());
+    }
 }
diff --git a/src/frontend/app/printedFolder/printed-folder-modal.component.html b/src/frontend/app/printedFolder/printed-folder-modal.component.html
new file mode 100644
index 00000000000..81c642b3a8a
--- /dev/null
+++ b/src/frontend/app/printedFolder/printed-folder-modal.component.html
@@ -0,0 +1,84 @@
+<h1 mat-dialog-title>
+    <span style="flex: 1;">
+        {{lang.generateAndDownloadPrintedFolder}}
+    </span>
+    <button [title]="lang.close" mat-icon-button (click)="dialogRef.close();">
+        <mat-icon class="fa fa-times"></mat-icon>
+    </button></h1>
+<mat-dialog-content class="modal-container">
+    <div class="loading" *ngIf="loading; else loadingTemplate">
+        <mat-spinner style="margin:auto;"></mat-spinner>
+    </div>
+    <ng-template #loadingTemplate>
+        <div style="padding: 10px;">
+            <mat-slide-toggle color="primary" [(ngModel)]="summarySheet"
+                (change)="$event.checked ? openSummarySheet() : false">{{lang.attachSummarySheet}}</mat-slide-toggle>
+        </div>
+        <div style="padding: 10px;">
+            <mat-slide-toggle color="primary" [(ngModel)]="withSeparator">{{lang.generateSeparators}}</mat-slide-toggle>
+        </div>
+        <div class="printedFolderContainer">
+            <mat-expansion-panel hideToggle disabled>
+                <mat-expansion-panel-header>
+                    <mat-panel-title style="color: #135f7f;font-weight: bold;">
+                        <mat-checkbox color="primary" [(ngModel)]="mainDocument" disableRipple>{{lang.mainDocument}}
+                        </mat-checkbox>
+                    </mat-panel-title>
+                </mat-expansion-panel-header>
+            </mat-expansion-panel>
+            <ng-container *ngFor="let keyVal of printedFolderElement | keyvalue">
+                <div class="printedFolderElement" *ngIf="printedFolderElement[keyVal.key].length > 0">
+                    <mat-expansion-panel>
+                        <mat-expansion-panel-header>
+                            <mat-panel-title style="color: #135f7f;font-weight: bold;">
+                                <mat-checkbox color="primary"
+                                    (change)="$event ? toggleAllElements($event.checked, keyVal.key) : null"
+                                    [checked]="selectedPrintedFolderElement[keyVal.key].value.length > 0 && selectedPrintedFolderElement[keyVal.key].value.length === printedFolderElement[keyVal.key].length"
+                                    [indeterminate]="selectedPrintedFolderElement[keyVal.key].value.length > 0 && selectedPrintedFolderElement[keyVal.key].value.length !== printedFolderElement[keyVal.key].length"
+                                    (click)="$event.stopPropagation()" disableRipple>{{lang[keyVal.key]}}</mat-checkbox>
+                            </mat-panel-title>
+                        </mat-expansion-panel-header>
+                        <mat-selection-list [formControl]="selectedPrintedFolderElement[keyVal.key]" color="primary"
+                            class="printedFolderElement-content">
+                            <mat-list-option class="printedFolderElement-option" checkboxPosition="before"
+                                *ngFor="let element of printedFolderElement[keyVal.key]" [value]="element.id">
+                                <div class="printedFolderElement-item">
+                                    <div color="primary" style="flex:1;font-size: 80%"
+                                        *ngIf="!functions.empty(element.chrono)">
+                                        {{element.chrono}}
+                                    </div>
+                                    <div color="primary" style="flex:1;display: flex;font-size: 80%;white-space: pre;"
+                                        *ngIf="!functions.empty(element.recipients)">
+                                        {{lang.for | ucfirst}} : {{element.recipients}}
+                                    </div>
+                                    <div *ngIf="!functions.empty(element.creator)" color="primary"
+                                        style="flex:1;font-size: 80%">
+                                        {{element.creator}}
+                                    </div>
+                                    <div style="flex:2" [title]="element.label"
+                                        [innerHTML]="element.label | shorten: 150: '...'">
+                                    </div>
+                                    <div *ngIf="!functions.empty(element.type)" color="primary"
+                                        style="flex:1;font-size: 80%">
+                                        {{element.type}}
+                                    </div>
+
+                                    <div color="primary" [title]="element.creationDate | fullDate"
+                                        style="flex:1;justify-content: flex-end;display: flex;font-size: 80%;">
+                                        {{element.creationDate | timeAgo : 'full' | ucfirst}}
+                                    </div>
+                                </div>
+                            </mat-list-option>
+                        </mat-selection-list>
+                    </mat-expansion-panel>
+                </div>
+            </ng-container>
+        </div>
+    </ng-template>
+
+
+</mat-dialog-content>
+<div mat-dialog-actions class="actions">
+    <button mat-raised-button color="primary" [disabled]="isEmptySelection()"
+        (click)="onSubmit()">{{lang.validate}}</button>
+</div>
\ No newline at end of file
diff --git a/src/frontend/app/printedFolder/printed-folder-modal.component.scss b/src/frontend/app/printedFolder/printed-folder-modal.component.scss
new file mode 100644
index 00000000000..31f1fc86536
--- /dev/null
+++ b/src/frontend/app/printedFolder/printed-folder-modal.component.scss
@@ -0,0 +1,63 @@
+@import '../../css/vars.scss';
+
+.mat-dialog-title {
+    padding: 10px;
+    display: flex;
+    align-items: center;
+}
+
+.modal-container {
+    min-height: 250px;
+    height: auto;
+    padding-bottom: 5px;
+}
+
+.modal-body {
+    min-height: auto;
+}
+
+.loading {
+    display: flex;
+    height: 100%;
+    width: 100%;
+    position: absolute;
+    top: 0px;
+    left: 0px;
+}
+
+.printedFolderElement {
+
+
+    &-title {
+        position: sticky;
+        top: -10px;
+        padding: 10px;
+        font-size: 20px;
+        font-weight: bold;
+        color: $primary;
+        background: white;
+        z-index: 1;
+    }
+
+    &-option {
+        &:nth-child(2n) {
+            background: rgba($primary, .1);
+        }
+    }
+
+    &-item {
+        font-size: 14px !important;
+        align-items: center;
+        display: flex;
+    }
+}
+
+.printedFolderContainer {
+    display: grid;
+    grid-template-columns: 1fr;
+    grid-gap: 20px;
+}
+
+.mat-expansion-panel-header[aria-disabled="true"] {
+    color: initial !important;
+}
\ No newline at end of file
diff --git a/src/frontend/app/printedFolder/printed-folder-modal.component.ts b/src/frontend/app/printedFolder/printed-folder-modal.component.ts
new file mode 100644
index 00000000000..41f2ea74748
--- /dev/null
+++ b/src/frontend/app/printedFolder/printed-folder-modal.component.ts
@@ -0,0 +1,285 @@
+import { Component, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '@angular/material/dialog';
+import { LANG } from '../translate.component';
+import { HttpClient } from '@angular/common/http';
+import { NotificationService } from '../notification.service';
+import { map, tap, catchError } from 'rxjs/operators';
+import { of } from 'rxjs';
+import { FunctionsService } from '../../service/functions.service';
+import { FormControl } from '@angular/forms';
+import { SortPipe } from '../../plugins/sorting.pipe';
+import { SummarySheetComponent } from '../list/summarySheet/summary-sheet.component';
+
+
+@Component({
+    templateUrl: 'printed-folder-modal.component.html',
+    styleUrls: ['printed-folder-modal.component.scss'],
+    providers: [SortPipe]
+})
+export class PrintedFolderModalComponent {
+    loading: boolean = true;
+
+    lang: any = LANG;
+
+    document: any[] = [];
+
+    mainDocument: boolean = false;
+    summarySheet: boolean = false;
+    withSeparator: boolean = false;
+
+    printedFolderElement: any = {
+        attachments: [],
+        notes: [],
+        emails: [],
+        acknowledgementReceipts: []
+    }
+
+    selectedPrintedFolderElement: any = {};
+
+    constructor(
+        public http: HttpClient,
+        private notify: NotificationService,
+        @Inject(MAT_DIALOG_DATA) public data: any,
+        public dialogRef: MatDialogRef<PrintedFolderModalComponent>,
+        public functions: FunctionsService,
+        private sortPipe: SortPipe,
+        public dialog: MatDialog) {
+    }
+
+    async ngOnInit(): Promise<void> {
+        Object.keys(this.printedFolderElement).forEach(element => {
+            this.selectedPrintedFolderElement[element] = new FormControl({ value: [], disabled: false });
+        });
+
+        await this.getAttachments();
+        await this.getEmails();
+        await this.getAcknowledgementReceips();
+        await this.getNotes();
+
+        this.loading = false;
+    }
+
+    getAttachments() {
+        return new Promise((resolve, reject) => {
+            this.http.get("../../rest/resources/" + this.data.resId + "/attachments").pipe(
+                map((data: any) => {
+                    data.attachments = data.attachments.map((attachment: any) => {
+                        return {
+                           id: attachment.resId,
+                           label: attachment.title,
+                           chrono: !this.functions.empty(attachment.chrono) ? attachment.chrono : this.lang.undefined,
+                           type: attachment.typeLabel,
+                           creationDate: attachment.creationDate,
+                        }
+                    });
+                    return data.attachments;
+                }),
+                tap((data) => {
+                    
+                   this.printedFolderElement.attachments = this.sortPipe.transform(data, 'chrono');
+                   resolve(true);
+                }),
+                catchError((err: any) => {
+                    this.notify.handleSoftErrors(err);
+                    resolve(false);
+                    return of(false);
+                })
+            ).subscribe();
+        });
+    }
+
+    getEmails() {
+        return new Promise((resolve, reject) => {
+            this.http.get(`../../rest/resources/${this.data.resId}/emails?type=email`).pipe(
+                map((data: any) => {
+                    data.emails = data.emails.map((item: any) => {
+                        return {
+                            id: item.id,
+                            recipients: item.recipients,
+                            creationDate: item.creation_date,
+                            label: !this.functions.empty(item.object) ? item.object : `<i>${this.lang.emptySubject}<i>`,
+                        }
+                    })
+                    return data.emails;
+                }),
+                tap((data: any) => {
+                    this.printedFolderElement.emails = this.sortPipe.transform(data, 'creationDate');
+
+                    resolve(true);
+                }),
+                catchError((err: any) => {
+                    this.notify.handleSoftErrors(err);
+                    resolve(false);
+                    return of(false);
+                })
+            ).subscribe();
+        });
+    }
+
+    getNotes() {
+        return new Promise((resolve, reject) => {
+            this.http.get(`../../rest/resources/${this.data.resId}/notes`).pipe(
+                map((data: any) => {
+                    data.notes = data.notes.map((item: any) => {
+                        return {
+                            id: item.id,
+                            creator: `${item.firstname} ${item.lastname}`,
+                            creationDate: item.creation_date,
+                            label: item.value,
+                        }
+                    })
+                    return data.notes;
+                }),
+                tap((data: any) => {
+                    this.printedFolderElement.notes = this.sortPipe.transform(data, 'creationDate');
+
+                    resolve(true);
+                }),
+                catchError((err: any) => {
+                    this.notify.handleSoftErrors(err);
+                    resolve(false);
+                    return of(false);
+                })
+            ).subscribe();
+        });
+    }
+
+    getAcknowledgementReceips() {
+        return new Promise((resolve, reject) => {
+            this.http.get(`../../rest/resources/${this.data.resId}/acknowledgementReceipts?type=ar`).pipe(
+                map((data: any) => {
+                    data = data.map((item: any) => {
+                        let email;
+                        if (!this.functions.empty(item.contact.email)) {
+                            email = item.contact.email;
+                        } else {
+                            email = this.lang.contactDeleted;
+                        }
+                        let name;
+                        if (!this.functions.empty(item.contact.firstname) && !this.functions.empty(item.contact.lastname)) {
+                            name = `${item.contact.firstname} ${item.contact.lastname}`
+                        } else {
+                            name = this.lang.contactDeleted;
+                        }
+
+                        return {
+                            id: item.id,
+                            sender: false,
+                            recipients: item.format === 'html' ? email : name,
+                            creationDate: item.creationDate,
+                            label: item.format === 'html' ? this.lang.ARelectronic : this.lang.ARPaper
+                        }
+                    })
+                    return data;
+                }),
+                tap((data: any) => {
+                    this.printedFolderElement.acknowledgementReceipts = this.sortPipe.transform(data, 'creationDate');
+
+                    resolve(true);
+                }),
+                catchError((err: any) => {
+                    this.notify.handleSoftErrors(err);
+                    resolve(false);
+                    return of(false);
+                })
+            ).subscribe();
+        });
+    }
+
+    toggleAllElements(state: boolean, type: any) {
+
+        if (state) {
+            this.selectedPrintedFolderElement[type].setValue(this.printedFolderElement[type].map((item: any) => item.id));
+        } else {
+            this.selectedPrintedFolderElement[type].setValue([]);
+        }
+    }
+
+    onSubmit() {
+        this.http.post(`../../rest/resources/exportData`, this.formatPrintedFolder(), { responseType: "blob" }).pipe(
+            tap((data: any) => {
+                let downloadLink = document.createElement('a');
+                    downloadLink.href = window.URL.createObjectURL(data);
+                    let today: any;
+                    let dd: any;
+                    let mm: any;
+                    let yyyy: any;
+    
+                    today = new Date();
+                    dd = today.getDate();
+                    mm = today.getMonth() + 1;
+                    yyyy = today.getFullYear();
+    
+                    if (dd < 10) {
+                        dd = '0' + dd;
+                    }
+                    if (mm < 10) {
+                        mm = '0' + mm;
+                    }
+                    today = dd + '-' + mm + '-' + yyyy;
+                    downloadLink.setAttribute('download', "export_maarch_" + today + ".pdf");
+                    document.body.appendChild(downloadLink);
+                    downloadLink.click();
+            }),
+            catchError((err: any) => {
+                this.notify.handleSoftErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
+
+    formatPrintedFolder() {
+        let printedFolder: any = {
+            withSeparator : this.withSeparator,
+            summarySheet : this.summarySheet,
+            resources : []
+        }
+        let resource = {
+            resId : this.data.resId,
+            document : this.mainDocument,
+        };
+        Object.keys(this.printedFolderElement).forEach(element => {
+            resource[element] = this.selectedPrintedFolderElement[element].value.length === this.printedFolderElement[element].length ? 'ALL' : this.selectedPrintedFolderElement[element].value;
+        });
+
+        printedFolder.resources.push(resource);
+
+
+        return printedFolder;
+    }
+
+    openSummarySheet(): void {
+
+        const dialogRef = this.dialog.open(SummarySheetComponent, {
+            panelClass: 'summary-sheet-dialog',
+            width: '800px',
+            data: {
+                paramMode : true
+            }
+        });
+        dialogRef.afterClosed().pipe(
+            tap((data: any) => {
+                this.summarySheet = data;
+            }),
+            catchError((err: any) => {
+                this.notify.handleSoftErrors(err);
+                return of(false);
+            })
+        ).subscribe(); 
+    }
+
+    isEmptySelection() {
+        let state = true;
+        Object.keys(this.printedFolderElement).forEach(element => {
+            if (this.selectedPrintedFolderElement[element].value.length > 0) {
+                state = false;
+            }
+        });
+
+        if (this.summarySheet || this.mainDocument) {
+            state = false;
+        }
+
+        return state;
+    }
+}
diff --git a/src/frontend/app/process/process.component.html b/src/frontend/app/process/process.component.html
index 8c9980a4285..76e8f668964 100644
--- a/src/frontend/app/process/process.component.html
+++ b/src/frontend/app/process/process.component.html
@@ -25,6 +25,9 @@
             <ng-container *ngIf="currentTool === 'dashboard'">
                 <div
                     style="display: flex;align-items: center;justify-content: flex-end;margin-top: 10px;margin-bottom: -20px;">
+                    <button mat-button color="primary" [title]="lang.generateAndDownloadPrintedFolder" (click)="openPrintedFolderPrompt()">
+                        <mat-icon class="fa fa-print" style="height:auto"></mat-icon> {{lang.generateAndDownloadPrintedFolder}}
+                    </button>
                 </div>
                 <div class="banner" [style.borderColor]="currentPriorityColor">
                     <div class="title" (click)="currentTool = 'history'">
diff --git a/src/frontend/app/process/process.component.ts b/src/frontend/app/process/process.component.ts
index 499dd8c2149..3fd76636d94 100755
--- a/src/frontend/app/process/process.component.ts
+++ b/src/frontend/app/process/process.component.ts
@@ -25,6 +25,7 @@ import { VisaWorkflowComponent } from '../visa/visa-workflow.component';
 import { PrivilegeService } from '../../service/privileges.service';
 import { AvisWorkflowComponent } from '../avis/avis-workflow.component';
 import { FunctionsService } from '../../service/functions.service';
+import { PrintedFolderModalComponent } from '../printedFolder/printed-folder-modal.component';
 
 
 
@@ -714,4 +715,8 @@ export class ProcessComponent implements OnInit {
             return true;
         }
     }
+
+    openPrintedFolderPrompt() {
+        this.dialog.open(PrintedFolderModalComponent, { data: { resId: this.currentResourceInformations.resId } });
+    }
 }
diff --git a/src/frontend/lang/lang-en.ts b/src/frontend/lang/lang-en.ts
index 14975ff0731..15fc9ff66cb 100755
--- a/src/frontend/lang/lang-en.ts
+++ b/src/frontend/lang/lang-en.ts
@@ -16,6 +16,7 @@ export const LANG_EN = {
     "accountAdded"                          : "Account added",
     "accountDeleted"                        : "Account deleted",
     "acknowledgementReceipt"                : "Acknowledgement of receipt",
+    "acknowledgementReceipts"                : "Acknowledgement of receipts",
     "acknowledgementReceiptType"            : "Type of acknowledgement of receipt",
     "acknowledgementSendDate"               : "Acknowledgement send date",
     "action"                                : "Action",
@@ -330,6 +331,7 @@ export const LANG_EN = {
     "electronicTemplate"                    : "Electronic template",
     "elements"                              : "element(s)",
     "email"                                 : "Email",
+    "emails"                                : "Emails",
     "emailSendFailed"                       : "Email send failed",
     "emailSendInProgress"                   : "Sending email...",
     "emailSendSuccess"                      : "Email sent",
@@ -1559,4 +1561,8 @@ export const LANG_EN = {
     "insufficientPrivilege" : "Privilege insuffisant",
     "cannotMergeTags" : "This tag has a parent or children : impossible to merge tags",
     "mergeTagWith" : "Merge this tag with",
+    "generateAndDownloadPrintedFolder" : "Generate the printed folder",
+    "mainDocument" : "Main document",
+    "attachSummarySheet" : "Attach the summary sheet",
+    "generateSeparators" : "Generate separators for each elements", 
 };
diff --git a/src/frontend/lang/lang-fr.ts b/src/frontend/lang/lang-fr.ts
index 10c1ac88958..f2e1fad0641 100755
--- a/src/frontend/lang/lang-fr.ts
+++ b/src/frontend/lang/lang-fr.ts
@@ -20,6 +20,7 @@ export const LANG_FR = {
     "accountAdded"                          : "Compte créé",
     "accountDeleted"                        : "Compte supprimé",
     "acknowledgementReceipt"                : "Accusé de réception",
+    "acknowledgementReceipts"               : "Accusés de réception",
     "acknowledgementReceiptType"            : "Type d'accusé de réception",
     "acknowledgementSendDate"               : "Date d'envoi de l'accusé de reception",
     "action"                                : "Action",
@@ -346,6 +347,7 @@ export const LANG_FR = {
     "electronicTemplate"                    : "Modèle électronique",
     "elements"                              : "élément(s)",
     "email"                                 : "Courriel",
+    "emails"                                 : "Courriels",
     "emailSendFailed"                       : "Échec d'envoi",
     "emailSendInProgress"                   : "En cours d'envoi...",
     "emailSendSuccess"                      : "Envoi réussi",
@@ -1598,4 +1600,8 @@ export const LANG_FR = {
     "insufficientPrivilege" : "Privilège insuffisant",
     "cannotMergeTags" : "Ce mot-clé possède un parent ou des enfants : impossible de le fusionner avec un autre mot clé.",
     "mergeTagWith" : "Fusionner le mot-clé avec",
+    "generateAndDownloadPrintedFolder" : "Générer le dossier d'impression", 
+    "mainDocument" : "Document principal", 
+    "attachSummarySheet" : "Attacher la fiche de liaison", 
+    "generateSeparators" : "Générer des intercalaires entre les élements", 
 };
diff --git a/src/frontend/lang/lang-nl.ts b/src/frontend/lang/lang-nl.ts
index c4767a2e1d3..f70f7d8b5f2 100755
--- a/src/frontend/lang/lang-nl.ts
+++ b/src/frontend/lang/lang-nl.ts
@@ -11,6 +11,7 @@ export const LANG_NL = {
     "accountAdded"                          : "Account added", //_TO_TRANSLATE
     "accountDeleted"                        : "Account deleted", //_TO_TRANSLATE
     "acknowledgementReceipt"                : "Acknowledgement of receipt", //_TO_TRANSLATE
+    "acknowledgementReceipts"                : "Acknowledgement of receipts", //_TO_TRANSLATE
     "acknowledgementReceiptType"            : "Type of acknowledgement of receipt", //_TO_TRANSLATE
     "acknowledgementSendDate"               : "Acknowledgement send date", //_TO_TRANSLATE
     "action"                                : "Actie",
@@ -336,6 +337,7 @@ export const LANG_NL = {
     "electronicTemplate"                    : "Electronic template", //_TO_TRANSLATE
     "elements"                              : "element(s)", //_TO_TRANSLATE
     "email"                                 : "E-mail",
+    "emails"                                : "E-mails",
     "emailSendFailed"                       : "_TO_TRANSLATE",
     "emailSendInProgress"                   : "_TO_TRANSLATE",
     "emailSendSuccess"                      : "_TO_TRANSLATE",
@@ -1584,4 +1586,8 @@ export const LANG_NL = {
     "insufficientPrivilege" : "Privilege insuffisant", //TRANSLATE
     "cannotMergeTags" : "This tag has a parent or children : impossible to merge tags",//_TO_TRANSLATE
     "mergeTagWith" : "Merge this tag with",//_TO_TRANSLATE
+    "generateAndDownloadPrintedFolder" : "Generate the printed folder", //_TO_TRANSLATE
+    "mainDocument" : "Main document", //_TO_TRANSLATE
+    "attachSummarySheet" : "Attach the summary sheet", //_TO_TRANSLATE
+    "generateSeparators" : "Generate separators for each elements", //_TO_TRANSLATE
 };
-- 
GitLab