From 6f3db280b3031cbc8761c75d5a560a47f7a16c4a Mon Sep 17 00:00:00 2001
From: Alex ORLUC <alex.orluc@maarch.org>
Date: Fri, 17 Jan 2020 15:47:52 +0100
Subject: [PATCH] FEAT #10633 TIME 1:20 add give avis parallel + fix msg

---
 src/frontend/app/actions/actions.service.ts   |  23 ++++
 ...ontinue-avis-circuit-action.component.html |   7 +-
 .../continue-avis-circuit-action.component.ts |  36 +++--
 .../give-avis-parallel-action.component.html  |  50 +++++++
 .../give-avis-parallel-action.component.scss  | 128 ++++++++++++++++++
 .../give-avis-parallel-action.component.ts    | 102 ++++++++++++++
 .../send-avis-parallel-action.component.ts    |   2 +-
 .../send-avis-workflow-action.component.ts    |   2 +-
 src/frontend/app/app.module.ts                |   3 +
 .../app/avis/avis-workflow.component.ts       |   8 +-
 src/frontend/lang/lang-en.ts                  |   8 ++
 src/frontend/lang/lang-fr.ts                  |   8 ++
 src/frontend/lang/lang-nl.ts                  |   8 ++
 13 files changed, 366 insertions(+), 19 deletions(-)
 create mode 100644 src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.html
 create mode 100644 src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.scss
 create mode 100644 src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.ts

diff --git a/src/frontend/app/actions/actions.service.ts b/src/frontend/app/actions/actions.service.ts
index 6533b97c3f8..4ef2814ce01 100644
--- a/src/frontend/app/actions/actions.service.ts
+++ b/src/frontend/app/actions/actions.service.ts
@@ -30,6 +30,7 @@ import { ContinueVisaCircuitActionComponent } from './visa-continue-circuit-acti
 import { SendAvisWorkflowComponent } from './avis-workflow-send-action/send-avis-workflow-action.component';
 import { ContinueAvisCircuitActionComponent } from './avis-continue-circuit-action/continue-avis-circuit-action.component';
 import { SendAvisParallelComponent } from './avis-parallel-send-action/send-avis-parallel-action.component';
+import { GiveAvisParallelActionComponent } from './avis-give-parallel-action/give-avis-parallel-action.component';
 
 @Injectable()
 export class ActionsService {
@@ -798,5 +799,27 @@ export class ActionsService {
         ).subscribe();
     }
 
