From 46d000f14c6d7e1ef8fd30b0f1e711a338666b7d Mon Sep 17 00:00:00 2001
From: "florian.azizian" <florian.azizian@maarch.org>
Date: Thu, 19 Nov 2020 18:58:45 +0100
Subject: [PATCH] FIX #11169 TIME 1:20 Display groups in user administration

---
 lang/en.json                                  |   1 +
 lang/fr.json                                  |   1 +
 src/app/user/controllers/UserController.php   |   2 +-
 .../administration/user/user.component.html   | 169 +++++++++++-------
 .../administration/user/user.component.scss   |  15 ++
 .../app/administration/user/user.component.ts |   5 +
 6 files changed, 124 insertions(+), 69 deletions(-)

diff --git a/lang/en.json b/lang/en.json
index 37174027fe..2330d42364 100755
--- a/lang/en.json
+++ b/lang/en.json
@@ -308,6 +308,7 @@
 		"passwordValid": "Password is valid",
 		"wrongCurrentPassword": "Wrong current password",
 		"alreadyUsedPassword": "The password has already been used",
+		"noAssociatedGroup": "The user does not belong to any group",
 		"homePage": "Home page"
 	}
 }
diff --git a/lang/fr.json b/lang/fr.json
index cb404a2165..73fec3d706 100755
--- a/lang/fr.json
+++ b/lang/fr.json
@@ -324,6 +324,7 @@
 		"inca_card": "Carte agent",
 		"eidas": "Eidas",
 		"rgs_2stars": "Rgs**",
+		"noAssociatedGroup": "L'utilisateur appartient à aucun groupe",
 		"docToSign": "Document à signer",
 		"attachDocToSign": "Annexe attaché au(x) document(s) à signer",
 		"titleSearch": "Sujet du document à signer",
diff --git a/src/app/user/controllers/UserController.php b/src/app/user/controllers/UserController.php
index 795463b38d..486322ef94 100755
--- a/src/app/user/controllers/UserController.php
+++ b/src/app/user/controllers/UserController.php
@@ -86,7 +86,7 @@ class UserController
         $user['groups'] = [];
 
         $userGroups = UserGroupModel::get(['select' => ['group_id'], 'where' => ['user_id = ?'], 'data' => [$args['id']]]);
