From 9a2741733c2f1adc68f08aa59b49ced1620dd30b Mon Sep 17 00:00:00 2001
From: Alex ORLUC <alex.orluc@maarch.org>
Date: Fri, 27 Dec 2019 18:43:53 +0100
Subject: [PATCH] FEAT #11275 TIME 1:35 contact list refactoring

---
 .../modal/contact-modal.component.html        | 28 +++---
 .../modal/contact-modal.component.scss        | 11 ++-
 .../contact/modal/contact-modal.component.ts  | 16 +++-
 .../contact-autocomplete.component.html       |  8 +-
 .../contact-autocomplete.component.scss       | 12 ---
 .../contact-autocomplete.component.ts         | 48 ++++------
 .../contact/list/contacts-list.component.html | 43 +++++----
 .../contact/list/contacts-list.component.scss |  9 +-
 .../contact/list/contacts-list.component.ts   | 87 +++++++++++++++++--
 9 files changed, 177 insertions(+), 85 deletions(-)

diff --git a/src/frontend/app/administration/contact/modal/contact-modal.component.html b/src/frontend/app/administration/contact/modal/contact-modal.component.html
index de8dca2448a..86d0fcfe53e 100644
--- a/src/frontend/app/administration/contact/modal/contact-modal.component.html
+++ b/src/frontend/app/administration/contact/modal/contact-modal.component.html
@@ -1,10 +1,18 @@
-<h1 mat-dialog-title>
-    <span style="flex: 1;">
-        {{creationMode ? lang.contactCreation : lang.contact}}
-    </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">
-    <app-contact-form [creationMode]="creationMode" [contactId]="data.contactId" (onSubmitEvent)="dialogRef.close($event)"></app-contact-form>
-</mat-dialog-content>
\ No newline at end of file
+<div [class.admin-contact]="mode === 'update'">
+    <h1 mat-dialog-title>
+        <span style="flex: 1;">
+            {{creationMode ? lang.contactCreation : lang.contact}}
+        </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">
+        <app-contact-form *ngIf="mode === 'update'" [creationMode]="creationMode" [contactId]="data.contactId"
+            (onSubmitEvent)="dialogRef.close($event)"></app-contact-form>
+        <app-contacts-list *ngIf="mode === 'read'" [contact]="contact"></app-contacts-list>
+    </mat-dialog-content>
+    <div mat-dialog-actions class="actions" *ngIf="canUpdate && mode === 'read'">
+        <button mat-raised-button mat-button color="primary"
+            (click)="mode = mode === 'read' ? 'update' : 'read'">{{lang.update}}</button>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/frontend/app/administration/contact/modal/contact-modal.component.scss b/src/frontend/app/administration/contact/modal/contact-modal.component.scss
index a3b61021e19..25a437dfdb5 100644
--- a/src/frontend/app/administration/contact/modal/contact-modal.component.scss
+++ b/src/frontend/app/administration/contact/modal/contact-modal.component.scss
@@ -5,11 +5,18 @@
     display: flex;
     align-items: center;
 }
