RED-10064: added id on report container for hover + component refactor.

This commit is contained in:
Nicoleta Panaghiu 2024-09-26 14:00:06 +03:00
parent 5bb7c780a1
commit b3de35eac7
2 changed files with 101 additions and 84 deletions

View File

@ -2,67 +2,74 @@
<div [translate]="'reports-screen.title'" class="heading-xl"></div>
<div [translate]="'reports-screen.setup'" class="description"></div>
<div *ngIf="!isDocumine" [translate]="'reports-screen.description'" class="description"></div>
<div *ngIf="!isDocumine && placeholders$ | async as placeholders" class="placeholders">
<div [translate]="'reports-screen.table-header.placeholders'" class="all-caps-label"></div>
<div [translate]="'reports-screen.table-header.description'" class="all-caps-label"></div>
<ng-container *ngFor="let placeholder of placeholders">
<div class="placeholder">{{ placeholder.placeholder }}</div>
<div
[innerHTML]="placeholder.descriptionTranslation | translate: { attribute: placeholder.attributeName }"
class="description"
></div>
</ng-container>
</div>
@if (!isDocumine) {
<div [translate]="'reports-screen.description'" class="description"></div>
}
@if (!isDocumine && placeholders$ | async; as placeholders) {
<div class="placeholders">
<div [translate]="'reports-screen.table-header.placeholders'" class="all-caps-label"></div>
<div [translate]="'reports-screen.table-header.description'" class="all-caps-label"></div>
@for (placeholder of placeholders; track placeholder.placeholder) {
<div class="placeholder">{{ placeholder.placeholder }}</div>
<div
[innerHTML]="placeholder.descriptionTranslation | translate: { attribute: placeholder.attributeName }"
class="description"
></div>
}
</div>
}
</div>
<div *ngIf="availableTemplates$ | async as availableTemplates" class="right-container" iqserHasScrollbar>
<div class="header">
<div [translate]="'reports-screen.report-documents'" class="heading"></div>
<iqser-circle-button
(action)="fileInput.click()"
*allow="roles.reportTemplates.upload; if: currentUser.isAdmin"
[tooltip]="'reports-screen.upload-document' | translate"
[attr.help-mode-key]="'upload_report'"
[buttonId]="'upload_report'"
icon="iqser:upload"
></iqser-circle-button>
</div>
<div
(click)="fileInput.click()"
*allow="roles.reportTemplates.upload; if: currentUser.isAdmin && !availableTemplates?.length"
[translate]="'reports-screen.upload-document'"
class="template upload-button"
></div>
<div *ngFor="let template of availableTemplates" class="template">
<div class="name">
{{ template.fileName }} {{ template.multiFileReport ? ('reports-screen.multi-file-report' | translate) : '' }}
</div>
<div class="actions">
<iqser-circle-button
(action)="download(template)"
*allow="roles.reportTemplates.download"
[buttonId]="(template.fileName | snakeCase) + '-download-button'"
[iconSize]="12"
[size]="18"
icon="iqser:download"
></iqser-circle-button>
@if (availableTemplates$ | async; as availableTemplates) {
<div class="right-container" iqserHasScrollbar>
<div class="header">
<div [translate]="'reports-screen.report-documents'" class="heading"></div>
<iqser-circle-button
(action)="deleteTemplate(template)"
*allow="roles.reportTemplates.delete; if: currentUser.isAdmin"
[buttonId]="(template.fileName | snakeCase) + '-delete-button'"
[iconSize]="12"
[size]="18"
icon="iqser:trash"
(action)="fileInput.click()"
*allow="roles.reportTemplates.upload; if: currentUser.isAdmin"
[tooltip]="'reports-screen.upload-document' | translate"
[attr.help-mode-key]="'upload_report'"
[buttonId]="'upload_report'"
icon="iqser:upload"
></iqser-circle-button>
</div>
<div
(click)="fileInput.click()"
*allow="roles.reportTemplates.upload; if: currentUser.isAdmin && !availableTemplates?.length"
[translate]="'reports-screen.upload-document'"
class="template upload-button"
></div>
@for (template of availableTemplates; track template.templateId) {
<div [id]="template.fileName | snakeCase" class="template">
<div class="name">
{{ template.fileName }}
</div>
<div class="actions">
<iqser-circle-button
(action)="download(template)"
*allow="roles.reportTemplates.download"
[buttonId]="(template.fileName | snakeCase) + '-download-button'"
[iconSize]="12"
[size]="18"
icon="iqser:download"
></iqser-circle-button>
<iqser-circle-button
(action)="deleteTemplate(template)"
*allow="roles.reportTemplates.delete; if: currentUser.isAdmin"
[buttonId]="(template.fileName | snakeCase) + '-delete-button'"
[iconSize]="12"
[size]="18"
icon="iqser:trash"
></iqser-circle-button>
</div>
</div>
}
</div>
</div>
}
<input #fileInput (change)="uploadTemplate($event)" hidden type="file" />

