RED-9447, RED-10244: disable dossier template field if state is changed.
This commit is contained in:
parent
b0d38e1b0f
commit
2e2eaf476d
@ -44,11 +44,15 @@
|
||||
<div class="iqser-input-group w-300">
|
||||
<label translate="edit-dossier-dialog.general-info.form.dossier-state.label"></label>
|
||||
<mat-form-field>
|
||||
<mat-select [placeholder]="statusPlaceholder" formControlName="dossierStatusId">
|
||||
<mat-option *ngFor="let stateId of states" [value]="stateId">
|
||||
<div [matTooltip]="getStateName(stateId)" class="flex-align-items-center" matTooltipPosition="after">
|
||||
<iqser-small-chip *ngIf="!!stateId" [color]="getStateColor(stateId)"></iqser-small-chip>
|
||||
<div class="clamp-1">{{ getStateName(stateId) }}</div>
|
||||
<mat-select [placeholder]="statePlaceholder()" formControlName="dossierStatusId">
|
||||
<mat-option *ngFor="let stateId of states()" [value]="stateId">
|
||||
<div
|
||||
[matTooltip]="stateNameAndColor()[stateId]?.name"
|
||||
class="flex-align-items-center"
|
||||
matTooltipPosition="after"
|
||||
>
|
||||
<iqser-small-chip *ngIf="!!stateId" [color]="stateNameAndColor()[stateId]?.color"></iqser-small-chip>
|
||||
<div class="clamp-1">{{ stateNameAndColor()[stateId]?.name }}</div>
|
||||
</div>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
@ -80,7 +84,7 @@
|
||||
<div class="dialog-actions">
|
||||
<iqser-icon-button
|
||||
(action)="deleteDossier()"
|
||||
*ngIf="permissionsService.canDeleteDossier(dossier)"
|
||||
*ngIf="permissionsService.canDeleteDossier(dossier())"
|
||||
[attr.help-mode-key]="'edit_dossier_delete_dossier_DIALOG'"
|
||||
[buttonId]="'deleteDossier'"
|
||||
[icon]="'iqser:trash'"
|
||||
@ -90,7 +94,7 @@
|
||||
|
||||
<iqser-icon-button
|
||||
(action)="archiveDossier()"
|
||||
*ngIf="permissionsService.canArchiveDossier(dossier)"
|
||||
*ngIf="permissionsService.canArchiveDossier(dossier())"
|
||||
[attr.help-mode-key]="'edit_dossier_archive_dossier_DIALOG'"
|
||||
[icon]="'red:archive'"
|
||||
[label]="'dossier-listing.archive.action' | translate"
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { NgForOf, NgIf } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||
import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, effect, input, OnInit, signal, untracked } from '@angular/core';
|
||||
import { FormGroup, ReactiveFormsModule, UntypedFormBuilder, Validators } from '@angular/forms';
|
||||
import { MatCheckbox } from '@angular/material/checkbox';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatFormField, MatSuffix } from '@angular/material/form-field';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { MatOption, MatSelect } from '@angular/material/select';
|
||||
import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { Router } from '@angular/router';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
@ -30,12 +30,22 @@ import { DossiersService } from '@services/dossiers/dossiers.service';
|
||||
import { DossierStatesMapService } from '@services/entity-services/dossier-states-map.service';
|
||||
import { TrashService } from '@services/entity-services/trash.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { dateWithoutTime } from '@utils/functions';
|
||||
import { dateWithoutTime, formControlToSignal } from '@utils/functions';
|
||||
import dayjs from 'dayjs';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
|
||||
import { type EditDossierDialogComponent } from '../edit-dossier-dialog.component';
|
||||
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
|
||||
import { AsControl, isJustOne } from '@common-ui/utils';
|
||||
import { DossierStatesService } from '@services/entity-services/dossier-states.service';
|
||||
|
||||
interface GeneralInfoForm {
|
||||
dossierName: string;
|
||||
dossierTemplateId: string;
|
||||
dossierStatusId?: string;
|
||||
description?: string;
|
||||
dueDate?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-edit-dossier-general-info',
|
||||
@ -59,18 +69,36 @@ import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-doss
|
||||
MatSuffix,
|
||||
IconButtonComponent,
|
||||
NgIf,
|
||||
MatSelectTrigger,
|
||||
],
|
||||
})
|
||||
export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSectionInterface {
|
||||
@Input() dossier: Dossier;
|
||||
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
|
||||
form: UntypedFormGroup;
|
||||
statusPlaceholder: string;
|
||||
readonly dossier = input<Dossier>();
|
||||
hasDueDate: boolean;
|
||||
dossierTemplates: IDossierTemplate[];
|
||||
states: string[];
|
||||
form: FormGroup<AsControl<GeneralInfoForm>> = this._formBuilder.group({
|
||||
dossierName: [null, Validators.required],
|
||||
dossierTemplateId: [null, Validators.required],
|
||||
dossierStatusId: [null],
|
||||
description: [null],
|
||||
dueDate: [null],
|
||||
});
|
||||
initialFormValue: GeneralInfoForm;
|
||||
readonly dossierStatusIdControl = formControlToSignal(this.form.controls.dossierStatusId);
|
||||
readonly dossierTemplateIdControl = formControlToSignal<GeneralInfoForm['dossierTemplateId']>(this.form.controls.dossierTemplateId);
|
||||
readonly states = signal([null]);
|
||||
readonly stateNameAndColor = computed(() => {
|
||||
const nameAndColor = {};
|
||||
this.states().forEach(stateId => {
|
||||
nameAndColor[stateId] = {
|
||||
name: this.#getStateName(stateId, untracked(this.dossierTemplateIdControl)),
|
||||
color: this.#getStateColor(stateId, untracked(this.dossierTemplateIdControl)),
|
||||
};
|
||||
});
|
||||
return nameAndColor;
|
||||
});
|
||||
readonly statePlaceholder = computed(() => this.#statePlaceholder);
|
||||
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
@ -87,18 +115,36 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _archivedDossiersService: ArchivedDossiersService,
|
||||
) {}
|
||||
private readonly _changeDetectorRef: ChangeDetectorRef,
|
||||
private readonly _dossierStatesService: DossierStatesService,
|
||||
) {
|
||||
effect(() => {
|
||||
if (this.dossierStatusIdControl() !== this.initialFormValue.dossierStatusId && this.dossierStatusIdControl()) {
|
||||
this.form.controls.dossierTemplateId.disable();
|
||||
} else {
|
||||
this.form.controls.dossierTemplateId.enable();
|
||||
}
|
||||
});
|
||||
|
||||
effect(
|
||||
() => {
|
||||
this.states.set(this.#statesForDossierTemplate);
|
||||
this.#onDossierTemplateChange();
|
||||
},
|
||||
{ allowSignalWrites: true },
|
||||
);
|
||||
}
|
||||
|
||||
get changed(): boolean {
|
||||
for (const key of Object.keys(this.form.getRawValue())) {
|
||||
if (key === 'dueDate') {
|
||||
if (this.hasDueDate !== !!this.dossier.dueDate) {
|
||||
if (this.hasDueDate !== !!this.dossier().dueDate) {
|
||||
return true;
|
||||
}
|
||||
if (this.hasDueDate && !dayjs(this.dossier.dueDate).isSame(dayjs(this.form.get(key).value), 'day')) {
|
||||
if (this.hasDueDate && !dayjs(this.dossier().dueDate).isSame(dayjs(this.form.get(key).value), 'day')) {
|
||||
return true;
|
||||
}
|
||||
} else if (this.dossier[key] !== this.form.get(key).value) {
|
||||
} else if (this.dossier()[key] !== this.form.get(key).value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -114,40 +160,89 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
return this.hasDueDate && this.form.get('dueDate').value === null;
|
||||
}
|
||||
|
||||
get #statusPlaceholder(): string {
|
||||
get #statePlaceholder(): string {
|
||||
return this._translateService.instant(
|
||||
this.states.length === 1
|
||||
isJustOne(this.states())
|
||||
? 'edit-dossier-dialog.general-info.form.dossier-state.no-state-placeholder'
|
||||
: 'dossier-state.placeholder',
|
||||
) as string;
|
||||
}
|
||||
|
||||
get #statesForDossierTemplate() {
|
||||
return [
|
||||
null,
|
||||
...this._dossierStatesMapService
|
||||
.get(this.dossierTemplateIdControl() ?? untracked(this.dossier).dossierTemplateId)
|
||||
.map(s => s.id),
|
||||
];
|
||||
}
|
||||
|
||||
get #formValue(): { key: string; value: string; disabled: boolean }[] {
|
||||
const dossier = untracked(this.dossier);
|
||||
const formFieldWithArchivedCheck = value => ({ value, disabled: !dossier.isActive });
|
||||
const dossierStateId = untracked(this.dossierStatusIdControl);
|
||||
const states = untracked(this.states);
|
||||
return [
|
||||
{
|
||||
key: 'dossierName',
|
||||
...formFieldWithArchivedCheck(dossier.dossierName),
|
||||
},
|
||||
{
|
||||
key: 'dossierTemplateId',
|
||||
value: dossier.dossierTemplateId,
|
||||
disabled: this._dossierStatsService.get(dossier.id).hasFiles || !dossier.isActive || !!dossierStateId,
|
||||
},
|
||||
{
|
||||
key: 'dossierStatusId',
|
||||
value: dossier.dossierStatusId,
|
||||
disabled: isJustOne(states) || !dossier.isActive,
|
||||
},
|
||||
{
|
||||
key: 'description',
|
||||
...formFieldWithArchivedCheck(dossier.description),
|
||||
},
|
||||
{
|
||||
key: 'dueDate',
|
||||
...formFieldWithArchivedCheck(dossier.dueDate),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.states = [null, ...this._dossierStatesMapService.get(this.dossier.dossierTemplateId).map(s => s.id)];
|
||||
this.statusPlaceholder = this.#statusPlaceholder;
|
||||
this.#filterInvalidDossierTemplates();
|
||||
this.form = this.#getForm();
|
||||
if (!this.permissionsService.canEditDossier(this.dossier)) {
|
||||
this.#patchFormValue();
|
||||
if (isJustOne(this._dossierTemplatesService.all)) {
|
||||
this._loadingService.loadWhile(
|
||||
firstValueFrom(this._dossierTemplatesService.loadOnlyDossierTemplates()).then(async () => {
|
||||
await firstValueFrom(this._dossierStatesService.loadAllForAllTemplates());
|
||||
this.#filterInvalidDossierTemplates();
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
this.#filterInvalidDossierTemplates();
|
||||
}
|
||||
|
||||
if (!this.permissionsService.canEditDossier(this.dossier())) {
|
||||
this.form.disable();
|
||||
}
|
||||
this.hasDueDate = !!this.dossier.dueDate;
|
||||
this.hasDueDate = !!this.dossier().dueDate;
|
||||
}
|
||||
|
||||
revert() {
|
||||
this.form.reset({
|
||||
dossierName: this.dossier.dossierName,
|
||||
dossierTemplateId: this.dossier.dossierTemplateId,
|
||||
dossierStatusId: this.dossier.dossierStatusId,
|
||||
description: this.dossier.description,
|
||||
dueDate: this.dossier.dueDate,
|
||||
dossierName: this.dossier().dossierName,
|
||||
dossierTemplateId: this.dossier().dossierTemplateId,
|
||||
dossierStatusId: this.dossier().dossierStatusId,
|
||||
description: this.dossier().description,
|
||||
dueDate: this.dossier().dueDate,
|
||||
});
|
||||
this.hasDueDate = !!this.dossier.dueDate;
|
||||
this.hasDueDate = !!this.dossier().dueDate;
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
}
|
||||
|
||||
async save(): EditDossierSaveResult {
|
||||
const dueDate = dateWithoutTime(dayjs(this.form.get('dueDate').value));
|
||||
const dossier = {
|
||||
...this.dossier,
|
||||
...this.dossier(),
|
||||
dossierName: this.form.get('dossierName').value,
|
||||
description: this.form.get('description').value,
|
||||
dueDate: dueDate.isValid() ? dueDate.toISOString() : undefined,
|
||||
@ -156,9 +251,10 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
} as IDossierRequest;
|
||||
|
||||
const updatedDossier = await firstValueFrom(this._dossiersService.createOrUpdate(dossier));
|
||||
if (updatedDossier && updatedDossier.dossierTemplateId !== this.dossier.dossierTemplateId) {
|
||||
if (updatedDossier && updatedDossier.dossierTemplateId !== this.dossier().dossierTemplateId) {
|
||||
await this._router.navigate([updatedDossier.routerLink]);
|
||||
}
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
return { success: !!updatedDossier };
|
||||
}
|
||||
|
||||
@ -171,14 +267,14 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
requireInput: true,
|
||||
denyText: _('confirmation-dialog.delete-dossier.deny-text'),
|
||||
translateParams: {
|
||||
dossierName: this.dossier.dossierName,
|
||||
dossierName: this.dossier().dossierName,
|
||||
dossiersCount: 1,
|
||||
},
|
||||
};
|
||||
|
||||
this._dialogService.openDialog('confirm', data, async () => {
|
||||
this._loadingService.start();
|
||||
const successful = await this._trashService.deleteDossier(this.dossier);
|
||||
const successful = await this._trashService.deleteDossier(this.dossier());
|
||||
if (successful) {
|
||||
await this.#closeDialogAndRedirectToDossier();
|
||||
}
|
||||
@ -194,7 +290,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
confirmationText: _('confirm-archive-dossier.archive'),
|
||||
denyText: _('confirm-archive-dossier.cancel'),
|
||||
titleColor: TitleColors.WARN,
|
||||
translateParams: { ...this.dossier },
|
||||
translateParams: { ...this.dossier() },
|
||||
checkboxes: [{ value: false, label: _('confirm-archive-dossier.checkbox.documents') }],
|
||||
toastMessage: _('confirm-archive-dossier.toast-error'),
|
||||
};
|
||||
@ -202,10 +298,10 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
this._dialogService.openDialog('confirm', data, async result => {
|
||||
if (result === ConfirmOptions.CONFIRM) {
|
||||
this._loadingService.start();
|
||||
await firstValueFrom(this._archivedDossiersService.archive([this.dossier]));
|
||||
await firstValueFrom(this._archivedDossiersService.archive([this.dossier()]));
|
||||
this._toaster.success(_('dossier-listing.archive.archive-succeeded'), {
|
||||
params: {
|
||||
dossierName: this.dossier.dossierName,
|
||||
dossierName: this.dossier().dossierName,
|
||||
},
|
||||
});
|
||||
this._editDossierDialogRef.close();
|
||||
@ -214,15 +310,6 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
});
|
||||
}
|
||||
|
||||
getStateName(stateId: string): string {
|
||||
return (this._dossierStatesMapService.get(this.dossier.dossierTemplateId, stateId)?.name ||
|
||||
this._translateService.instant('dossier-state.placeholder')) as string;
|
||||
}
|
||||
|
||||
getStateColor(stateId: string): string {
|
||||
return this._dossierStatesMapService.get(this.dossier.dossierTemplateId, stateId).color;
|
||||
}
|
||||
|
||||
toggleDueDateField() {
|
||||
this.hasDueDate = !this.hasDueDate;
|
||||
if (!this.hasDueDate) {
|
||||
@ -230,46 +317,63 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
}
|
||||
}
|
||||
|
||||
#getStateName(stateId: string, templateId: string): string {
|
||||
return (this._dossierStatesMapService.get(templateId, stateId)?.name ||
|
||||
this._translateService.instant('dossier-state.placeholder')) as string;
|
||||
}
|
||||
|
||||
#getStateColor(stateId: string, templateId: string): string {
|
||||
return this._dossierStatesMapService.get(templateId, stateId)?.color;
|
||||
}
|
||||
|
||||
#patchFormValue() {
|
||||
this.#formValue.forEach(formValue => {
|
||||
this.form.patchValue({ [formValue.key]: formValue.value });
|
||||
if (formValue.disabled) this.form.get(formValue.key).disable();
|
||||
});
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
}
|
||||
|
||||
async #closeDialogAndRedirectToDossier() {
|
||||
this._editDossierDialogRef.close();
|
||||
await this._router.navigate([this.dossier.dossiersListRouterLink]);
|
||||
await this._router.navigate([this.dossier().dossiersListRouterLink]);
|
||||
this._toaster.success(_('edit-dossier-dialog.delete-successful'), {
|
||||
params: {
|
||||
dossierName: this.dossier.dossierName,
|
||||
dossierName: this.dossier().dossierName,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
#getForm(): UntypedFormGroup {
|
||||
const formFieldWithArchivedCheck = value => ({ value, disabled: !this.dossier.isActive });
|
||||
return this._formBuilder.group({
|
||||
dossierName: [formFieldWithArchivedCheck(this.dossier.dossierName), Validators.required],
|
||||
dossierTemplateId: [
|
||||
{
|
||||
value: this.dossier.dossierTemplateId,
|
||||
disabled: this._dossierStatsService.get(this.dossier.id).hasFiles || !this.dossier.isActive,
|
||||
},
|
||||
Validators.required,
|
||||
],
|
||||
dossierStatusId: [
|
||||
{
|
||||
value: this.dossier.dossierStatusId,
|
||||
disabled: this.states.length === 1 || !this.dossier.isActive,
|
||||
},
|
||||
],
|
||||
description: [formFieldWithArchivedCheck(this.dossier.description)],
|
||||
dueDate: [formFieldWithArchivedCheck(this.dossier.dueDate)],
|
||||
});
|
||||
}
|
||||
|
||||
#filterInvalidDossierTemplates() {
|
||||
const dossier = untracked(this.dossier);
|
||||
this.dossierTemplates = this._dossierTemplatesService.all.filter(r => {
|
||||
if (this.dossier?.dossierTemplateId === r.dossierTemplateId) {
|
||||
if (dossier.dossierTemplateId === r.dossierTemplateId) {
|
||||
return true;
|
||||
}
|
||||
const notYetValid = !!r.validFrom && dayjs(r.validFrom).isAfter(dayjs());
|
||||
const notValidAnymore = !!r.validTo && dayjs(r.validTo).add(1, 'd').isBefore(dayjs());
|
||||
this._changeDetectorRef.markForCheck();
|
||||
return !(notYetValid || notValidAnymore) && r.isActive;
|
||||
});
|
||||
}
|
||||
|
||||
#onDossierTemplateChange() {
|
||||
const dossierStateId = untracked(this.dossierStatusIdControl);
|
||||
const dossierTemplateId = untracked(this.dossierTemplateIdControl);
|
||||
if (!!dossierStateId && dossierTemplateId !== this.initialFormValue.dossierTemplateId) {
|
||||
this.form.controls.dossierStatusId.setValue(null);
|
||||
}
|
||||
const dossier = untracked(this.dossier);
|
||||
if (dossierTemplateId === this.initialFormValue.dossierTemplateId) {
|
||||
this.form.controls.dossierStatusId.setValue(dossier.dossierStatusId);
|
||||
}
|
||||
const states = untracked(this.states);
|
||||
if (isJustOne(states) || !dossier.isActive) {
|
||||
this.form.controls.dossierStatusId.disable();
|
||||
} else {
|
||||
this.form.controls.dossierStatusId.enable();
|
||||
}
|
||||
|
||||
this._changeDetectorRef.markForCheck();
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,6 +45,13 @@ export class DossierTemplatesService extends EntitiesService<IDossierTemplate, D
|
||||
);
|
||||
}
|
||||
|
||||
loadOnlyDossierTemplates(): Observable<DossierTemplate[]> {
|
||||
return this.getAll().pipe(
|
||||
mapEach(entity => new DossierTemplate(entity)),
|
||||
tap(templates => this.setEntities(templates)),
|
||||
);
|
||||
}
|
||||
|
||||
loadDossierTemplate(dossierTemplateId: string) {
|
||||
return this._getOne([dossierTemplateId], this._defaultModelPath).pipe(
|
||||
map(entity => new DossierTemplate(entity)),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user