finished states screen, update dossier table

This commit is contained in:
Edi Cziszter 2022-02-03 21:02:11 +02:00
parent 4c67355bb4
commit 30883a5349
16 changed files with 253 additions and 15 deletions

View File

@ -49,6 +49,7 @@ import { BaseDossierTemplateScreenComponent } from './base-dossier-templates-scr
import { DossierStatesListingScreenComponent } from './screens/dossier-states-listing/dossier-states-listing-screen.component';
import { AddEditDossierStateDialogComponent } from './dialogs/add-edit-dossier-state-dialog/add-edit-dossier-state-dialog.component';
import { A11yModule } from '@angular/cdk/a11y';
import { ConfirmDeleteDossierStateDialogComponent } from './dialogs/confirm-delete-dossier-state-dialog/confirm-delete-dossier-state-dialog.component';
const dialogs = [
AddEditDossierTemplateDialogComponent,
@ -98,7 +99,12 @@ const components = [
];
@NgModule({
declarations: [...components, DossierStatesListingScreenComponent, AddEditDossierStateDialogComponent],
declarations: [
...components,
DossierStatesListingScreenComponent,
AddEditDossierStateDialogComponent,
ConfirmDeleteDossierStateDialogComponent,
],
providers: [AdminDialogService, AuditService, DigitalSignatureService, LicenseReportService, RulesService, SmtpConfigService],
imports: [
CommonModule,

View File

@ -0,0 +1,39 @@
<section class="dialog">
<div class="dialog-header heading-l">
{{ 'confirm-delete-dossier-state.title' | translate }}
</div>
<div class="dialog-content">
<div class="heading">{{ 'confirm-delete-dossier-state.warning' | translate: translateArgs }}</div>
<div class="replacement-suggestion">{{ 'confirm-delete-dossier-state.suggestion' | translate }}</div>
<form [formGroup]="form">
<div class="flex">
<div class="iqser-input-group required w-300">
<label translate="confirm-delete-dossier-state.form.status"></label>
<mat-select
formControlName="replaceDossierStatusId"
[placeholder]="'confirm-delete-dossier-state.form.status-placeholder' | translate"
>
<mat-option *ngFor="let state of data.otherStates" [value]="state.dossierStatusId">
{{ state.name }}
</mat-option>
</mat-select>
</div>
</div>
</form>
</div>
<div class="dialog-actions">
<button (click)="dialogRef.close(true)" color="primary" mat-flat-button>
{{ 'confirm-delete-dossier-state.delete-only' | translate }}
</button>
<button (click)="dialogRef.close(replaceDossierStatusId)" mat-flat-button [disabled]="!replaceDossierStatusId">
{{ 'confirm-delete-dossier-state.delete-replace' | translate }}
</button>
<div (click)="dialogRef.close()" [translate]="'confirm-delete-dossier-state.cancel'" class="all-caps-label cancel"></div>
</div>
<iqser-circle-button class="dialog-close" icon="iqser:close" mat-dialog-close></iqser-circle-button>
</section>

View File

@ -0,0 +1,16 @@
@use 'variables';
.replacement-suggestion {
font-size: 13px;
line-height: 18px;
color: variables.$grey-1;
margin-bottom: 24px;
}
.dialog-header {
color: variables.$primary;
}
.heading {
margin-bottom: 8px;
}

View File

@ -0,0 +1,46 @@
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
import { IDossierState } from '../../../../../../../../libs/red-domain/src/lib/dossier-state';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { FormBuilder, FormGroup } from '@angular/forms';
interface DialogData {
toBeDeletedState: IDossierState;
otherStates: IDossierState[];
dossierCount: number;
}
@Component({
selector: 'redaction-confirm-delete-dossier-state-dialog',
templateUrl: './confirm-delete-dossier-state-dialog.component.html',
styleUrls: ['./confirm-delete-dossier-state-dialog.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ConfirmDeleteDossierStateDialogComponent {
readonly form: FormGroup;
constructor(
private readonly _formBuilder: FormBuilder,
readonly dialogRef: MatDialogRef<ConfirmDeleteDossierStateDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: DialogData,
) {
this.form = this._getForm();
console.log(data);
}
private _getForm(): FormGroup {
return this._formBuilder.group({
replaceDossierStatusId: [null],
});
}
get translateArgs() {
return {
name: this.data.toBeDeletedState.name,
count: this.data.dossierCount,
};
}
get replaceDossierStatusId(): string {
return this.form.get('replaceDossierStatusId').value;
}
}

View File

@ -72,6 +72,12 @@
[type]="circleButtonTypes.dark"
icon="iqser:edit"
></iqser-circle-button>
<iqser-circle-button
(action)="openConfirmDeleteStateDialog($event, state)"
[tooltip]="'dossier-states-listing.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:trash"
></iqser-circle-button>
</div>
</div>
</div>

View File

@ -6,6 +6,7 @@ import {
ListingComponent,
LoadingService,
TableColumnConfig,
Toaster,
} from '../../../../../../../../libs/common-ui/src';
import { DossierState, IDossierState } from '../../../../../../../../libs/red-domain/src/lib/dossier-state';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
@ -16,6 +17,7 @@ import { DossierTemplatesService } from '../../../../services/entity-services/do
import { AdminDialogService } from '../../services/admin-dialog.service';
import { UserService } from '../../../../services/user.service';
import { AppStateService } from '../../../../state/app-state.service';
import { HttpStatusCode } from '@angular/common/http';
@Component({
templateUrl: './dossier-states-listing-screen.component.html',
@ -45,6 +47,7 @@ export class DossierStatesListingScreenComponent extends ListingComponent<Dossie
private readonly _dialogService: AdminDialogService,
private readonly _userService: UserService,
private readonly _appStateService: AppStateService,
private readonly _toaster: Toaster,
) {
super(_injector);
}
@ -59,26 +62,59 @@ export class DossierStatesListingScreenComponent extends ListingComponent<Dossie
dossierTemplateId: this._dossierTemplatesService.activeDossierTemplateId,
};
this._dialogService.openDialog('addEditDossierState', $event, data, async (newValue: IDossierState) => {
await firstValueFrom(this._dossierStateService.setDossierState(newValue));
await this._appStateService.refreshDossierTemplate(this._dossierTemplatesService.activeDossierTemplateId);
await this._createNewDossierStateAndRefreshView(newValue);
});
}
openConfirmDeleteStateDialog($event: MouseEvent, dossierState: IDossierState) {
const templateId = this._dossierTemplatesService.activeDossierTemplateId;
const data = {
toBeDeletedState: dossierState,
otherStates: this.entitiesService.all.filter(state => state.dossierStatusId !== dossierState.dossierStatusId),
dossierCount: this._getDossiersWithStateAndTemplateCount(dossierState.dossierStatusId, templateId),
};
this._dialogService.openDialog('deleteDossierState', $event, data, async (value: string | true) => {
if (value) {
if (value === true) {
console.log('asteptam');
} else {
await firstValueFrom(this._dossierStateService.deleteAndReplace(dossierState.dossierStatusId, value));
}
}
await this._appStateService.refreshDossierTemplate(templateId);
await this._loadData();
});
}
private async _createNewDossierStateAndRefreshView(newValue: IDossierState): Promise<void> {
await firstValueFrom(this._dossierStateService.setDossierState(newValue)).catch(error => {
if (error.status === HttpStatusCode.Conflict) {
this._toaster.error(_('dossier-states-listing.error.conflict'));
} else {
this._toaster.error(_('dossier-states-listing.error.generic'));
}
});
await this._appStateService.refreshDossierTemplate(this._dossierTemplatesService.activeDossierTemplateId);
await this._loadData();
}
private async _loadData() {
this._loadingService.start();
try {
const templateId = this._dossierTemplatesService.activeDossierTemplateId;
const dossierStates = await firstValueFrom(this._dossierStateService.loadAll(`dossier-status/dossier-template/${templateId}`));
const dossiers = this._dossiersService.all;
const dossierStates = await firstValueFrom(this._dossierStateService.loadAllForTemplate(templateId));
dossierStates.forEach(state => {
state.dossierCount = dossiers.filter(
dossier => dossier.dossierStatusId === state.dossierStatusId && dossier.dossierTemplateId === templateId,
).length;
state.dossierCount = this._getDossiersWithStateAndTemplateCount(state.dossierStatusId, templateId);
});
this.entitiesService.setEntities(dossierStates || []);
} catch (e) {}
this._loadingService.stop();
}
private _getDossiersWithStateAndTemplateCount(dossierStatusId: string, templateId: string) {
const dossiers = this._dossiersService.all;
return dossiers.filter(dossier => dossier.dossierStatusId === dossierStatusId && dossier.dossierTemplateId === templateId).length;
}
}

View File

@ -14,6 +14,7 @@ import { ConfirmationDialogComponent, DialogConfig, DialogService, largeDialogCo
import { UploadDictionaryDialogComponent } from '../dialogs/upload-dictionary-dialog/upload-dictionary-dialog.component';
import { FileAttributesConfigurationsDialogComponent } from '../dialogs/file-attributes-configurations-dialog/file-attributes-configurations-dialog.component';
import { AddEditDossierStateDialogComponent } from '../dialogs/add-edit-dossier-state-dialog/add-edit-dossier-state-dialog.component';
import { ConfirmDeleteDossierStateDialogComponent } from '../dialogs/confirm-delete-dossier-state-dialog/confirm-delete-dossier-state-dialog.component';
type DialogType =
| 'confirm'
@ -30,7 +31,8 @@ type DialogType =
| 'addEditDossierAttribute'
| 'addEditJustification'
| 'uploadDictionary'
| 'addEditDossierState';
| 'addEditDossierState'
| 'deleteDossierState';
@Injectable()
export class AdminDialogService extends DialogService<DialogType> {
@ -88,6 +90,9 @@ export class AdminDialogService extends DialogService<DialogType> {
addEditDossierState: {
component: AddEditDossierStateDialogComponent,
},
deleteDossierState: {
component: ConfirmDeleteDossierStateDialogComponent,
},
};
constructor(protected readonly _dialog: MatDialog) {

View File

@ -0,0 +1,4 @@
<div class="flex-align-items-center dossier-status-container">
<div class="dossier-status-text">{{ dossierState.name }}</div>
<div class="dossier-status-chip" [style.background-color]="dossierState.description"></div>
</div>

View File

@ -0,0 +1,19 @@
@use 'variables';
.dossier-status-container {
justify-content: flex-end;
width: 100%;
}
.dossier-status-chip {
width: 12px;
height: 6px;
border-radius: 6px;
margin-left: 8px;
}
.dossier-status-text {
font-size: 13px;
line-height: 16px;
color: variables.$grey-1;
}

View File

@ -0,0 +1,12 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { DossierState } from '../../../../../../../../../../libs/red-domain/src/lib/dossier-state';
@Component({
selector: 'redaction-dossiers-listing-status',
templateUrl: './dossiers-listing-status.component.html',
styleUrls: ['./dossiers-listing-status.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DossiersListingStatusComponent {
@Input() dossierState: DossierState;
}

View File

@ -14,4 +14,8 @@
<div class="cell status-container">
<redaction-dossiers-listing-actions [dossier]="dossier" [stats]="stats"></redaction-dossiers-listing-actions>
</div>
<div class="cell">
<redaction-dossiers-listing-status [dossierState]="states[0]"></redaction-dossiers-listing-status>
</div>
</ng-container>

View File

@ -1,8 +1,10 @@
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit } from '@angular/core';
import { Dossier, DossierStats } from '@red/domain';
import { DossierStatsService } from '@services/entity-services/dossier-stats.service';
import { BehaviorSubject, Observable } from 'rxjs';
import { BehaviorSubject, firstValueFrom, Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { DossierStateService } from '../../../../../../services/entity-services/dossier-state.service';
import { DossierState } from '../../../../../../../../../../libs/red-domain/src/lib/dossier-state';
@Component({
selector: 'redaction-table-item [dossier]',
@ -10,13 +12,14 @@ import { switchMap } from 'rxjs/operators';
styleUrls: ['./table-item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TableItemComponent implements OnChanges {
export class TableItemComponent implements OnChanges, OnInit {
@Input() dossier!: Dossier;
states: DossierState[];
readonly stats$: Observable<DossierStats>;
private readonly _ngOnChanges$ = new BehaviorSubject<string>(undefined);
constructor(readonly dossierStatsService: DossierStatsService) {
constructor(readonly dossierStatsService: DossierStatsService, readonly dossierStateService: DossierStateService) {
this.stats$ = this._ngOnChanges$.pipe(switchMap(dossierId => this.dossierStatsService.watch$(dossierId)));
}
@ -25,4 +28,9 @@ export class TableItemComponent implements OnChanges {
this._ngOnChanges$.next(this.dossier.dossierId);
}
}
async ngOnInit(): Promise<void> {
this.states = await firstValueFrom(this.dossierStateService.loadAllForTemplate('b3413395-8511-4a45-b0eb-b103012b4d8a'));
console.log(this.states);
}
}

View File

@ -26,7 +26,8 @@ export class ConfigService {
{ label: _('dossier-listing.table-col-names.name'), sortByKey: 'searchKey', width: '2fr' },
{ label: _('dossier-listing.table-col-names.needs-work') },
{ label: _('dossier-listing.table-col-names.owner'), class: 'user-column' },
{ label: _('dossier-listing.table-col-names.status'), class: 'flex-end', width: 'auto' },
{ label: _('dossier-listing.table-col-names.documents-status'), class: 'flex-end', width: 'auto' },
{ label: _('dossier-listing.table-col-names.dossier-status'), class: 'flex-end' },
];
}

View File

@ -12,6 +12,7 @@ import { ConfigService } from './config.service';
import { TableItemComponent } from './components/table-item/table-item.component';
import { SharedDossiersModule } from '../../shared/shared-dossiers.module';
import { DossierWorkloadColumnComponent } from './components/dossier-workload-column/dossier-workload-column.component';
import { DossiersListingStatusComponent } from './components/dossiers-listing-status/dossiers-listing-status.component';
const routes: Routes = [
{
@ -30,6 +31,7 @@ const routes: Routes = [
DossiersListingDossierNameComponent,
DossierWorkloadColumnComponent,
TableItemComponent,
DossiersListingStatusComponent,
],
providers: [ConfigService],
imports: [RouterModule.forChild(routes), CommonModule, SharedModule, SharedDossiersModule, IqserIconsModule, TranslateModule],

View File

@ -1,6 +1,7 @@
import { Injectable, Injector } from '@angular/core';
import { EntitiesService, RequiredParam, Validate } from '../../../../../../libs/common-ui/src';
import { DossierState, IDossierState } from '../../../../../../libs/red-domain/src/lib/dossier-state';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root',
@ -14,4 +15,20 @@ export class DossierStateService extends EntitiesService<DossierState, IDossierS
setDossierState(@RequiredParam() body: IDossierState) {
return this._post<unknown>(body, this._defaultModelPath);
}
@Validate()
loadAllForTemplate(@RequiredParam() templateId: string) {
return this.loadAll(`${this._defaultModelPath}/dossier-template/${templateId}`);
}
@Validate()
deleteAndReplace(@RequiredParam() dossierStatusId: string, @RequiredParam() replaceDossierStatusId: string) {
const url = `${this._defaultModelPath}/${dossierStatusId}?replaceDossierStatusId=${replaceDossierStatusId}`;
return this.delete({}, url);
}
@Validate()
getById(@RequiredParam() id: string): Observable<DossierState> {
return this._getOne([id]);
}
}

View File

@ -421,6 +421,18 @@
"toast-error": "Please confirm that you understand the ramifications of your action!",
"warning": "Warning: this cannot be undone!"
},
"confirm-delete-dossier-state": {
"title": "Delete Dossier Status",
"warning": "The {name} status is assigned to {count} Dossiers.",
"suggestion": "Would you like to replace the states of the Dossiers with another status?",
"form": {
"status": "Replace Status",
"status-placeholder": "Choose another status"
},
"delete-only": "Delete Only",
"delete-replace": "Delete and Replace",
"cancel": "Cancel"
},
"confirm-delete-users": {
"cancel": "Keep {usersCount, plural, one{User} other{Users}}",
"delete": "Delete {usersCount, plural, one{User} other{Users}}",
@ -628,6 +640,10 @@
"delete": "Delete Status",
"edit": "Edit Status"
},
"error": {
"conflict": "Dossier State with this name already exists!",
"generic": "Failed to add Dossier State"
},
"search": "Search...",
"table-col-names": {
"name": "Name",
@ -732,7 +748,8 @@
"name": "Name",
"needs-work": "Workload",
"owner": "Owner",
"status": "Status"
"documents-status": "Documents Status",
"dossier-status": "Dossier Status"
},
"table-header": {
"title": "{length} active {length, plural, one{Dossier} other{Dossiers}}"