RED-7783: Fixed numeric and date file attrs

This commit is contained in:
Adina Țeudan 2023-10-20 14:40:13 +03:00
parent 8f131aff23
commit b2e7814a75
3 changed files with 68 additions and 30 deletions

View File

@ -1,7 +1,7 @@
<ng-container *ngIf="configService.listingMode$ | async as mode"> <ng-container *ngIf="configService.listingMode$ | async as mode">
<div <div
(mousedown)="handleClick($event)"
(click)="editFileAttribute($event)" (click)="editFileAttribute($event)"
(mousedown)="handleClick($event)"
[ngClass]="{ 'workflow-attribute': mode === 'workflow' }" [ngClass]="{ 'workflow-attribute': mode === 'workflow' }"
class="file-attribute" class="file-attribute"
> >
@ -9,8 +9,8 @@
<b *ngIf="mode === 'workflow' && !isInEditMode"> {{ fileAttribute.label }}: </b> <b *ngIf="mode === 'workflow' && !isInEditMode"> {{ fileAttribute.label }}: </b>
<span <span
*ngIf="!isDate; else date" *ngIf="!isDate; else date"
[ngClass]="{ hide: isInEditMode, 'clamp-3': mode !== 'workflow' }"
[matTooltip]="fileAttributeValue" [matTooltip]="fileAttributeValue"
[ngClass]="{ hide: isInEditMode, 'clamp-3': mode !== 'workflow' }"
> >
{{ fileAttributeValue || '-' }}</span {{ fileAttributeValue || '-' }}</span
> >
@ -44,7 +44,7 @@
</div> </div>
<ng-template #input> <ng-template #input>
<div [ngClass]="{ 'workflow-edit-input': mode === 'workflow' }" class="edit-input"> <div (click)="$event.stopPropagation()" [ngClass]="{ 'workflow-edit-input': mode === 'workflow' }" class="edit-input">
<form (ngSubmit)="form.valid && save()" [formGroup]="form"> <form (ngSubmit)="form.valid && save()" [formGroup]="form">
<iqser-dynamic-input <iqser-dynamic-input
(closedDatepicker)="closedDatepicker = $event" (closedDatepicker)="closedDatepicker = $event"

View File

@ -1,8 +1,8 @@
import { Component, HostListener, Input, OnDestroy } from '@angular/core'; import { Component, HostListener, Input, OnDestroy } from '@angular/core';
import { Dossier, File, FileAttributeConfigTypes, IFileAttributeConfig } from '@red/domain'; import { Dossier, File, FileAttributeConfigTypes, IFileAttributeConfig } from '@red/domain';
import { BaseFormComponent, Debounce, HelpModeService, ListingService, Toaster } from '@iqser/common-ui'; import { BaseFormComponent, HelpModeService, ListingService, Toaster } from '@iqser/common-ui';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { FormBuilder, UntypedFormGroup } from '@angular/forms'; import { AbstractControl, FormBuilder, UntypedFormGroup, ValidatorFn } from '@angular/forms';
import { FileAttributesService } from '@services/entity-services/file-attributes.service'; import { FileAttributesService } from '@services/entity-services/file-attributes.service';
import { firstValueFrom, Subscription } from 'rxjs'; import { firstValueFrom, Subscription } from 'rxjs';
import { FilesService } from '@services/files/files.service'; import { FilesService } from '@services/files/files.service';
@ -24,7 +24,6 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr
isInEditMode = false; isInEditMode = false;
closedDatepicker = true; closedDatepicker = true;
readonly #subscriptions = new Subscription();
readonly shouldClose$ = this.fileAttributesService.isEditingFileAttribute$.pipe( readonly shouldClose$ = this.fileAttributesService.isEditingFileAttribute$.pipe(
tap(value => { tap(value => {
if ( if (
@ -39,6 +38,23 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr
} }
}), }),
); );
readonly #subscriptions = new Subscription();
get isDate(): boolean {
return this.fileAttribute.type === FileAttributeConfigTypes.DATE;
}
get isNumber(): boolean {
return this.fileAttribute.type === FileAttributeConfigTypes.NUMBER;
}
get isText(): boolean {
return this.fileAttribute.type === FileAttributeConfigTypes.TEXT;
}
get fileAttributeValue(): string {
return this.file.fileAttributes.attributeIdToValue[this.fileAttribute.id];
}
constructor( constructor(
router: Router, router: Router,
@ -62,15 +78,6 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr
this.#subscriptions.add(sub2.subscribe()); this.#subscriptions.add(sub2.subscribe());
} }
get isDate(): boolean {
return this.fileAttribute.type === FileAttributeConfigTypes.DATE;
}
get fileAttributeValue(): string {
return this.file.fileAttributes.attributeIdToValue[this.fileAttribute.id];
}
@Debounce(50)
@HostListener('document:click') @HostListener('document:click')
clickOutside() { clickOutside() {
if (this.isInEditMode && this.closedDatepicker) { if (this.isInEditMode && this.closedDatepicker) {
@ -164,16 +171,40 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr
config[key] = [dayjs(attrValue, 'YYYY-MM-DD', true).isValid() ? dayjs(attrValue).toDate() : attrValue]; config[key] = [dayjs(attrValue, 'YYYY-MM-DD', true).isValid() ? dayjs(attrValue).toDate() : attrValue];
}); });
return this._formBuilder.group(config, { return this._formBuilder.group(config, {
validators: control => validators: [this.#checkEmptyInput(), this.#checkDate()],
(!control.get(this.fileAttribute.id)?.value?.trim().length && !this.fileAttributeValue) ||
control.get(this.fileAttribute.id)?.value === this.fileAttributeValue
? { emptyString: true }
: null,
}); });
} }
#checkEmptyInput(): ValidatorFn {
return (control: AbstractControl) =>
(this.isText && !control.get(this.fileAttribute.id)?.value?.trim().length && !this.fileAttributeValue) ||
control.get(this.fileAttribute.id)?.value === this.fileAttributeValue
? { emptyString: true }
: null;
}
#checkDate(): ValidatorFn {
return (control: AbstractControl) => {
const expr = new RegExp('(0?[1-9]|[12][0-9]|3[01])(/|.)(0?[1-9]|1[12])(/|.)\\d{2}');
return this.isDate
? (!expr.test(control.get(this.fileAttribute.id)?.value) && control.get(this.fileAttribute.id)?.value?.length) ||
this.#formatAttributeValue(control.get(this.fileAttribute.id)?.value) === this.fileAttributeValue
? { invalidDate: true }
: null
: null;
};
}
#formatAttributeValue(attrValue) { #formatAttributeValue(attrValue) {
return this.isDate ? attrValue && dayjs(attrValue).format('YYYY-MM-DD') : attrValue.trim().replaceAll(/\s\s+/g, ' '); if (this.isDate) {
return attrValue && dayjs(attrValue).format('YYYY-MM-DD');
}
if (this.isText) {
return attrValue.trim().replaceAll(/\s\s+/g, ' ');
}
return attrValue;
} }
#toggleEdit(): void { #toggleEdit(): void {
@ -191,9 +222,16 @@ export class FileAttributeComponent extends BaseFormComponent implements OnDestr
} }
#focusOnEditInput(): void { #focusOnEditInput(): void {
setTimeout(() => { if (this.isDate || this.isText) {
const input = document.getElementById(this.fileAttribute.id); setTimeout(() => {
input?.focus(); const input = document.getElementById(this.fileAttribute.id) as HTMLInputElement;
}, 100); if (!input) {
return;
}
const end = input.value.length;
input.setSelectionRange(end, end);
input.focus();
}, 100);
}
} }
} }