-        $groupsIds = array_column($userGroups, 'group_id');
+        $groupsIds  = array_column($userGroups, 'group_id');
         if (!empty($groupsIds)) {
             $groups = GroupModel::get(['select' => ['label'], 'where' => ['id in (?)'], 'data' => [$groupsIds]]);
             $user['groups'] = $groups;
diff --git a/src/frontend/app/administration/user/user.component.html b/src/frontend/app/administration/user/user.component.html
index 01eb0d3387..044c3defd9 100644
--- a/src/frontend/app/administration/user/user.component.html
+++ b/src/frontend/app/administration/user/user.component.html
@@ -9,74 +9,107 @@
         </ion-avatar>
     </ion-toolbar>
 </ion-header>
-<form style="display: contents;" id="adminForm" (ngSubmit)="onSubmit()" #adminForm="ngForm">
+
+<ion-header>
+    <ion-toolbar>
+        <ion-segment [value]="currentTool" (ionChange)="initTab($event.detail.value)">
+            <ion-segment-button value="info">
+                <ion-label>{{'lang.informations' | translate}}</ion-label>
+                <ion-icon name="information-circle"></ion-icon>
+            </ion-segment-button>
+            <ion-segment-button value="groups">
+                <ion-label>{{'lang.manage_groups' | translate}}</ion-label>
+                <ion-icon name="people-sharp"></ion-icon>
+            </ion-segment-button>
+        </ion-segment>
+    </ion-toolbar>
+</ion-header>
+
+<ng-container *ngIf="currentTool === 'info'">
+    <form style="display: contents;" id="adminForm" (ngSubmit)="onSubmit()" #adminForm="ngForm">
+        <ion-content>
+            <ion-item>
+                <ion-label color="secondary" position="floating">{{'lang.login' | translate}} *</ion-label>
+                <ion-input name="login" [readonly]="!creationMode" [(ngModel)]="user.login" required pattern="^[\w.@-]*$">
+                </ion-input>
+            </ion-item>
+            <ion-item>
+                <ion-label color="secondary" position="floating">{{'lang.firstname' | translate}} *</ion-label>
+                <ion-input name="firstname" [(ngModel)]="user.firstname" required></ion-input>
+            </ion-item>
+            <ion-item>
+                <ion-label color="secondary" position="floating">{{'lang.lastname' | translate}} *</ion-label>
+                <ion-input name="lastname" [(ngModel)]="user.lastname" required></ion-input>
+            </ion-item>
+            <ion-item>
+                <ion-label color="secondary" position="floating">{{'lang.email' | translate}} *</ion-label>
+                <ion-input type="email" name="email" [(ngModel)]="user.email" required
+                    pattern="(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"></ion-input>
+            </ion-item>
+            <ion-item>
+                <ion-label>{{'lang.restUser' | translate}}</ion-label>
+                <ion-toggle slot="start" color="primary" [disabled]="!creationMode" name="isRest" [(ngModel)]="user.isRest"
+                    [checked]="user.isRest" (ionChange)="getPassRules($event)"></ion-toggle>
+            </ion-item>
+            <ion-list>
+                <ion-list-header>
+                    <ion-label color="secondary">{{'lang.signatureModes' | translate}}</ion-label>
+                </ion-list-header>
+                <ng-container *ngFor="let signMode of authService.signatureRoles">
+                    <ion-item *ngIf="signMode.id !=='visa'">
+                        <ion-label [style.color]="signMode.color">{{'lang.' + signMode.id | translate}}</ion-label>
+                        <ion-checkbox slot="start" [checked]="user.signatureModes.indexOf(signMode.id) > -1" (ionChange)="toggleSignMode(signMode, $event.detail.checked)" [disabled]="signMode.id === 'stamp'"></ion-checkbox>
+                    </ion-item>
+                </ng-container>
+            </ion-list>
+            <ion-item style="align-items: center;" *ngIf="user.isRest">
+                <ion-button slot="end" fill="clear" color="primary" (click)="hideNewPassword = !hideNewPassword">
+                    <ion-icon color="primary" [name]="hideNewPassword ? 'eye-outline' : 'eye-off-outline'">
+                    </ion-icon>
+                </ion-button>
+                <ion-label color="secondary" position="floating">{{'lang.newPassword' | translate}}</ion-label>
+                <ion-input [type]="hideNewPassword ? 'password' : 'text'" name="newPasswordRest"
+                    [(ngModel)]="passwordRest.newPassword" (ionChange)="checkPasswordValidity(passwordRest.newPassword)">
+                </ion-input>
+            </ion-item>
+            <ion-item style="align-items: center;" *ngIf="user.isRest">
+                <ion-button slot="end" fill="clear" color="primary"
+                    (click)="hideNewPasswordConfirm = !hideNewPasswordConfirm">
+                    <ion-icon color="primary" [name]="hideNewPasswordConfirm ? 'eye-outline' : 'eye-off-outline'">
+                    </ion-icon>
+                </ion-button>
+                <ion-label color="secondary" position="floating">{{'lang.passwordConfirmation' | translate}}</ion-label>
+                <ion-input [type]="hideNewPasswordConfirm ? 'password' : 'text'" name="passwordConfirmation"
+                    [(ngModel)]="passwordRest.passwordConfirmation"></ion-input>
+                <ion-note color="danger" *ngIf="passwordRest.passwordConfirmation !== passwordRest.newPassword">
+                    {{'lang.passwordNotMatch' | translate}}</ion-note>
+                <ion-note color="success"
+                    *ngIf="passwordRest.passwordConfirmation === passwordRest.newPassword && passwordRest.newPassword.length > 0 && passwordRest.passwordConfirmation.length> 0">
+                    {{'lang.samePassword' | translate}}</ion-note>
+            </ion-item>
+            <ion-item text-center lines="none" style="position: sticky;bottom:0px;z-index:1;">
+                <div style="display: flex;align-items: center;justify-content: center;width: 100%;background: white;">
+                    <ion-button type="submit" shape="round" size="large" fill="outline" color="primary"
+                        [disabled]="!adminForm.form.valid || !canValidate()">
+                        <ion-label style="font-size: 13px;">{{'lang.validate' | translate}}</ion-label>
+                    </ion-button>
+                </div>
+            </ion-item>
+        </ion-content>
+    </form>
+</ng-container>
+
+<ng-container *ngIf="currentTool === 'groups'">
     <ion-content>
-        <ion-item>
-            <ion-label color="secondary" position="floating">{{'lang.login' | translate}} *</ion-label>
-            <ion-input name="login" [readonly]="!creationMode" [(ngModel)]="user.login" required pattern="^[\w.@-]*$">
-            </ion-input>
-        </ion-item>
-        <ion-item>
-            <ion-label color="secondary" position="floating">{{'lang.firstname' | translate}} *</ion-label>
-            <ion-input name="firstname" [(ngModel)]="user.firstname" required></ion-input>
-        </ion-item>
-        <ion-item>
-            <ion-label color="secondary" position="floating">{{'lang.lastname' | translate}} *</ion-label>
-            <ion-input name="lastname" [(ngModel)]="user.lastname" required></ion-input>
-        </ion-item>
-        <ion-item>
-            <ion-label color="secondary" position="floating">{{'lang.email' | translate}} *</ion-label>
-            <ion-input type="email" name="email" [(ngModel)]="user.email" required
-                pattern="(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"></ion-input>
-        </ion-item>
-        <ion-item>
-            <ion-label>{{'lang.restUser' | translate}}</ion-label>
-            <ion-toggle slot="start" color="primary" [disabled]="!creationMode" name="isRest" [(ngModel)]="user.isRest"
-                [checked]="user.isRest" (ionChange)="getPassRules($event)"></ion-toggle>
-        </ion-item>
-        <ion-list>
-            <ion-list-header>
-                <ion-label color="secondary">{{'lang.signatureModes' | translate}}</ion-label>
-            </ion-list-header>
-            <ng-container *ngFor="let signMode of authService.signatureRoles">
-                <ion-item *ngIf="signMode.id !=='visa'">
-                    <ion-label [style.color]="signMode.color">{{'lang.' + signMode.id | translate}}</ion-label>
-                    <ion-checkbox slot="start" [checked]="user.signatureModes.indexOf(signMode.id) > -1" (ionChange)="toggleSignMode(signMode, $event.detail.checked)" [disabled]="signMode.id === 'stamp'"></ion-checkbox>
-                </ion-item>
-            </ng-container>
+        <ion-list *ngIf="user.groups.length > 0">
+            <ion-item *ngFor="let group of user.groups">
+                <ion-label>{{group.label}}</ion-label>
+            </ion-item>
+        </ion-list>
+        <ion-list class="no-result" *ngIf="user.groups.length === 0">
+            <ion-item lines="none">
+                <ion-label class="no-result-label" color="medium">{{'lang.noAssociatedGroup' | translate}}</ion-label>
+            </ion-item>
         </ion-list>
-        <ion-item style="align-items: center;" *ngIf="user.isRest">
-            <ion-button slot="end" fill="clear" color="primary" (click)="hideNewPassword = !hideNewPassword">
-                <ion-icon color="primary" [name]="hideNewPassword ? 'eye-outline' : 'eye-off-outline'">
-                </ion-icon>
-            </ion-button>
-            <ion-label color="secondary" position="floating">{{'lang.newPassword' | translate}}</ion-label>
-            <ion-input [type]="hideNewPassword ? 'password' : 'text'" name="newPasswordRest"
-                [(ngModel)]="passwordRest.newPassword" (ionChange)="checkPasswordValidity(passwordRest.newPassword)">
-            </ion-input>
-        </ion-item>
-        <ion-item style="align-items: center;" *ngIf="user.isRest">
-            <ion-button slot="end" fill="clear" color="primary"
-                (click)="hideNewPasswordConfirm = !hideNewPasswordConfirm">
-                <ion-icon color="primary" [name]="hideNewPasswordConfirm ? 'eye-outline' : 'eye-off-outline'">
-                </ion-icon>
-            </ion-button>
-            <ion-label color="secondary" position="floating">{{'lang.passwordConfirmation' | translate}}</ion-label>
-            <ion-input [type]="hideNewPasswordConfirm ? 'password' : 'text'" name="passwordConfirmation"
-                [(ngModel)]="passwordRest.passwordConfirmation"></ion-input>
-            <ion-note color="danger" *ngIf="passwordRest.passwordConfirmation !== passwordRest.newPassword">
-                {{'lang.passwordNotMatch' | translate}}</ion-note>
-            <ion-note color="success"
-                *ngIf="passwordRest.passwordConfirmation === passwordRest.newPassword && passwordRest.newPassword.length > 0 && passwordRest.passwordConfirmation.length> 0">
-                {{'lang.samePassword' | translate}}</ion-note>
-        </ion-item>
-        <ion-item text-center lines="none" style="position: sticky;bottom:0px;z-index:1;">
-            <div style="display: flex;align-items: center;justify-content: center;width: 100%;background: white;">
-                <ion-button type="submit" shape="round" size="large" fill="outline" color="primary"
-                    [disabled]="!adminForm.form.valid || !canValidate()">
-                    <ion-label style="font-size: 13px;">{{'lang.validate' | translate}}</ion-label>
-                </ion-button>
-            </div>
-        </ion-item>
     </ion-content>
-</form>
\ No newline at end of file
+</ng-container>
diff --git a/src/frontend/app/administration/user/user.component.scss b/src/frontend/app/administration/user/user.component.scss
index e18ad0d5c7..c655824dc5 100644
--- a/src/frontend/app/administration/user/user.component.scss
+++ b/src/frontend/app/administration/user/user.component.scss
@@ -11,3 +11,18 @@
   transition: all 0.2s;
 }
 
+.no-result {
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.no-result .item {
+  width: 100%;
+  text-align: center;
+}
+
+.no-result-label {
+  font-size: 30px;
+}
\ No newline at end of file
diff --git a/src/frontend/app/administration/user/user.component.ts b/src/frontend/app/administration/user/user.component.ts
index 2f288d5d04..f593ecd840 100644
--- a/src/frontend/app/administration/user/user.component.ts
+++ b/src/frontend/app/administration/user/user.component.ts
@@ -46,6 +46,7 @@ export class UserComponent implements OnInit {
     hideCurrentPassword: Boolean = true;
     hideNewPassword: Boolean = true;
     hideNewPasswordConfirm: Boolean = true;
+    currentTool = 'info';
 
     // HANDLE PASSWORD
     passwordRules: any = {
@@ -305,4 +306,8 @@ export class UserComponent implements OnInit {
             this.user.signatureModes = this.user.signatureModes.filter((item: any) => item !== signMode.id);
         }
     }
+
+    initTab(val: any) {
+        this.currentTool = val;
+    }
 }
-- 
GitLab