diff --git a/src/app/contentManagement/controllers/MergeController.php b/src/app/contentManagement/controllers/MergeController.php index 7af02309898ae3001311f499c4761d5562d19ecc..98a7ba7587a40f72b0647710c5e18dd310d68010 100644 --- a/src/app/contentManagement/controllers/MergeController.php +++ b/src/app/contentManagement/controllers/MergeController.php @@ -358,8 +358,10 @@ class MergeController $person['postal_address'] = implode("\n", $postalAddress); $customFields = json_decode($person['custom_fields'], true); unset($person['custom_fields']); - foreach ($customFields as $key => $customField) { - $person["customField_{$key}"] = is_array($customField) ? implode("\n", $customField) : $customField; + if (!empty($customFields)) { + foreach ($customFields as $key => $customField) { + $person["customField_{$key}"] = is_array($customField) ? implode("\n", $customField) : $customField; + } } } elseif ($args['type'] == 'user') { $person = UserModel::getById(['id' => $args['id'], 'select' => ['firstname', 'lastname']]); diff --git a/src/frontend/app/administration/contact/list/contacts-list-administration.component.html b/src/frontend/app/administration/contact/list/contacts-list-administration.component.html index f5912981483be6def11c1a5b64e1ce0878ee3470..701996326bc1d4a164db743a899312761f589c16 100644 --- a/src/frontend/app/administration/contact/list/contacts-list-administration.component.html +++ b/src/frontend/app/administration/contact/list/contacts-list-administration.component.html @@ -55,37 +55,37 @@ </div> </div> <div style="height:90%;overflow:auto;position:absolute;width:100%;"> - <table id="contact-list" #tableContactListSort="matSort" mat-table [dataSource]="data" matSort + <mat-table id="contact-list" #tableContactListSort="matSort" [dataSource]="data" matSort matSortActive="lastname" matSortDirection="asc" style="width:100%;"> <ng-container matColumnDef="firstname"> - <th mat-header-cell *matHeaderCellDef mat-sort-header - [class.hide-for-mobile]="appService.getViewMode()">{{lang.firstname}}</th> - <td mat-cell *matCellDef="let element" [class.hide-for-mobile]="appService.getViewMode()"> - {{element.firstname}} </td> + <mat-header-cell *matHeaderCellDef mat-sort-header + [class.hide-for-mobile]="appService.getViewMode()">{{lang.firstname}}</mat-header-cell> + <mat-cell mat-cell *matCellDef="let element" [class.hide-for-mobile]="appService.getViewMode()"> + {{element.firstname}} </mat-cell> </ng-container> <ng-container matColumnDef="lastname"> - <th mat-header-cell *matHeaderCellDef mat-sort-header - [class.hide-for-mobile]="appService.getViewMode()">{{lang.lastname}}</th> - <td mat-cell *matCellDef="let element" [class.hide-for-mobile]="appService.getViewMode()"> - {{element.lastname}} </td> + <mat-header-cell *matHeaderCellDef mat-sort-header + [class.hide-for-mobile]="appService.getViewMode()">{{lang.lastname}}</mat-header-cell> + <mat-cell *matCellDef="let element" [class.hide-for-mobile]="appService.getViewMode()"> + {{element.lastname}} </mat-cell> </ng-container> <ng-container matColumnDef="company"> - <th mat-header-cell *matHeaderCellDef mat-sort-header + <mat-header-cell *matHeaderCellDef mat-sort-header [class.hide-for-mobile]="appService.getViewMode()">{{lang.contactsParameters_company}} - </th> - <td mat-cell *matCellDef="let element" [class.hide-for-mobile]="appService.getViewMode()"> - {{element.company}} </td> + </mat-header-cell> + <mat-cell *matCellDef="let element" [class.hide-for-mobile]="appService.getViewMode()"> + {{element.company}} </mat-cell> </ng-container> <ng-container matColumnDef="formatedAddress"> - <th mat-header-cell *matHeaderCellDef [class.hide-for-mobile]="appService.getViewMode()"> - {{lang.address}}</th> - <td mat-cell *matCellDef="let element" [class.hide-for-mobile]="appService.getViewMode()"> - {{element.formatedAddress}} </td> + <mat-header-cell *matHeaderCellDef style="flex: 2;" [class.hide-for-mobile]="appService.getViewMode()"> + {{lang.address}}</mat-header-cell> + <mat-cell *matCellDef="let element" style="flex: 2;" [class.hide-for-mobile]="appService.getViewMode()"> + {{element.formatedAddress}} </mat-cell> </ng-container> <ng-container matColumnDef="actions"> - <th mat-header-cell *matHeaderCellDef> - </th> - <td mat-cell *matCellDef="let element" style="text-align: right;"> + <mat-header-cell *matHeaderCellDef> + </mat-header-cell> + <mat-cell *matCellDef="let element" style="justify-content: flex-end;"> <button mat-icon-button color="primary" *ngIf="element.enabled" [title]="lang.suspend" (click)="$event.stopPropagation();toggleContact(element)"> <mat-icon class="fa fa-pause fa-2x" aria-hidden="true"></mat-icon> @@ -99,13 +99,13 @@ (click)="$event.stopPropagation();deleteContact(element)"> <mat-icon class="fa fa-trash-alt fa-2x"></mat-icon> </button> - </td> + </mat-cell> </ng-container> - <tr mat-header-row *matHeaderRowDef="displayedColumnsContact"></tr> - <tr mat-row *matRowDef="let row; columns: displayedColumnsContact;" - routerLink="/administration/contacts/list/{{row.id}}" class="rowData"> - </tr> - </table> + <mat-header-row *matHeaderRowDef="displayedColumnsContact"></mat-header-row> + <mat-row *matRowDef="let row; columns: displayedColumnsContact;" + routerLink="/administration/contacts/list/{{row.id}}" style="cursor: pointer;"> + </mat-row> + </mat-table> <div class="mat-paginator" style="min-height:48px;min-height: 48px;display: flex;justify-content: end;align-items: center;padding-right: 20px;"> {{resultsLength}} {{lang.contacts}}</div> diff --git a/src/frontend/app/administration/contact/list/contacts-list-administration.component.scss b/src/frontend/app/administration/contact/list/contacts-list-administration.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..a0f97e20a77c28b6cbf5428f8e8fe2cfd8d67e1f --- /dev/null +++ b/src/frontend/app/administration/contact/list/contacts-list-administration.component.scss @@ -0,0 +1,8 @@ +@import '../../../../css/vars.scss'; + +.paginatorResultList { + ::ng-deep.mat-paginator-range-label { + justify-content: flex-end; + display: flex; + } +} diff --git a/src/frontend/app/administration/contact/list/contacts-list-administration.component.ts b/src/frontend/app/administration/contact/list/contacts-list-administration.component.ts index 9b3ae9e7727951a07850bf61d457a155b54e96e7..dfd23092576ef3938fd35d2eb441f43ec3779868 100644 --- a/src/frontend/app/administration/contact/list/contacts-list-administration.component.ts +++ b/src/frontend/app/administration/contact/list/contacts-list-administration.component.ts @@ -14,6 +14,7 @@ import { FormControl } from '@angular/forms'; @Component({ selector: 'contact-list', templateUrl: "contacts-list-administration.component.html", + styleUrls: ['contacts-list-administration.component.scss'], providers: [NotificationService, AppService] }) export class ContactsListAdministrationComponent implements OnInit { diff --git a/src/frontend/app/administration/contact/page/contacts-page-administration.component.html b/src/frontend/app/administration/contact/page/contacts-page-administration.component.html index ccad6029e8b8bd98fb3c9e9f9b4dba95541a7ceb..2f064793cecea4b6f8c29d22965daa1e0f947162 100644 --- a/src/frontend/app/administration/contact/page/contacts-page-administration.component.html +++ b/src/frontend/app/administration/contact/page/contacts-page-administration.component.html @@ -42,7 +42,8 @@ </mat-menu> <mat-menu #mainInfo="matMenu"> - <button mat-menu-item (click)="toogleAllFieldsUnit('mainInfo')" style="text-align: center;">{{lang.addAll}}</button> + <button mat-menu-item (click)="toogleAllFieldsUnit('mainInfo')" + style="text-align: center;">{{lang.addAll}}</button> <mat-divider></mat-divider> <ng-container *ngFor="let field of contactForm"> <button mat-menu-item *ngIf="!field.default && field.unit === 'mainInfo'" @@ -51,7 +52,8 @@ </mat-menu> <mat-menu #address="matMenu"> - <button mat-menu-item (click)="toogleAllFieldsUnit('address')" style="text-align: center;">{{lang.addAll}}</button> + <button mat-menu-item (click)="toogleAllFieldsUnit('address')" + style="text-align: center;">{{lang.addAll}}</button> <mat-divider></mat-divider> <ng-container *ngFor="let field of contactForm"> <button mat-menu-item *ngIf="!field.default && field.unit === 'address'" @@ -59,7 +61,8 @@ </ng-container> </mat-menu> <mat-menu #complement="matMenu"> - <button mat-menu-item (click)="toogleAllFieldsUnit('complement')" style="text-align: center;">{{lang.addAll}}</button> + <button mat-menu-item (click)="toogleAllFieldsUnit('complement')" + style="text-align: center;">{{lang.addAll}}</button> <mat-divider></mat-divider> <ng-container *ngFor="let field of contactForm"> <button mat-menu-item *ngIf="!field.default && field.unit === 'complement'" @@ -85,20 +88,23 @@ [required]="field.required"> <mat-hint *ngIf="companyFound !== null && field.id === 'company'" - align="end">Société <b>{{companyFound.company}}</b> trouvée + align="end">{{lang.company}} <b>{{companyFound.company}}</b> + {{lang.found}} ! cliquez <a (click)="setAddress(companyFound)" - style="cursor: pointer;">ici</a> pour copier son - adresse</mat-hint> + style="cursor: pointer;font-weight:bold;">{{lang.here}}</a> + {{lang.toCopyAddress}}</mat-hint> <mat-error *ngIf="field.control.hasError('required')"> {{lang.requiredField}}</mat-error> </mat-form-field> </ng-container> <ng-container *ngIf="field.type === 'integer'"> <mat-form-field> - <input type="number" matInput [formControl]="field.control" + <input type="text" matInput [formControl]="field.control" [placeholder]="field.label" min="0" step="0.1" [required]="field.required"> + <mat-error *ngIf="field.control.status!=='VALID'"> + {{lang.onlyNumber}}</mat-error> </mat-form-field> </ng-container> <ng-container *ngIf="field.type === 'select'"> @@ -114,8 +120,7 @@ </mat-label> <input [formControl]="field.control" matInput [matDatepicker]="picker" [placeholder]="field.label" - readonly style="cursor:pointer;" - (dateChange)="launchEvent($event, field)"> + readonly style="cursor:pointer;"> <mat-datepicker-toggle matSuffix [for]="picker" *ngIf="!field.control.value"> </mat-datepicker-toggle> @@ -143,7 +148,8 @@ <mat-selection-list #shoes class="checkbox-form" [formControl]="field.control"> <mat-list-option *ngFor="let value of field.values" - [value]="value.id" color="primary" checkboxPosition="before"> + [value]="value.id" color="primary" + checkboxPosition="before"> {{value.label}} </mat-list-option> </mat-selection-list> @@ -154,12 +160,29 @@ <mat-icon class="fa fa-trash"></mat-icon> </button> </mat-list-item> + <ng-container + *ngIf="unit.id === 'address' && addressBANMode && ['addressAdditional1', 'addressAdditional2'].indexOf(field.id) > -1"> + <mat-list-item class="contact-item"> + <p mat-line class="contact-content" *ngIf="field.default"> + <mat-form-field> + <input matInput [formControl]="field.control" + [placeholder]="field.label" [required]="field.required"> + <mat-error *ngIf="field.control.hasError('required')"> + {{lang.requiredField}}</mat-error> + </mat-form-field> + </p> + <button *ngIf="field.default && canDelete(field)" mat-icon-button + matSuffix color="warn" (click)="field.default = !field.default"> + <mat-icon class="fa fa-trash"></mat-icon> + </button> + </mat-list-item> + </ng-container> <ng-container *ngIf="unit.id === 'address' && addressBANMode && i === 0"> <mat-list-item> <p mat-line class="contact-content"> <mat-form-field appearance='outline' class="smallInput"> <button mat-button matSuffix [matMenuTriggerFor]="menuDep" - (click)="$event.stopPropagation();initBanSearch()" + (click)="$event.stopPropagation();" [title]="lang.targetDepartment"> {{addressBANCurrentDepartment}} <i class="fa fa-chevron-down"></i> @@ -186,7 +209,7 @@ </mat-option> </ng-container> <mat-option class="autoCompleteInfoResult smallInputInfo" - *ngIf="addressBANResult.length === 0 && !loading" + *ngIf="addressBANResult.length === 0 && !addressBANLoading" disabled [innerHTML]="addressBANInfo"> </mat-option> <mat-option *ngIf="addressBANLoading" disabled> @@ -220,7 +243,8 @@ </ng-container> </div> <div style="text-align:center;"> - <button mat-raised-button color="default" type="button" [matMenuTriggerFor]="menu">{{lang.moreInfos}}...</button> + <button mat-raised-button color="default" type="button" + [matMenuTriggerFor]="menu">{{lang.moreInfos}}...</button> <button mat-raised-button color="primary" type="button" (click)="onSubmit()">{{lang.validate}}</button> diff --git a/src/frontend/app/administration/contact/page/contacts-page-administration.component.ts b/src/frontend/app/administration/contact/page/contacts-page-administration.component.ts index 9666d2ad3669230eed082567ea5ddae4ca54ecd9..8d29327087b5ca0b06b61b15899bf0d6b4cb1300 100644 --- a/src/frontend/app/administration/contact/page/contacts-page-administration.component.ts +++ b/src/frontend/app/administration/contact/page/contacts-page-administration.component.ts @@ -9,7 +9,7 @@ import { Observable, merge, Subject, of as observableOf, of } from 'rxjs'; import { MatPaginator, MatSort, MatDialog } from '@angular/material'; import { takeUntil, startWith, switchMap, map, catchError, filter, exhaustMap, tap, debounceTime, distinctUntilChanged, finalize } from 'rxjs/operators'; import { ConfirmComponent } from '../../../../plugins/modal/confirm.component'; -import { FormControl, Validators, ValidatorFn, AbstractControl } from '@angular/forms'; +import { FormControl, Validators, ValidatorFn } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; @Component({ @@ -228,6 +228,8 @@ export class ContactsPageAdministrationComponent implements OnInit { ngOnInit(): void { this.loading = true; + + this.initBanSearch(); this.route.params.subscribe((params: any) => { if (typeof params['id'] == "undefined") { @@ -259,7 +261,6 @@ export class ContactsPageAdministrationComponent implements OnInit { this.headerService.setHeader(this.lang.contactModification); this.creationMode = false; - this.addressBANMode = false; this.contactForm.forEach(element => { element.default = false; @@ -311,19 +312,29 @@ export class ContactsPageAdministrationComponent implements OnInit { } initCustomElementForm(data: any) { + let valArr: ValidatorFn[] = []; + + let field: any = {}; + data.customFields.forEach((element: any) => { - this.contactForm.push( - { - id: `customField_${element.id}`, - unit: 'complement', - label: element.label, - type: element.type, - control: new FormControl({ value: '', disabled: false }), - required: false, - default: false, - values: element.values.map((val: any) => { return { id: val, label: val } }) - } - ); + valArr = []; + + field = { + id: `customField_${element.id}`, + unit: 'complement', + label: element.label, + type: element.type, + control: new FormControl({ value: '', disabled: false }), + required: false, + default: false, + values: element.values.map((val: any) => { return { id: val, label: val } }) + }; + + if (element.type === 'integer') { + valArr.push(Validators.pattern(/^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$/)); + field.control.setValidators(valArr); + } + this.contactForm.push(field); }); } @@ -352,6 +363,7 @@ export class ContactsPageAdministrationComponent implements OnInit { initBanSearch() { this.http.get("../../rest/ban/availableDepartments").pipe( tap((data: any) => { + this.addressBANCurrentDepartment = data.default !== null ? data.default : this.addressBANCurrentDepartment; this.departmentList = data.departments; }), catchError((err: any) => { @@ -363,18 +375,21 @@ export class ContactsPageAdministrationComponent implements OnInit { isValidForm() { let state = true; - + this.contactForm.filter(contact => contact.default).forEach(element => { if (element.control.status !== 'VALID') { state = false; } element.control.markAsTouched() }); + return state; } onSubmit() { - if (this.isValidForm()) { + if (this.addressBANMode && this.emptyAddress()) { + this.notify.error('Choisissez une BAN'); + } else if (this.isValidForm()) { if (this.contactId !== null) { this.updateContact(); } else { @@ -605,4 +620,26 @@ export class ContactsPageAdministrationComponent implements OnInit { }; window.open(`https://www.google.com/maps/search/${contact.addressNumber}+${contact.addressStreet},+${contact.addressPostcode}+${contact.addressTown},+${contact.addressCountry}`, '_blank') } + + switchAddressMode() { + let valArr: ValidatorFn[] = []; + if (this.addressBANMode) { + + valArr.push(Validators.required); + + this.contactForm.filter(contact => ['addressNumber', 'addressStreet', 'addressPostcode', 'addressTown', 'addressCountry'].indexOf(contact.id) > -1).forEach((element: any) => { + if (element.mandatory) { + element.control.setValidators(valArr); + } + }); + this.addressBANMode = !this.addressBANMode; + } else { + this.contactForm.filter(contact => ['addressNumber', 'addressStreet', 'addressPostcode', 'addressTown', 'addressCountry'].indexOf(contact.id) > -1).forEach((element: any) => { + if (element.mandatory) { + element.control.setValidators(valArr); + } + }); + this.addressBANMode = !this.addressBANMode; + } + } } \ No newline at end of file diff --git a/src/frontend/lang/lang-en.ts b/src/frontend/lang/lang-en.ts index f6a3891f4aeec62d08e71c57db95d0d2b6298376..4c5343ad83256c0c454f682261dc0fbe9ed0a10e 100755 --- a/src/frontend/lang/lang-en.ts +++ b/src/frontend/lang/lang-en.ts @@ -1353,4 +1353,8 @@ export const LANG_EN = { "additionals": "Additional(s)", "denomination": "Denomination", "moreInfos" : "More data", + "onlyNumber" : "Number only", + "found": "found", + "here": "here", + "toCopyAddress": "to copy the address", }; diff --git a/src/frontend/lang/lang-fr.ts b/src/frontend/lang/lang-fr.ts index 47a025fce0e7fe882365deb1edb727528ba9dae9..8c6176ffd7051fb94735e4a2afc868676a09a677 100755 --- a/src/frontend/lang/lang-fr.ts +++ b/src/frontend/lang/lang-fr.ts @@ -1391,4 +1391,8 @@ export const LANG_FR = { "additionals": "Complément(s)", "denomination": "Dénomination", "moreInfos" : "Plus d'informations", + "onlyNumber" : "Chiffre uniqument", + "found": "trouvée", + "here": "ici", + "toCopyAddress": "pour copier son adresse", }; diff --git a/src/frontend/lang/lang-nl.ts b/src/frontend/lang/lang-nl.ts index 6bce203363bff6c4ca7243acfa27b38de9314041..5a151e1cbd7e3362c4570427ad9eab5bd1ada9f3 100755 --- a/src/frontend/lang/lang-nl.ts +++ b/src/frontend/lang/lang-nl.ts @@ -1378,4 +1378,8 @@ export const LANG_NL = { "additionals": "Additional(s)", //_TO_TRANSLATE "denomination": "Denomination", //_TO_TRANSLATE "moreInfos" : "More data", //_TO_TRANSLATE + "onlyNumber" : "Number only", //_TO_TRANSLATE + "found": "found", //_TO_TRANSLATE + "here": "here", //_TO_TRANSLATE + "toCopyAddress": "to copy the address", //_TO_TRANSLATE };