View File

@ -8,7 +8,7 @@ import { DateAdapter, MAT_DATE_LOCALE } from '@angular/material/core';
import dayjs, { Dayjs } from 'dayjs'; import dayjs, { Dayjs } from 'dayjs';
import utc from 'dayjs/plugin/utc'; import utc from 'dayjs/plugin/utc';
import localeData from 'dayjs/plugin/localeData'; import localeData from 'dayjs/plugin/localeData';
import LocalizedFormat from 'dayjs/plugin/localizedFormat'; import localizedFormat from 'dayjs/plugin/localizedFormat';
import customParseFormat from 'dayjs/plugin/customParseFormat'; import customParseFormat from 'dayjs/plugin/customParseFormat';
export interface DayJsDateAdapterOptions { export interface DayJsDateAdapterOptions {
@ -135,8 +135,7 @@ export class CustomDateAdapter extends DateAdapter<Dayjs> {
} }
createDate(year: number, month: number, date: number): Dayjs { createDate(year: number, month: number, date: number): Dayjs {
const returnDayjs = this._dayJs().set('year', year).set('month', month).set('date', date); return this._dayJs().set('year', year).set('month', month).set('date', date);
return returnDayjs;
} }
today(): Dayjs { today(): Dayjs {
@ -145,8 +144,9 @@ export class CustomDateAdapter extends DateAdapter<Dayjs> {
parse(value: any, parseFormat: string): Dayjs | null { parse(value: any, parseFormat: string): Dayjs | null {
if (value && typeof value === 'string') { if (value && typeof value === 'string') {
return this._dayJs(value, dayjs().localeData().longDateFormat(parseFormat), this.locale); return dayjs(value, parseFormat);
} }
// todo: is this necessary?
return value ? this._dayJs(value).locale(this.locale) : null; return value ? this._dayJs(value).locale(this.locale) : null;
} }
@ -229,7 +229,7 @@ export class CustomDateAdapter extends DateAdapter<Dayjs> {
dayjs.extend(utc); dayjs.extend(utc);
} }
dayjs.extend(LocalizedFormat); dayjs.extend(localizedFormat);
dayjs.extend(customParseFormat); dayjs.extend(customParseFormat);
dayjs.extend(localeData); dayjs.extend(localeData);