Edit dossier attributes
This commit is contained in:
parent
efa4e76f62
commit
95edb70dea
@ -4,7 +4,7 @@ import { FileAttributeConfig } from '@redaction/red-ui-http';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { SortingService } from '../../../../../services/sorting.service';
|
||||
import { SortingService } from '@services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
|
||||
@Component({
|
||||
|
||||
@ -11,7 +11,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { SortingService } from '../../../../services/sorting.service';
|
||||
import { SortingService } from '@services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
|
||||
export interface Field {
|
||||
|
||||
@ -4,8 +4,8 @@ import { DossierAttributeConfig, DossierAttributesControllerService } from '@red
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { ScreenNames, SortingService } from '../../../../services/sorting.service';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
|
||||
@ -3,13 +3,13 @@ import { AppStateService } from '@state/app-state.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { DossierTemplateModelWrapper } from '../../../../models/file/dossier-template-model.wrapper';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { DossierTemplateModelWrapper } from '@models/file/dossier-template-model.wrapper';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { DossierTemplateControllerService } from '@redaction/red-ui-http';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { ScreenNames, SortingService } from '../../../../services/sorting.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
|
||||
@Component({
|
||||
|
||||
@ -4,11 +4,11 @@ import { FileAttributeConfig, FileAttributesConfig, FileAttributesControllerServ
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { ScreenNames, SortingService } from '../../../../services/sorting.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
|
||||
@Component({
|
||||
|
||||
@ -4,8 +4,8 @@ import { AppStateService } from '@state/app-state.service';
|
||||
import { ReportTemplate, ReportTemplateControllerService } from '@redaction/red-ui-http';
|
||||
import { download } from '../../../../utils/file-download-utils';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { PermissionsService } from '../../../../services/permissions.service';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-reports-screen',
|
||||
|
||||
@ -2,13 +2,13 @@ import { ChangeDetectionStrategy, Component, Injector, OnInit } from '@angular/c
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { Dossier, StatusControllerService } from '@redaction/red-ui-http';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { AppConfigKey, AppConfigService } from '../../../app-config/app-config.service';
|
||||
import * as moment from 'moment';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { ScreenNames, SortingService } from '../../../../services/sorting.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { DossiersService } from '../../../dossier/services/dossiers.service';
|
||||
|
||||
|
||||
@ -6,12 +6,12 @@ import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component';
|
||||
import { TranslateChartService } from '@services/translate-chart.service';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { InitialsAvatarComponent } from '@shared/components/initials-avatar/initials-avatar.component';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { SortingService } from '../../../../services/sorting.service';
|
||||
import { SortingService } from '@services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@ -9,7 +9,7 @@ import { UserService } from '@services/user.service';
|
||||
import { User } from '@redaction/red-ui-http';
|
||||
import { NotificationService } from '@services/notification.service';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { FileStatusWrapper } from '../../../../models/file/file-status.wrapper';
|
||||
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-details',
|
||||
|
||||
@ -1,21 +1,89 @@
|
||||
<form *ngIf="attributesForm" [formGroup]="attributesForm">
|
||||
<div>
|
||||
<div class="heading">
|
||||
{{ 'edit-dossier-dialog.nav-items.custom-dossier-attributes' | translate }}
|
||||
<div *ngIf="customAttributes.length" class="heading">
|
||||
{{ 'edit-dossier-dialog.attributes.custom-attributes' | translate }}
|
||||
</div>
|
||||
<div *ngFor="let attr of customAttributes" class="red-input-group w-300">
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="!customAttributes.length"
|
||||
icon="red:attribute"
|
||||
text="edit-dossier-dialog.attributes.no-custom-attributes"
|
||||
></redaction-empty-state>
|
||||
|
||||
<div *ngFor="let attr of customAttributes" [class.datepicker-wrapper]="isDate(attr)" class="red-input-group">
|
||||
<label>{{ attr.label }}</label>
|
||||
<input [formControlName]="attr.id" [name]="attr.id" type="text" />
|
||||
<input
|
||||
*ngIf="isNumber(attr) || isText(attr)"
|
||||
[formControlName]="attr.id"
|
||||
[name]="attr.id"
|
||||
[type]="isNumber(attr) ? 'number' : 'text'"
|
||||
/>
|
||||
|
||||
<ng-container *ngIf="isDate(attr)">
|
||||
<input [formControlName]="attr.id" [matDatepicker]="picker" placeholder="dd/mm/yy" />
|
||||
<mat-datepicker-toggle [for]="picker" matSuffix>
|
||||
<mat-icon matDatepickerToggleIcon svgIcon="red:calendar"></mat-icon>
|
||||
</mat-datepicker-toggle>
|
||||
<mat-datepicker #picker></mat-datepicker>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div>
|
||||
<div class="heading">
|
||||
{{ 'edit-dossier-dialog.nav-items.image-attributes' | translate }}
|
||||
<div class="image-attributes-container">
|
||||
<div *ngIf="imageAttributes.length" class="heading">
|
||||
{{ 'edit-dossier-dialog.attributes.image-attributes' | translate }}
|
||||
</div>
|
||||
<div *ngFor="let attr of imageAttributes" class="red-input-group w-300">
|
||||
<label>{{ attr.label }}</label>
|
||||
<input [formControlName]="attr.id" [name]="attr.id" type="text" />
|
||||
|
||||
<redaction-empty-state
|
||||
*ngIf="!imageAttributes.length"
|
||||
icon="red:attribute"
|
||||
text="edit-dossier-dialog.attributes.no-image-attributes"
|
||||
></redaction-empty-state>
|
||||
|
||||
<div
|
||||
*ngFor="let attr of imageAttributes"
|
||||
[class.displayed-preview]="currentAttrValue(attr)"
|
||||
class="red-input-group image-attribute"
|
||||
>
|
||||
<div>
|
||||
<img *ngIf="currentAttrValue(attr)" [alt]="attr.label" [src]="currentAttrValue(attr)" />
|
||||
|
||||
<label>{{ attr.label }}</label>
|
||||
|
||||
<redaction-icon-button
|
||||
(action)="fileInputClick(attr)"
|
||||
*ngIf="!currentAttrValue(attr)"
|
||||
class="upload-button"
|
||||
icon="red:upload"
|
||||
text="edit-dossier-dialog.attributes.upload-image"
|
||||
type="show-bg"
|
||||
></redaction-icon-button>
|
||||
|
||||
<input
|
||||
#fileInput
|
||||
(change)="uploadImage($event, attr)"
|
||||
[id]="attr.id"
|
||||
[name]="attr.id"
|
||||
accept="image/*"
|
||||
class="file-upload-input"
|
||||
hidden
|
||||
type="file"
|
||||
/>
|
||||
</div>
|
||||
<div *ngIf="currentAttrValue(attr)">
|
||||
<redaction-circle-button
|
||||
(action)="deleteAttr(attr)"
|
||||
icon="red:trash"
|
||||
tooltip="edit-dossier-dialog.attributes.delete-image"
|
||||
type="dark-bg"
|
||||
></redaction-circle-button>
|
||||
<redaction-circle-button
|
||||
(action)="fileInputClick(attr)"
|
||||
icon="red:upload"
|
||||
tooltip="edit-dossier-dialog.attributes.upload-image"
|
||||
type="dark-bg"
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -20,5 +20,53 @@
|
||||
padding: 0;
|
||||
background-color: $separator;
|
||||
}
|
||||
|
||||
.datepicker-wrapper {
|
||||
width: initial;
|
||||
}
|
||||
|
||||
.datepicker-wrapper input {
|
||||
width: initial;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.datepicker-wrapper:not(:first-child) {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.image-attribute {
|
||||
&.displayed-preview {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
> div {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(first-of-type) {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.upload-button {
|
||||
margin-top: 6px;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
border: 1px solid $grey-5;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
redaction-circle-button:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, QueryList, ViewChildren } from '@angular/core';
|
||||
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
|
||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
@ -6,6 +6,9 @@ import { PermissionsService } from '@services/permissions.service';
|
||||
import { DossierAttributeConfig, DossierAttributesControllerService } from '@redaction/red-ui-http';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import * as moment from 'moment';
|
||||
|
||||
type DossierAttributeWithValue = DossierAttributeConfig & { value: any };
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-edit-dossier-attributes',
|
||||
@ -15,11 +18,12 @@ import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
export class EditDossierAttributesComponent implements EditDossierSectionInterface, OnInit {
|
||||
@Input() dossierWrapper: DossierWrapper;
|
||||
@Output() updateDossier = new EventEmitter<any>();
|
||||
customAttributes: (DossierAttributeConfig & { value: any })[] = [];
|
||||
imageAttributes: (DossierAttributeConfig & { value: any })[] = [];
|
||||
attributesMapping: (DossierAttributeConfig & { value: any })[] = [];
|
||||
customAttributes: DossierAttributeWithValue[] = [];
|
||||
imageAttributes: DossierAttributeWithValue[] = [];
|
||||
attributesMapping: DossierAttributeWithValue[] = [];
|
||||
|
||||
attributesForm: FormGroup;
|
||||
@ViewChildren('fileInput') private _fileInputs: QueryList<ElementRef>;
|
||||
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
@ -31,7 +35,11 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa
|
||||
|
||||
get changed() {
|
||||
for (const attr of this.attributesMapping) {
|
||||
if (this._parseAttrValue(attr.value) !== this._parseAttrValue(this.attributesForm.get(attr.id).value)) {
|
||||
if (this.isDate(attr)) {
|
||||
if (!moment(attr.value).isSame(moment(this.currentAttrValue(attr)))) {
|
||||
return true;
|
||||
}
|
||||
} else if (this._parseAttrValue(attr.value) !== this._parseAttrValue(this.currentAttrValue(attr))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -54,21 +62,69 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa
|
||||
this._loadingService.start();
|
||||
const dossierAttributeList = this.attributesMapping.map(attr => ({
|
||||
dossierAttributeId: attr.id,
|
||||
value: this.attributesForm.get(attr.id).value
|
||||
value: this.currentAttrValue(attr)
|
||||
}));
|
||||
await this._dossierAttributesService.setDossierAttributes({ dossierAttributeList }, this.dossierWrapper.dossierId).toPromise();
|
||||
await this._loadAttributes();
|
||||
this.updateDossier.emit();
|
||||
this._loadingService.stop();
|
||||
}
|
||||
|
||||
updatedDossier($event) {
|
||||
this.updateDossier.emit($event);
|
||||
fileInputClick(attr: DossierAttributeWithValue) {
|
||||
this._getFileInputById(attr.id).nativeElement.click();
|
||||
}
|
||||
|
||||
isNumber(attr: DossierAttributeWithValue): boolean {
|
||||
return attr.type === 'NUMBER';
|
||||
}
|
||||
|
||||
isDate(attr: DossierAttributeWithValue): boolean {
|
||||
return attr.type === 'DATE';
|
||||
}
|
||||
|
||||
isImage(attr: DossierAttributeWithValue): boolean {
|
||||
return attr.type === 'IMAGE';
|
||||
}
|
||||
|
||||
isText(attr: DossierAttributeWithValue): boolean {
|
||||
return attr.type === 'TEXT';
|
||||
}
|
||||
|
||||
async uploadImage($event, attr: DossierAttributeWithValue) {
|
||||
const toBase64 = file =>
|
||||
new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => resolve(reader.result);
|
||||
reader.onerror = error => reject(error);
|
||||
});
|
||||
|
||||
const image = $event.target.files[0];
|
||||
const result = await toBase64(image);
|
||||
this.attributesForm.patchValue({
|
||||
[attr.id]: result
|
||||
});
|
||||
this._getFileInputById(attr.id).nativeElement.value = null;
|
||||
}
|
||||
|
||||
revert() {
|
||||
this._initForm();
|
||||
}
|
||||
|
||||
currentAttrValue(attr: DossierAttributeWithValue): string {
|
||||
return this.attributesForm.get(attr.id).value;
|
||||
}
|
||||
|
||||
deleteAttr(attr: DossierAttributeWithValue) {
|
||||
this.attributesForm.patchValue({
|
||||
[attr.id]: null
|
||||
});
|
||||
}
|
||||
|
||||
private _getFileInputById(id: string): ElementRef {
|
||||
return this._fileInputs.find(el => el.nativeElement.id === id);
|
||||
}
|
||||
|
||||
private _parseAttrValue(value: any) {
|
||||
return [null, undefined, ''].includes(value) ? undefined : value;
|
||||
}
|
||||
@ -83,8 +139,8 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa
|
||||
value: attributes.dossierAttributeList.find(attr => attr.dossierAttributeId === config.id)?.value
|
||||
}));
|
||||
|
||||
this.customAttributes = this.attributesMapping.filter(attr => attr.type !== 'IMAGE');
|
||||
this.imageAttributes = this.attributesMapping.filter(attr => attr.type === 'IMAGE');
|
||||
this.customAttributes = this.attributesMapping.filter(attr => !this.isImage(attr));
|
||||
this.imageAttributes = this.attributesMapping.filter(attr => this.isImage(attr));
|
||||
}
|
||||
|
||||
private _initForm() {
|
||||
|
||||
@ -22,13 +22,13 @@ import {
|
||||
dossierStatusChecker,
|
||||
dossierTemplateChecker
|
||||
} from '@shared/components/filters/popup-filter/utils/filter-utils';
|
||||
import { UserPreferenceService } from '../../../../services/user-preference.service';
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
import { ButtonConfig } from '@shared/components/page-header/models/button-config.model';
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { ScreenNames, SortingService } from '../../../../services/sorting.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './dossier-listing-screen.component.html',
|
||||
|
||||
@ -29,7 +29,7 @@ import { ActionConfig } from '@shared/components/page-header/models/action-confi
|
||||
import { FilterService } from '@shared/services/filter.service';
|
||||
import { SearchService } from '@shared/services/search.service';
|
||||
import { ScreenStateService } from '@shared/services/screen-state.service';
|
||||
import { ScreenNames, SortingService } from '../../../../services/sorting.service';
|
||||
import { ScreenNames, SortingService } from '@services/sorting.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
|
||||
@Component({
|
||||
|
||||
@ -831,9 +831,15 @@
|
||||
"general-info": "General Information",
|
||||
"members": "Members",
|
||||
"report-attributes": "Report Attributes",
|
||||
"team-members": "Team Members",
|
||||
"custom-dossier-attributes": "Custom Dossier Attributes",
|
||||
"image-attributes": "Image Attributes"
|
||||
"team-members": "Team Members"
|
||||
},
|
||||
"attributes": {
|
||||
"custom-attributes": "Custom Dossier Attributes",
|
||||
"image-attributes": "Image Attributes",
|
||||
"upload-image": "Upload Image",
|
||||
"delete-image": "Delete Image",
|
||||
"no-custom-attributes": "There are no text attributes",
|
||||
"no-image-attributes": "There are no image attributes"
|
||||
},
|
||||
"unsaved-changes": "You have unsaved changes. Save or revert before changing the tab."
|
||||
},
|
||||
|
||||
@ -196,6 +196,7 @@ form {
|
||||
.mat-datepicker-toggle {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
color: $accent;
|
||||
|
||||
&.mat-datepicker-toggle-active {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user