-.modal-container{
+
+.modal-container {
     min-height: 250px;
     height: auto;
 }
 
-.modal-body{
+.modal-body {
     min-height: auto;
 }
+
+
+.admin-contact {
+    min-width: 850px;
+    max-width: 99vw;
+}
\ No newline at end of file
diff --git a/src/frontend/app/administration/contact/modal/contact-modal.component.ts b/src/frontend/app/administration/contact/modal/contact-modal.component.ts
index 5dac984cf50..e218e8593d4 100644
--- a/src/frontend/app/administration/contact/modal/contact-modal.component.ts
+++ b/src/frontend/app/administration/contact/modal/contact-modal.component.ts
@@ -2,6 +2,7 @@ import { Component, Inject } from '@angular/core';
 import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
 import { LANG } from '../../../translate.component';
 import { HttpClient } from '@angular/common/http';
+import { PrivilegeService } from '../../../../service/privileges.service';
 
 @Component({
     templateUrl: 'contact-modal.component.html',
@@ -10,14 +11,27 @@ import { HttpClient } from '@angular/common/http';
 export class ContactModalComponent {
     lang: any = LANG;
     creationMode: boolean = true;
+    canUpdate: boolean = false;
+    contact: any = null;
+    mode: 'update' | 'read' = 'read';
 
     constructor(
         public http: HttpClient,
+        private privilegeService: PrivilegeService,
         @Inject(MAT_DIALOG_DATA) public data: any,
         public dialogRef: MatDialogRef<ContactModalComponent>) {
     }
 
     ngOnInit(): void {
-        this.creationMode = this.data.contactId !== null ? false : true;
+        if (this.data.contactId !== null) {
+            this.contact = {
+                id: this.data.contactId,
+                type: this.data.contactType
+            }
+            this.creationMode = false;
+        } else {
+            this.creationMode = true;
+        }
+        this.canUpdate = this.privilegeService.hasCurrentUserPrivilege('update_contacts');
     }
 }
diff --git a/src/frontend/app/contact/autocomplete/contact-autocomplete.component.html b/src/frontend/app/contact/autocomplete/contact-autocomplete.component.html
index 6efad773fd7..e8a35770a38 100644
--- a/src/frontend/app/contact/autocomplete/contact-autocomplete.component.html
+++ b/src/frontend/app/contact/autocomplete/contact-autocomplete.component.html
@@ -57,11 +57,11 @@
                                     <p mat-line class="contact-content" [title]="option.phone"> {{option.phone}} </p>
                                 </mat-list-item>
                                 <mat-list-item class="contact-address" [title]="lang.address"
-                                    *ngIf="!empty(option.number) || !empty(option.addressStreet) || !empty(option.addressAdditional2) || !empty(option.addressPostcode) || !empty(option.addressTown) || !empty(option.addressCountry)">
+                                    *ngIf="!empty(option.addressNumber) || !empty(option.addressStreet) || !empty(option.addressAdditional2) || !empty(option.addressPostcode) || !empty(option.addressTown) || !empty(option.addressCountry)">
                                     <mat-icon mat-list-icon class="contact-group fas fa-map-marker-alt"></mat-icon>
                                     <p mat-line class="contact-content"
-                                        *ngIf="!empty(option.number) || !empty(option.addressStreet)" [title]="option.addressStreet">
-                                        {{option.number}} {{option.addressStreet}} </p>
+                                        *ngIf="!empty(option.addressNumber) || !empty(option.addressStreet)" [title]="option.addressStreet">
+                                        {{option.addressNumber}} {{option.addressStreet}} </p>
                                     <p mat-line class="contact-content" *ngIf="!empty(option.addressAdditional2)"
                                         [title]="option.addressAdditional2"> ({{option.addressAdditional2}}) </p>
                                     <p mat-line class="contact-content"
@@ -89,7 +89,7 @@
             color="default">
             <ng-container *ngIf="!loadingValues">
                 <mat-chip *ngFor="let item of controlAutocomplete.value;let i=index" class="listAutocomplete"
-                    color="default" [removable]="!controlAutocomplete.disabled" (removed)="removeItem(i)" (click)="openContact(item)" [class.locked]="!canOpenContact(item)" [disableRipple]="!canOpenContact(item)">
+                    color="default" [removable]="!controlAutocomplete.disabled" (removed)="removeItem(i)" (click)="openContact(item)">
                     <span style="display: flex;flex: 1;align-items: center;">
                         <i class="fa" [class.fa-address-card]="this.valuesToDisplay[item.id].type === 'contact'"
                             [class.fa-sitemap]="this.valuesToDisplay[item.id].type ==='entity'"
diff --git a/src/frontend/app/contact/autocomplete/contact-autocomplete.component.scss b/src/frontend/app/contact/autocomplete/contact-autocomplete.component.scss
index 3a91f95a54a..e10d5acc7fe 100644
--- a/src/frontend/app/contact/autocomplete/contact-autocomplete.component.scss
+++ b/src/frontend/app/contact/autocomplete/contact-autocomplete.component.scss
@@ -25,18 +25,6 @@
     height: auto;
 }
 
-.locked {
-    cursor: default;
-
-    &:active {
-        box-shadow: none;
-    }
-
-    &:hover::after, &:focus::after {
-        opacity: 0;
-    }
-}
-
 .itemChip {
     display: block;
     width: 95%;
diff --git a/src/frontend/app/contact/autocomplete/contact-autocomplete.component.ts b/src/frontend/app/contact/autocomplete/contact-autocomplete.component.ts
index 92784729f52..343ca0702b3 100755
--- a/src/frontend/app/contact/autocomplete/contact-autocomplete.component.ts
+++ b/src/frontend/app/contact/autocomplete/contact-autocomplete.component.ts
@@ -198,7 +198,7 @@ export class ContactAutocompleteComponent implements OnInit {
         } else {
             this.setContact(item);
         }
-        
+
     }
 
     setContact(contact: any) {
@@ -261,35 +261,23 @@ export class ContactAutocompleteComponent implements OnInit {
     }
 
     openContact(contact: any = null) {
-        if ((this.canAdd && contact === null) || this.canOpenContact(contact)) {
-            const dialogRef = this.dialog.open(ContactModalComponent, { width: '1200px', maxWidth: '100vw', data: { editMode: this.canUpdate, contactId: contact !== null ? contact.id : null } });
-
-            dialogRef.afterClosed().pipe(
-                filter((data: number) => data !== undefined),
-                tap((contactId: number) => {
-                    const contact = {
-                        type: 'contact',
-                        id: contactId
-                    };
-                    this.setFormValue(contact);
-                    this.initFormValue();
-                }),
-                catchError((err: any) => {
-                    this.notify.handleErrors(err);
-                    return of(false);
-                })
-            ).subscribe();
-        } else {
-            this.dialog.open(ContactModalComponent, { width: '1200px', maxWidth: '100vw', data: { editMode: this.canUpdate, contactId: contact !== null ? contact.id : null } });
-        }
-    }
-
-    canOpenContact(contact: any) {
-        if (this.canUpdate && contact.type === 'contact') {
-            return true;
-        } else {
-            return false;
-        }
+        const dialogRef = this.dialog.open(ContactModalComponent, { maxWidth: '100vw', panelClass: 'contact-modal-container', data: { editMode: this.canUpdate, contactId: contact !== null ? contact.id : null, contactType: contact !== null ? contact.type : null } });
+
+        dialogRef.afterClosed().pipe(
+            filter((data: number) => data !== undefined),
+            tap((contactId: number) => {
+                const contact = {
+                    type: 'contact',
+                    id: contactId
+                };
+                this.setFormValue(contact);
+                this.initFormValue();
+            }),
+            catchError((err: any) => {
+                this.notify.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();
     }
 
     empty(value: any) {
diff --git a/src/frontend/app/contact/list/contacts-list.component.html b/src/frontend/app/contact/list/contacts-list.component.html
index 2c54a730efc..dbdb6b9853f 100644
--- a/src/frontend/app/contact/list/contacts-list.component.html
+++ b/src/frontend/app/contact/list/contacts-list.component.html
@@ -7,55 +7,60 @@
     <ng-template #elseTemplate>
         <mat-card class="contact-card" *ngFor="let contact of contacts">
             <mat-card-header>
-                <div mat-card-avatar class="contact-header-image fa" [class.fa-address-card]="contact.mode === 'corporate'"
-                    [class.fa-users]="contact.mode === 'internal'" [class.fa-user]="contact.mode ==='physical'" [class.fa-sitemap]="contact.mode ==='entity'" [class.fa-user-friends]="contact.mode ==='third'"
-                    [title]="lang['contact_'+contact.mode]">
+                <div mat-card-avatar class="contact-header-image fa" [class.fa-address-card]="contact.type === 'contact'" [class.fa-users]="contact.type ==='contactGroup'"
+                    [class.fa-sitemap]="contact.type ==='entity'" [class.fa-user]="contact.type ==='user'"
+                    [title]="lang['contact_'+contact.type]">
                 </div>
-                <mat-card-title>{{contact.firstname}} {{contact.lastname}}</mat-card-title>
-                <mat-card-subtitle [title]="lang.contactsParameters_function">{{contact.function}}&nbsp;
+                <mat-card-title *ngIf="!empty(contact.firstname) || !empty(contact.lastname)" [title]="contact.firstname + ' ' + contact.lastname">{{contact.firstname}}
+                    {{contact.lastname}}</mat-card-title>
+                <mat-card-title *ngIf="empty(contact.firstname) && empty(contact.lastname)" [title]="contact.company">{{contact.company}}</mat-card-title>
+                <mat-card-subtitle [title]="contact.function" *ngIf="!empty(contact.function)">
+                    {{contact.function}}&nbsp;
                 </mat-card-subtitle>
-                <i class="contact-filling fa fa-circle" *ngIf="(contact.mode === 'physical' || contact.mode === 'corporate') && contact.filling !== ''" [style.color]="contact.filling"
-                    [title]="lang.contactsFillingRate"></i>
+                <i class="contact-filling fa fa-circle"
+                                *ngIf="contact.type === 'contact' && !empty(contact.filling)"
+                                [style.color]="contact.filling"
+                                [title]="lang.contactsFillingRate"></i>
             </mat-card-header>
             <mat-card-content>
                 <mat-list>
                     <h3 mat-subheader>{{lang.contactDetails}}</h3>
-                    <mat-list-item class="contact-item" *ngIf="contact.company !== ''">
+                    <mat-list-item class="contact-item" *ngIf="(!empty(contact.firstname) || !empty(contact.lastname)) && !empty(contact.company)">
                         <mat-icon mat-list-icon class="contact-group far fa-building"
                             [title]="lang.contactsParameters_company"></mat-icon>
                         <p mat-line class="contact-content"> {{contact.company}} </p>
                     </mat-list-item>
-                    <mat-list-item class="contact-item" *ngIf="contact.department !== ''">
+                    <mat-list-item class="contact-item" *ngIf="!empty(contact.department)">
                         <mat-icon mat-list-icon class="contact-group fa fa-sitemap"
                             [title]="lang.contactsParameters_department"></mat-icon>
                         <p mat-line class="contact-content"> {{contact.department}} </p>
-                        <p mat-line class="contact-content" *ngIf="contact.occupancy !== ''"> ({{contact.occupancy}}) </p>
+                        <p mat-line class="contact-content" *ngIf="!empty(contact.addressAdditional1)"> ({{contact.addressAdditional1}}) </p>
                     </mat-list-item>
-                    <mat-list-item class="contact-item" *ngIf="contact.email !== ''">
+                    <mat-list-item class="contact-item" *ngIf="!empty(contact.email)">
                         <mat-icon mat-list-icon class="contact-group far fa-envelope" [title]="lang.email"></mat-icon>
                         <a matLine href="mailto:{{contact.email}}" class="contact-content"> {{contact.email}} </a>
                     </mat-list-item>
-                    <mat-list-item class="contact-item" *ngIf="contact.phone !== ''">
+                    <mat-list-item class="contact-item" *ngIf="!empty(contact.phone)">
                         <mat-icon mat-list-icon class="contact-group fas fa-phone" [title]="lang.phoneNumber">
                         </mat-icon>
                         <p mat-line class="contact-content"> {{contact.phone}} </p>
                     </mat-list-item>
-                    <mat-list-item class="contact-address" (click)="goTo(contact)" [title]="lang.address" *ngIf="contact.number !== '' || contact.street !== '' || contact.complement !== '' || contact.postalCode !== '' || contact.town !== '' || contact.country !== ''">
+                    <mat-list-item class="contact-address" (click)="goTo(contact)" [title]="lang.address" *ngIf="!empty(contact.addressNumber) || !empty(contact.addressStreet) || !empty(contact.addressAdditional2) || !empty(contact.addressPostcode) || !empty(contact.addressTown) || !empty(contact.addressCountry)">
                         <mat-icon mat-list-icon class="contact-group fas fa-map-marker-alt"></mat-icon>
-                        <p mat-line class="contact-content" *ngIf="contact.number !== '' || contact.street !== ''"> {{contact.number}} {{contact.street}} </p>
-                        <p mat-line class="contact-content" *ngIf="contact.complement !== ''"> ({{contact.complement}}) </p>
-                        <p mat-line class="contact-content" *ngIf="contact.postalCode !== '' || contact.town !== ''"> {{contact.postalCode}} {{contact.town}} </p>
-                        <p mat-line class="contact-content" *ngIf="contact.country !== ''"> {{contact.country}} </p>
+                        <p mat-line class="contact-content" *ngIf="!empty(contact.addressNumber) || !empty(contact.addressStreet)"> {{contact.addressNumber}} {{contact.addressStreet}} </p>
+                        <p mat-line class="contact-content" *ngIf="!empty(contact.addressAdditional2)"> ({{contact.addressAdditional2}}) </p>
+                        <p mat-line class="contact-content" *ngIf="!empty(contact.addressPostcode) || !empty(contact.addressTown)"> {{contact.addressPostcode}} {{contact.addressTown}} </p>
+                        <p mat-line class="contact-content" *ngIf="!empty(contact.addressCountry)"> {{contact.addressCountry}} </p>
                     </mat-list-item>
                 </mat-list>
-                <mat-expansion-panel *ngIf="contact.website !== '' || contact.otherData !== ''">
+                <mat-expansion-panel *ngIf="!empty(contact.website) || !empty(contact.otherData)">
                     <mat-expansion-panel-header>
                         <mat-panel-title>
                             {{lang.othersInfos}}
                         </mat-panel-title>
                     </mat-expansion-panel-header>
                     <mat-list>
-                        <mat-list-item class="contact-item" *ngIf="contact.otherData !== ''" [title]="lang.others">
+                        <mat-list-item class="contact-item" *ngIf="!empty(contact.otherData)" [title]="lang.others">
                             <mat-icon mat-list-icon class="contact-group far fa-question-circle"></mat-icon>
                             <p mat-line class="contact-content"> {{contact.otherData}} </p>
                         </mat-list-item>
diff --git a/src/frontend/app/contact/list/contacts-list.component.scss b/src/frontend/app/contact/list/contacts-list.component.scss
index ffaf5b50213..43a12bf1c9c 100644
--- a/src/frontend/app/contact/list/contacts-list.component.scss
+++ b/src/frontend/app/contact/list/contacts-list.component.scss
@@ -17,6 +17,7 @@
 }
 
 .contact-card {
+    min-width: 350px;
     width: 100%;
     margin-top: 10px;
     margin-bottom: 10px;
@@ -32,8 +33,12 @@
 
 .mat-card-header {
     background: #F9F9F9;
-    padding-top: 16px;
-    padding-left: 16px;
+    padding: 10px;
+    padding-bottom: 5px;
+}
+
+.mat-card-title {
+    padding-right: 15px;
 }
 
 
diff --git a/src/frontend/app/contact/list/contacts-list.component.ts b/src/frontend/app/contact/list/contacts-list.component.ts
index bec92760a6c..481a99a6e75 100644
--- a/src/frontend/app/contact/list/contacts-list.component.ts
+++ b/src/frontend/app/contact/list/contacts-list.component.ts
@@ -2,7 +2,6 @@ import { Component, Input, OnInit } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
 import { LANG } from '../../translate.component';
 import { NotificationService } from '../../notification.service';
-import { MatDialog } from '@angular/material';
 import { tap, finalize, catchError } from 'rxjs/operators';
 import { of } from 'rxjs';
 
@@ -23,8 +22,20 @@ export class ContactsListComponent implements OnInit {
     /**
      * Ressource identifier to load contact List
      */
-    @Input('resId') resId: number;
-    @Input('mode') mode: 'recipients' | 'senders';
+    @Input() resId: number = null;
+
+    /**
+     * [Filter to load specific contact Type]
+     * use with @resId
+     */
+    @Input() mode: 'recipients' | 'senders' = 'recipients';
+
+    /**
+     * [Id of contact to load a specific resource]
+     * DO NOT USE with @resId
+     * ex : {id: 1, type: 'contact'}
+     */
+    @Input() contact: any = null;
 
     constructor(
         public http: HttpClient,
@@ -33,7 +44,16 @@ export class ContactsListComponent implements OnInit {
 
     ngOnInit(): void {
         this.loading = false;
-        this.http.get(`../../rest/resources/${this.resId}/contacts?type=${this.mode}`).pipe(
+
+        if (this.resId !== null) {
+            this.loadContactsOfResource(this.resId, this.mode);
+        } else if (this.contact !== null) {
+            this.loadContact(this.contact.id, this.contact.type);
+        }  
+    }
+
+    loadContactsOfResource(resId: number, mode: string) {
+        this.http.get(`../../rest/resources/${resId}/contacts?type=${mode}`).pipe(
             tap((data: any) => {
                 this.contacts = data.contacts;
             }),
@@ -45,7 +65,64 @@ export class ContactsListComponent implements OnInit {
         ).subscribe();
     }
 
+    loadContact(contactId: number, type: string) {
+        this.contacts = [];
+
+        if (type === 'contact') {
+            this.http.get('../../rest/contacts/' + contactId).pipe(
+                tap((contact: any) => {
+                    this.contacts[0] = {
+                        ...contact,
+                        type: 'contact'
+                    };
+                }),
+                finalize(() => this.loading = false),
+                catchError((err: any) => {
+                    this.notify.handleErrors(err);
+                    return of(false);
+                })
+            ).subscribe();
+        } else if (type === 'user') {
+            this.http.get('../../rest/users/' + contactId).pipe(
+                tap((data: any) => {
+                    this.contacts[0] = {
+                        type: 'user',
+                        firstname: data.firstname,
+                        lastname: data.lastname,
+                    };
+                }),
+                finalize(() => this.loading = false),
+                catchError((err: any) => {
+                    this.notify.handleErrors(err);
+                    return of(false);
+                })
+            ).subscribe();
+        } else if (type === 'entity') {
+            this.http.get('../../rest/entities/' + contactId).pipe(
+                tap((data: any) => {
+                    this.contacts[0] = {
+                        type: 'entity',
+                        lastname: data.short_label,
+                    };
+                }),
+                finalize(() => this.loading = false),
+                catchError((err: any) => {
+                    this.notify.error(err.error.errors);
+                    return of(false);
+                })
+            ).subscribe();
+        }
+    }
+
     goTo(contact: any) {
-        window.open(`https://www.google.com/maps/search/${contact.num}+${contact.street},+${contact.postalCode}+${contact.town},+${contact.country}`,'_blank')
+        window.open(`https://www.google.com/maps/search/${contact.addressNumber}+${contact.addressStreet},+${contact.addressPostcode}+${contact.addressTown},+${contact.addressCountry}`,'_blank')
+    }
+
+    empty(value: any) {
+        if (value !== null && value !== '' && value !== undefined) {
+            return false;
+        } else {
+            return true;
+        }
     }
 }
-- 
GitLab