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}} + <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}} </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