+    giveOpinionParallelAction(options: any = null) {
+        const dialogRef = this.dialog.open(GiveAvisParallelActionComponent, {
+            autoFocus: false,
+            disableClose: true,
+            data: this.setDatasActionToSend()
+        });
+        dialogRef.afterClosed().pipe(
+            tap((data: any) => {
+                this.unlockResourceAfterActionModal(data);
+            }),
+            filter((data: string) => data === 'success'),
+            tap((result: any) => {
+                this.endAction(result);
+            }),
+            finalize(() => this.loading = false),
+            catchError((err: any) => {
+                this.notify.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
+
     
 }
diff --git a/src/frontend/app/actions/avis-continue-circuit-action/continue-avis-circuit-action.component.html b/src/frontend/app/actions/avis-continue-circuit-action/continue-avis-circuit-action.component.html
index a53d4a66038..6a7400832c5 100644
--- a/src/frontend/app/actions/avis-continue-circuit-action/continue-avis-circuit-action.component.html
+++ b/src/frontend/app/actions/avis-continue-circuit-action/continue-avis-circuit-action.component.html
@@ -12,6 +12,11 @@
                 <b *ngIf="data.resIds.length > 1" color="primary" class="highlight">{{data.resIds.length}}
                     {{lang.elements}}</b> ?
             </div>
+            <div class="alert-message alert-message-info"
+                *ngIf="data.resIds.length == 1  && !noResourceToProcess"
+                role="alert" style="margin-top: 30px;"
+                [innerHTML]="'<b>' + ownerOpinion + '</b> '+ lang.askOpinionUser + ' :<br/><br/>' + opinionContent">
+            </div>
             <div class="alert-message alert-message-info"
                 *ngIf="data.resIds.length == 1 && appAvisWorkflow !== undefined && appAvisWorkflow.getNextAvisUser() !== ''"
                 role="alert" style="margin-top: 30px;"
@@ -39,7 +44,7 @@
                     </li>
                 </ul>
             </div>
-            <app-note-editor #noteEditor [resIds]="data.resIds"></app-note-editor>
+            <app-note-editor #noteEditor [title]="lang.addOpinion" [resIds]="data.resIds"></app-note-editor>
             <app-avis-workflow *ngIf="data.resIds.length == 1" [adminMode]="false" [resId]="data.resIds[0]"
                 #appAvisWorkflow>
             </app-avis-workflow>
diff --git a/src/frontend/app/actions/avis-continue-circuit-action/continue-avis-circuit-action.component.ts b/src/frontend/app/actions/avis-continue-circuit-action/continue-avis-circuit-action.component.ts
index 2eae3dd7b16..3dd4d2ad304 100644
--- a/src/frontend/app/actions/avis-continue-circuit-action/continue-avis-circuit-action.component.ts
+++ b/src/frontend/app/actions/avis-continue-circuit-action/continue-avis-circuit-action.component.ts
@@ -21,6 +21,9 @@ export class ContinueAvisCircuitActionComponent implements OnInit {
     resourcesWarnings: any[] = [];
     resourcesErrors: any[] = [];
 
+    ownerOpinion: string = '';
+    opinionContent: string = '';
+
     noResourceToProcess: boolean = null;
 
     @ViewChild('noteEditor', { static: true }) noteEditor: NoteEditorComponent;
@@ -33,35 +36,40 @@ export class ContinueAvisCircuitActionComponent implements OnInit {
         @Inject(MAT_DIALOG_DATA) public data: any,
         public functions: FunctionsService) { }
 
-    async ngOnInit(): Promise<void> {
-        this.loading = true;
-        await this.checkAvisCircuit();
-        this.loading = false;
+    ngOnInit() {
+        this.checkAvisCircuit();
     }
 
     checkAvisCircuit() {
+        this.loading = true;
         this.resourcesErrors = [];
         this.resourcesWarnings = [];
-
-        return new Promise((resolve, reject) => {
-            this.http.post('../../rest/resourcesList/users/' + this.data.userId + '/groups/' + this.data.groupId + '/baskets/' + this.data.basketId + '/actions/' + this.data.action.id + '/checkContinueOpinionCircuit', { resources: this.data.resIds })
-            .subscribe((data: any) => {
+        this.http.post('../../rest/resourcesList/users/' + this.data.userId + '/groups/' + this.data.groupId + '/baskets/' + this.data.basketId + '/actions/' + this.data.action.id + '/checkContinueOpinionCircuit', { resources: this.data.resIds }).pipe(
+            tap((data: any) => {
                 if (!this.functions.empty(data.resourcesInformations.warning)) {
                     this.resourcesWarnings = data.resourcesInformations.warning;
                 }
 
-                if(!this.functions.empty(data.resourcesInformations.error)) {
+                if (!this.functions.empty(data.resourcesInformations.error)) {
                     this.resourcesErrors = data.resourcesInformations.error;
                     this.noResourceToProcess = this.resourcesErrors.length === this.data.resIds.length;
                 }
-                resolve(true);
-            }, (err: any) => {
+
+                if (!this.noResourceToProcess) {
+                    this.ownerOpinion = data.resourcesInformations.success[0].avisUserAsk;
+                    this.opinionContent = data.resourcesInformations.success[0].note;
+                }
+            }),
+            finalize(() => this.loading = false),
+            catchError((err: any) => {
                 this.notify.handleSoftErrors(err);
-            });
-        });
+                this.dialogRef.close();
+                return of(false);
+            })
+        ).subscribe();
     }
 
-    async onSubmit() {
+    onSubmit() {
         const realResSelected: number[] = this.data.resIds.filter((resId: any) => this.resourcesErrors.map(resErr => resErr.res_id).indexOf(resId) === -1);
         this.executeAction(realResSelected);
     }
diff --git a/src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.html b/src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.html
new file mode 100644
index 00000000000..6d9816f405e
--- /dev/null
+++ b/src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.html
@@ -0,0 +1,50 @@
+<h1 mat-dialog-title>{{data.action.label}}</h1>
+<div mat-dialog-content>
+    <div *ngIf="loading" class="loading" style="display:flex;height:100%;">
+        <mat-spinner style="margin:auto;"></mat-spinner>
+    </div>
+    <mat-sidenav-container autosize style="height:100%;">
+        <mat-sidenav-content style="background: white;padding:10px;">
+            <div>
+                {{lang.makeActionOn}}
+                <b *ngIf="data.resIds.length === 0" color="primary" class="highlight">{{lang.currentIndexingMail}}</b>
+                <b *ngIf="data.resIds.length == 1" color="primary" class="highlight">{{data.resource.chrono}}</b>
+                <b *ngIf="data.resIds.length > 1" color="primary" class="highlight">{{data.resIds.length}}
+                    {{lang.elements}}</b> ?
+            </div>
+            <div class="alert-message alert-message-info"
+                *ngIf="data.resIds.length == 1  && !noResourceToProcess"
+                role="alert" style="margin-top: 30px;"
+                [innerHTML]="'<b>' + ownerOpinion + '</b> '+ lang.askOpinionUser + ' :<br/><br/>' + opinionContent">
+            </div>
+
+            <div class="alert-message alert-message-info"
+                *ngIf="data.resIds.length > 1 && !noResourceToProcess"
+                role="alert" style="margin-top: 30px;" [innerHTML]="lang.askOpinion"></div>
+
+            <div *ngIf="resourcesErrors.length > 0" class="alert-message alert-message-danger mailList" role="alert">
+                <p>
+                    {{lang.canNotMakeAction}} :
+                </p>
+                <ul>
+                    <li *ngFor="let ressource of resourcesErrors">
+                        <b>{{ressource.alt_identifier}}</b> : {{lang[ressource.reason]}}
+                    </li>
+                </ul>
+            </div>
+            <div *ngIf="resourcesWarnings.length > 0" class="alert-message alert-message-info mailList" role="alert">
+                <ul style="margin: 0;padding-bottom: 0px;">
+                    <li *ngFor="let ressource of resourcesWarnings">
+                        <b>{{ressource.alt_identifier}}</b> : {{lang[ressource.reason]}}
+                    </li>
+                </ul>
+            </div>
+            <app-note-editor #noteEditor [title]="lang.addOpinion" [resIds]="data.resIds"></app-note-editor>
+        </mat-sidenav-content>
+    </mat-sidenav-container>
+</div>
+<div mat-dialog-actions class="actions">
+    <button mat-raised-button mat-button color="primary" [disabled]="loading || !isValidAction()"
+        (click)="onSubmit()">{{lang.validate}}</button>
+    <button mat-raised-button mat-button [disabled]="loading" [mat-dialog-close]="">{{lang.cancel}}</button>
+</div>
\ No newline at end of file
diff --git a/src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.scss b/src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.scss
new file mode 100644
index 00000000000..9424211bb4a
--- /dev/null
+++ b/src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.scss
@@ -0,0 +1,128 @@
+@import '../../../css/vars.scss';
+
+.fullHeight {
+    height: 70vh;
+}
+
+.fullWidth {
+    width: 70vw;
+}
+
+.highlight {
+    font-size: 110%;
+}
+
+.loading {
+    display: flex;
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background: #ffffffb3;
+    z-index: 2;
+    overflow: hidden;
+}
+
+.mailList {
+    ul {
+        font-size: 12px;
+        max-height: 100px;
+        overflow: auto;
+        padding-left: 25px;
+        padding-right: 5px;
+        padding-bottom: 10px;
+        margin-top: 10px;
+    }
+
+    p {
+        //font-size: 18px;
+        margin: 0;
+        text-decoration: underline;
+    }
+
+    b {
+        font-size: 120%;
+    }
+}
+
+.formType {
+    align-items: center;
+    display: flex;
+    margin: 10px;
+    border-radius: 4px;
+    border: solid 1px #ccc;
+    position: relative;
+    padding: 10px;
+
+    &-title {
+        white-space: pre;
+        overflow: hidden;
+        max-width: 85%;
+        text-overflow: ellipsis;
+        z-index: 1;
+        font-size: 10px;
+        font-weight: bold;
+        background: white;
+        position: absolute;
+        top: -7px;
+        left: 10px;
+        padding: 0px;
+        margin: 0px;
+        color: #135f7f;
+    }
+
+    ::ng-deep.mat-form-field-suffix {
+        color: $secondary;
+        font-size: 15px;
+        top: 0;
+    }
+
+    ::ng-deep.mat-form-field-wrapper {
+        padding: 0;
+    }
+}
+
+.priceContent {
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+    width: 100%;
+
+    &-label {
+        text-align: right;
+        color: $primary;
+        flex: 1;
+        justify-content: flex-end;
+        display: flex;
+        padding-right: 10px;
+    }
+
+    .mat-form-field {
+        width: 90px !important;
+
+        input {
+            font-weight: bold;
+            user-select: none;
+        }
+    }
+}
+
+.priceInfo {
+    padding-right: 20px;
+    font-size: 10px;
+    opacity: 0.5;
+    width: 100%;
+}
+
+.pjList {
+    display: flex;
+    width: 100%;
+    overflow: auto;
+    flex-direction: column;
+    background: #666;
+
+    img {
+        margin: 10px;
+    }
+}
\ No newline at end of file
diff --git a/src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.ts b/src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.ts
new file mode 100644
index 00000000000..f449a05576d
--- /dev/null
+++ b/src/frontend/app/actions/avis-give-parallel-action/give-avis-parallel-action.component.ts
@@ -0,0 +1,102 @@
+import { Component, OnInit, Inject, ViewChild } from '@angular/core';
+import { LANG } from '../../translate.component';
+import { NotificationService } from '../../notification.service';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { HttpClient } from '@angular/common/http';
+import { NoteEditorComponent } from '../../notes/note-editor.component';
+import { tap, finalize, catchError } from 'rxjs/operators';
+import { of } from 'rxjs';
+import { FunctionsService } from '../../../service/functions.service';
+
+@Component({
+    templateUrl: "give-avis-parallel-action.component.html",
+    styleUrls: ['give-avis-parallel-action.component.scss'],
+})
+export class GiveAvisParallelActionComponent implements OnInit {
+
+    lang: any = LANG;
+    loading: boolean = false;
+
+    resourcesWarnings: any[] = [];
+    resourcesErrors: any[] = [];
+
+    noResourceToProcess: boolean = null;
+
+    ownerOpinion: string = '';
+    opinionContent: string = '';
+
+    @ViewChild('noteEditor', { static: true }) noteEditor: NoteEditorComponent;
+
+    constructor(
+        public http: HttpClient,
+        private notify: NotificationService,
+        public dialogRef: MatDialogRef<GiveAvisParallelActionComponent>,
+        @Inject(MAT_DIALOG_DATA) public data: any,
+        public functions: FunctionsService) { }
+
+    ngOnInit() {
+        this.checkAvisParallel();
+    }
+
+    checkAvisParallel() {
+        this.loading = true;
+        this.resourcesErrors = [];
+        this.resourcesWarnings = [];
+
+        this.http.post('../../rest/resourcesList/users/' + this.data.userId + '/groups/' + this.data.groupId + '/baskets/' + this.data.basketId + '/actions/' + this.data.action.id + '/checkGiveParallelOpinion', { resources: this.data.resIds }).pipe(
+            tap((data: any) => {
+                if (!this.functions.empty(data.resourcesInformations.warning)) {
+                    this.resourcesWarnings = data.resourcesInformations.warning;
+                }
+
+                if (!this.functions.empty(data.resourcesInformations.error)) {
+                    this.resourcesErrors = data.resourcesInformations.error;
+                    this.noResourceToProcess = this.resourcesErrors.length === this.data.resIds.length;
+                }
+
+                if (!this.noResourceToProcess) {
+                    this.ownerOpinion = data.resourcesInformations.success[0].avisUserAsk;
+                    this.opinionContent = data.resourcesInformations.success[0].note;
+                }
+            }),
+            finalize(() => this.loading = false),
+            catchError((err: any) => {
+                this.notify.handleSoftErrors(err);
+                this.dialogRef.close();
+                return of(false);
+            })
+        ).subscribe();
+    }
+
+    onSubmit() {
+        const realResSelected: number[] = this.data.resIds.filter((resId: any) => this.resourcesErrors.map(resErr => resErr.res_id).indexOf(resId) === -1);
+        this.executeAction(realResSelected);
+    }
+
+    executeAction(realResSelected: number[]) {
+        const noteContent: string = `[${this.lang.avisUserState}] ${this.noteEditor.getNoteContent()}`;
+        this.http.put(this.data.processActionRoute, { resources: realResSelected, note: noteContent }).pipe(
+            tap((data: any) => {
+                if (!data) {
+                    this.dialogRef.close('success');
+                }
+                if (data && data.errors != null) {
+                    this.notify.error(data.errors);
+                }
+            }),
+            finalize(() => this.loading = false),
+            catchError((err: any) => {
+                this.notify.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
+
+    isValidAction() {
+        if (!this.noResourceToProcess && !this.functions.empty(this.noteEditor.getNoteContent())) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/src/frontend/app/actions/avis-parallel-send-action/send-avis-parallel-action.component.ts b/src/frontend/app/actions/avis-parallel-send-action/send-avis-parallel-action.component.ts
index d57ec93da64..978f9514b75 100644
--- a/src/frontend/app/actions/avis-parallel-send-action/send-avis-parallel-action.component.ts
+++ b/src/frontend/app/actions/avis-parallel-send-action/send-avis-parallel-action.component.ts
@@ -86,7 +86,7 @@ export class SendAvisParallelComponent implements AfterViewInit {
     }
 
     executeAction(realResSelected: number[]) {
-        const noteContent: string = `[POUR AVIS] ${this.noteEditor.getNoteContent()}`;
+        const noteContent: string = `[${this.lang.avisUserAsk.toUpperCase()}] ${this.noteEditor.getNoteContent()}`;
         this.http.put(this.data.processActionRoute, { resources: realResSelected, note: noteContent, data: { opinionLimitDate: this.functions.formatDateObjectToFrenchDateString(this.opinionLimitDate, true), opinionCircuit : this.appAvisWorkflow.getWorkflow() } }).pipe(
             tap((data: any) => {
                 if (!data) {
diff --git a/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.ts b/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.ts
index f85e842d252..695a9af27ec 100644
--- a/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.ts
+++ b/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.ts
@@ -84,7 +84,7 @@ export class SendAvisWorkflowComponent implements AfterViewInit {
     }
 
     executeAction(realResSelected: number[]) {
-        const noteContent: string = `[POUR AVIS] ${this.noteEditor.getNoteContent()}`;
+        const noteContent: string = `[${this.lang.avisUserAsk.toUpperCase()}] ${this.noteEditor.getNoteContent()}`;
         this.http.put(this.data.processActionRoute, { resources: realResSelected, note: noteContent, data: { opinionLimitDate: this.functions.formatDateObjectToFrenchDateString(this.opinionLimitDate, true) } }).pipe(
             tap((data: any) => {
                 if (!data) {
diff --git a/src/frontend/app/app.module.ts b/src/frontend/app/app.module.ts
index 6b40043d2e0..d36e56761c2 100755
--- a/src/frontend/app/app.module.ts
+++ b/src/frontend/app/app.module.ts
@@ -62,6 +62,7 @@ import { ContinueVisaCircuitActionComponent }               from './actions/visa
 import { ContinueAvisCircuitActionComponent }               from './actions/avis-continue-circuit-action/continue-avis-circuit-action.component';
 import { SendAvisWorkflowComponent }               from './actions/avis-workflow-send-action/send-avis-workflow-action.component';
 import { SendAvisParallelComponent }               from './actions/avis-parallel-send-action/send-avis-parallel-action.component';
+import { GiveAvisParallelActionComponent }               from './actions/avis-give-parallel-action/give-avis-parallel-action.component';
 
 import { FiltersListComponent }                 from './list/filters/filters-list.component';
 import { FiltersToolComponent }                 from './list/filters/filters-tool.component';
@@ -159,6 +160,7 @@ import { AddAvisModelModalComponent } from './avis/addAvisModel/add-avis-model-m
         ContinueAvisCircuitActionComponent,
         SendAvisWorkflowComponent,
         SendAvisParallelComponent,
+        GiveAvisParallelActionComponent,
         ActionsListComponent,
         PrintSeparatorComponent,
         FolderPinnedComponent,
@@ -212,6 +214,7 @@ import { AddAvisModelModalComponent } from './avis/addAvisModel/add-avis-model-m
         SendExternalNoteBookActionComponent,
         ContinueVisaCircuitActionComponent,
         ContinueAvisCircuitActionComponent,
+        GiveAvisParallelActionComponent,
         ProcessActionComponent,
         RedirectActionComponent,
         SendShippingActionComponent,
diff --git a/src/frontend/app/avis/avis-workflow.component.ts b/src/frontend/app/avis/avis-workflow.component.ts
index 16e0a9d928f..2238e47b7e2 100644
--- a/src/frontend/app/avis/avis-workflow.component.ts
+++ b/src/frontend/app/avis/avis-workflow.component.ts
@@ -62,12 +62,16 @@ export class AvisWorkflowComponent implements OnInit {
     ) { }
 
     ngOnInit(): void {
-        if (this.mode === 'parallel') {
+        if (this.mode === 'parallel' && this.adminMode) {
             this.loadAvisRoles();
         }
 
         if (this.resId !== null) {
-            this.loadWorkflow(this.resId);
+            if (this.mode === 'circuit') {
+                this.loadWorkflow(this.resId);
+            } else {
+                this.loadParallelWorkflow(this.resId);
+            }
         }
     }
 
diff --git a/src/frontend/lang/lang-en.ts b/src/frontend/lang/lang-en.ts
index e9e39cd12ba..3db903c5fa3 100755
--- a/src/frontend/lang/lang-en.ts
+++ b/src/frontend/lang/lang-en.ts
@@ -1423,4 +1423,12 @@ export const LANG_EN = {
     "interrupted": "Interrupted",
     "addOpinionReason": "Please fill the opinion reason",
     "opinionLimitDate": "Opinion limit date",
+    "addOpinion": "Give your opinion",
+    "askOpinion": "Several users ask your opinion",
+    "askOpinionUser": "ask your opinion",
+    "avisUserAsk": "for opinion",
+    "avisUserState": "opinion",
+    "userNotInDiffusionList": "You are not in opinion diffusion list",
+    "noOpinionLimiteDate": "The opinion limit date is not defined",
+    "noOpinionNote": "The reason is not defined",
 };
diff --git a/src/frontend/lang/lang-fr.ts b/src/frontend/lang/lang-fr.ts
index 78ddb665033..5ba65656d73 100755
--- a/src/frontend/lang/lang-fr.ts
+++ b/src/frontend/lang/lang-fr.ts
@@ -1463,4 +1463,12 @@ export const LANG_FR = {
     "interrupted": "Interrompu",
     "addOpinionReason": "Veuillez renseigner le motif de l'avis",
     "opinionLimitDate": "Date limite de l'avis",
+    "addOpinion": "Donner votre avis",
+    "askOpinion": "Des personnes vous demande votre avis",
+    "askOpinionUser": "vous demande votre avis",
+    "avisUserAsk": "pour avis",
+    "avisUserState": "avis",
+    "userNotInDiffusionList": "Vous n'êtes pas dans la liste de diffusion des avis",
+    "noOpinionLimiteDate": "La date limite de l'avis n'est pas défini",
+    "noOpinionNote": "Aucun motif défini",
 };
diff --git a/src/frontend/lang/lang-nl.ts b/src/frontend/lang/lang-nl.ts
index c6e7540e2d3..b59104669e6 100755
--- a/src/frontend/lang/lang-nl.ts
+++ b/src/frontend/lang/lang-nl.ts
@@ -1448,4 +1448,12 @@ export const LANG_NL = {
     "opinionLimitDate": "Opinion limit date", //_TO_TRANSLATE
     "visaWorkflowInterrupted" : "Interrupted workflow",//_TO_TRANSLATE
     "hasInterruptedWorkflow" : "Has interrupted the workflow",//_TO_TRANSLATE
+    "addOpinion": "Give your opinion", //_TO_TRANSLATE
+    "askOpinion": "Several users ask your opinion", //_TO_TRANSLATE
+    "askOpinionUser": "ask your opinion", //_TO_TRANSLATE
+    "avisUserAsk": "for opinion", //_TO_TRANSLATE
+    "avisUserState": "opinion", //_TO_TRANSLATE
+    "userNotInDiffusionList": "You are not in opinion diffusion list", //_TO_TRANSLATE
+    "noOpinionLimiteDate": "The opinion limit date is not defined", //_TO_TRANSLATE
+    "noOpinionNote": "The reason is not defined", //_TO_TRANSLATE
 };
-- 
GitLab