View File

@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { ChangeDetectionStrategy, Component, ElementRef, inject, OnInit, viewChild } from '@angular/core';
import { DOSSIER_TEMPLATE_ID, IPlaceholdersResponse, IReportTemplate, User } from '@red/domain';
import { download } from '@utils/file-download-utils';
import {
@ -23,8 +23,8 @@ import { BehaviorSubject, firstValueFrom } from 'rxjs';
import { Roles } from '@users/roles';
import { getCurrentUser } from '@iqser/common-ui/lib/users';
import { getParam } from '@iqser/common-ui/lib/utils';
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { AsyncPipe } from '@angular/common';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { SnakeCasePipe } from '@common-ui/pipes/snake-case.pipe';
interface Placeholder {
@ -42,15 +42,16 @@ const placeholderTypes: PlaceholderType[] = ['generalPlaceholders', 'fileAttribu
styleUrls: ['./reports-screen.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [HasScrollbarDirective, NgIf, NgForOf, AsyncPipe, TranslateModule, CircleButtonComponent, IqserAllowDirective, SnakeCasePipe],
imports: [HasScrollbarDirective, AsyncPipe, TranslateModule, CircleButtonComponent, IqserAllowDirective, SnakeCasePipe],
})
export default class ReportsScreenComponent implements OnInit {
@ViewChild('fileInput') private readonly _fileInput: ElementRef;
readonly placeholders$ = new BehaviorSubject<Placeholder[]>([]);
readonly availableTemplates$ = new BehaviorSubject<IReportTemplate[]>([]);
readonly currentUser = getCurrentUser<User>();
readonly roles = Roles;
readonly isDocumine = getConfig().IS_DOCUMINE;
readonly #translateService = inject(TranslateService);
private readonly _fileInput = viewChild<ElementRef>('fileInput');
readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);
constructor(
@ -63,8 +64,8 @@ export default class ReportsScreenComponent implements OnInit {
async ngOnInit() {
this._loadingService.start();
await this._loadReportTemplates();
await this._loadPlaceholders();
await this.#loadReportTemplates();
await this.#loadPlaceholders();
this._loadingService.stop();
}
@ -84,14 +85,14 @@ export default class ReportsScreenComponent implements OnInit {
deleteTemplate(template: IReportTemplate) {
this._dialogService.openDialog('confirm', null, () => {
this._loadingService.loadWhile(this._deleteTemplate(template));
this._loadingService.loadWhile(this.#deleteTemplate(template));
});
}
uploadTemplate($event) {
const file: File = $event.target.files[0];
if (!this._isValidFile(file)) {
if (!this.#isValidFile(file)) {
this._toaster.error(_('reports-screen.invalid-upload'));
return;
}
@ -115,27 +116,31 @@ export default class ReportsScreenComponent implements OnInit {
template => template.fileName === file.name && template.multiFileReport === multiFileReport,
)
) {
await this._openOverwriteConfirmationDialog(file, multiFileReport);
await this.#openOverwriteConfirmationDialog(file, multiFileReport);
} else {
await this._uploadTemplateForm(file, multiFileReport);
await this.#uploadTemplateForm(file, multiFileReport);
}
}
});
this._fileInput.nativeElement.value = null;
this._fileInput().nativeElement.value = null;
}
private _getAttributeName(placeholder: string): string {
#getAttributeName(placeholder: string): string {
return removeBraces(placeholder).split('.').pop();
}
private _getPlaceholderDescriptionTranslation(type: PlaceholderType, placeholder: string): string {
#getPlaceholderDescriptionTranslation(type: PlaceholderType, placeholder: string): string {
return type === 'generalPlaceholders'
? generalPlaceholdersDescriptionsTranslations[removeBraces(placeholder)]
: placeholdersDescriptionsTranslations[type];
}
private async _openOverwriteConfirmationDialog(file: File, multiFileReport: boolean): Promise<void> {
#getTemplateFilename(template: IReportTemplate): string {
return `${template.fileName} ${template.multiFileReport ? this.#translateService.instant(_('reports-screen.multi-file-report')) : ''}`.trim();
}
async #openOverwriteConfirmationDialog(file: File, multiFileReport: boolean): Promise<void> {
const data: IConfirmationDialogData = {
title: _('confirmation-dialog.report-template-same-name.title'),
question: _('confirmation-dialog.report-template-same-name.question'),
@ -148,29 +153,34 @@ export default class ReportsScreenComponent implements OnInit {
this._dialogService.openDialog('confirm', data, null, async result => {
if (result) {
await this._uploadTemplateForm(file, multiFileReport);
await this.#uploadTemplateForm(file, multiFileReport);
}
});
}
private async _uploadTemplateForm(file: File, multiFileReport: boolean): Promise<void> {
async #uploadTemplateForm(file: File, multiFileReport: boolean): Promise<void> {
this._loadingService.start();
await firstValueFrom(this._reportTemplateService.uploadTemplateForm(this.#dossierTemplateId, multiFileReport, file));
await this._loadReportTemplates();
await this.#loadReportTemplates();
this._loadingService.stop();
}
private async _deleteTemplate(template: IReportTemplate) {
async #deleteTemplate(template: IReportTemplate) {
await firstValueFrom(this._reportTemplateService.delete(template.dossierTemplateId, template.templateId));
await this._loadReportTemplates();
await this.#loadReportTemplates();
}
private async _loadReportTemplates() {
async #loadReportTemplates() {
const reportTemplates = await this._reportTemplateService.getAvailableReportTemplates(this.#dossierTemplateId);
this.availableTemplates$.next(reportTemplates);
this.availableTemplates$.next(
reportTemplates.map(template => ({
...template,
fileName: this.#getTemplateFilename(template),
})),
);
}
private async _loadPlaceholders() {
async #loadPlaceholders() {
const placeholdersResponse: IPlaceholdersResponse = await firstValueFrom(
this._reportTemplateService.getAvailablePlaceholders(this.#dossierTemplateId),
);
@ -178,25 +188,25 @@ export default class ReportsScreenComponent implements OnInit {
placeholderTypes.flatMap(type =>
placeholdersResponse[type].map(placeholder => ({
placeholder,
descriptionTranslation: this._getPlaceholderDescriptionTranslation(type, placeholder),
attributeName: this._getAttributeName(placeholder),
descriptionTranslation: this.#getPlaceholderDescriptionTranslation(type, placeholder),
attributeName: this.#getAttributeName(placeholder),
})),
),
);
}
private _isValidFile(file: File): boolean {
return this._isExcelFile(file) || this._isWordFile(file);
#isValidFile(file: File): boolean {
return this.#isExcelFile(file) || this.#isWordFile(file);
}
private _isExcelFile(file: File): boolean {
#isExcelFile(file: File): boolean {
return (
file.type?.toLowerCase() === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
file.name.toLowerCase().endsWith('.xlsx')
);
}
private _isWordFile(file: File): boolean {
#isWordFile(file: File): boolean {
return (
file.type?.toLowerCase() === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
file.name.toLowerCase().endsWith('.docx')