RED-6285: fix watermark double save

This commit is contained in:
Dan Percic 2023-03-13 19:29:59 +02:00
parent 8356c86692
commit 5bb46c7c32
2 changed files with 134 additions and 126 deletions

View File

@ -1,8 +1,9 @@
<div class="content-container">
<div class="viewer" id="viewer"></div>
<redaction-paginator *ngIf="loaded$ | async" (changePage)="navigateTo($event)"></redaction-paginator>
<div #viewer class="viewer" id="viewer"></div>
<div *ngIf="changed && currentUser.isAdmin" class="changes-box">
<redaction-paginator (changePage)="navigateTo($event)" *ngIf="loaded$ | async"></redaction-paginator>
<div *ngIf="!!instance && changed && currentUser.isAdmin" class="changes-box">
<iqser-icon-button
(action)="save()"
[disabled]="!valid"
@ -10,6 +11,7 @@
[type]="iconButtonTypes.primary"
icon="iqser:check"
></iqser-icon-button>
<div (click)="revert()" [translate]="'watermark-screen.action.revert'" class="all-caps-label cancel"></div>
</div>
</div>

View File

@ -1,4 +1,4 @@
import { Component, Inject } from '@angular/core';
import { Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core';
import WebViewer, { WebViewerInstance } from '@pdftron/webviewer';
import { HttpClient } from '@angular/common/http';
import { FormBuilder, FormGroup } from '@angular/forms';
@ -19,13 +19,13 @@ import { stampPDFPage } from '@utils/page-stamper';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { WatermarkService } from '@services/entity-services/watermark.service';
import { BehaviorSubject, firstValueFrom, Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
import { LicenseService } from '@services/license.service';
import { UserPreferenceService } from '@users/user-preference.service';
import { Router } from '@angular/router';
import { WatermarksMapService } from '@services/entity-services/watermarks-map.service';
import { ROLES } from '@users/roles';
import { environment } from '@environments/environment';
import { tap } from 'rxjs/operators';
export const DEFAULT_WATERMARK: Partial<IWatermark> = {
text: 'Watermark',
@ -51,10 +51,10 @@ interface WatermarkForm {
templateUrl: './watermark-screen.component.html',
styleUrls: ['./watermark-screen.component.scss'],
})
export class WatermarkScreenComponent {
export class WatermarkScreenComponent implements OnInit {
readonly iconButtonTypes = IconButtonTypes;
readonly currentUser = getCurrentUser<User>();
readonly form = this._getForm();
readonly form = this.#form;
readonly watermark$: Observable<Partial<IWatermark>>;
readonly fontOptions = [
{ value: 'times-new-roman', display: 'Times' },
@ -62,12 +62,12 @@ export class WatermarkScreenComponent {
{ value: 'courier', display: 'Courier' },
];
readonly orientationOptions = ['DIAGONAL', 'HORIZONTAL', 'VERTICAL'];
instance: WebViewerInstance;
readonly loaded$ = new BehaviorSubject(false);
@ViewChild('viewer', { static: true }) private readonly _viewer: ElementRef<HTMLDivElement>;
readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);
readonly #watermarkId = Number(getParam(WATERMARK_ID));
readonly #loaded$ = new BehaviorSubject(false);
readonly loaded$ = this.#loaded$.asObservable();
private _instance: WebViewerInstance;
private _watermark: Partial<IWatermark> = {};
#watermark: Partial<IWatermark> = {};
constructor(
private readonly _http: HttpClient,
@ -80,17 +80,16 @@ export class WatermarkScreenComponent {
private readonly _watermarkService: WatermarkService,
private readonly _userPreferenceService: UserPreferenceService,
private readonly _router: Router,
private readonly _watermarksMapService: WatermarksMapService,
watermarksMapService: WatermarksMapService,
) {
const obs$: Observable<Partial<IWatermark>> = this.#watermarkId
? _watermarksMapService.watch$(this.#dossierTemplateId, this.#watermarkId)
: of(DEFAULT_WATERMARK);
this.watermark$ = obs$.pipe(tap(wm => this._initForm(wm)));
const watermark$ = watermarksMapService.watch$(this.#dossierTemplateId, this.#watermarkId);
const obs$: Observable<Partial<IWatermark>> = this.#watermarkId ? watermark$ : of(DEFAULT_WATERMARK);
this.watermark$ = obs$.pipe(tap(watermark => this.#initForm(watermark)));
}
get changed(): boolean {
for (const key of Object.keys(this.form.getRawValue())) {
if (this._watermark[key] !== this.form.get(key)?.value) {
if (this.#watermark[key] !== this.form.get(key)?.value) {
return true;
}
}
@ -104,114 +103,7 @@ export class WatermarkScreenComponent {
return this.form.valid;
}
@Debounce()
async configChanged() {
await this._drawWatermark();
}
async save(): Promise<void> {
const watermark: IWatermark = {
id: this._watermark.id,
enabled: this._watermark.id ? this._watermark.enabled : true,
dossierTemplateId: this.#dossierTemplateId,
...this.form.getRawValue(),
};
this._loadingService.start();
try {
const updatedWatermark = await this._watermarkService.saveWatermark(watermark);
this._toaster.success(
watermark.id ? _('watermark-screen.action.change-success') : _('watermark-screen.action.created-success'),
);
if (!watermark.id) {
await this._router.navigate([`/main/admin/dossier-templates/${this.#dossierTemplateId}/watermarks/${updatedWatermark.id}`]);
}
} catch (error) {
this._toaster.error(_('watermark-screen.action.error'));
}
this._loadingService.stop();
}
async revert() {
this.form.patchValue({ ...this._watermark });
await this.configChanged();
}
async setValue(type: 'fontType' | 'orientation' | 'hexColor', value: any) {
if (!this.form.get(type).disabled) {
this.form.get(type).setValue(value);
await this.configChanged();
}
}
private async _initForm(watermark: Partial<IWatermark>) {
this._watermark = { ...watermark, dossierTemplateId: this.#dossierTemplateId };
this.form.patchValue({ ...watermark });
await this._loadViewer();
}
private async _loadViewer() {
if (this._instance) {
return;
}
this._instance = await WebViewer(
{
licenseKey: this._licenseService.activeLicenseKey,
path: this._convertPath('/assets/wv-resources'),
css: this._convertPath('/assets/pdftron/stylesheet.css'),
fullAPI: true,
isReadOnly: true,
backendType: 'ems',
},
document.getElementById('viewer'),
);
this._instance.UI.setTheme(this._userPreferenceService.getTheme());
this._instance.Core.documentViewer.addEventListener('documentLoaded', async () => {
this.#loaded$.next(true);
this._loadingService.stop();
await this._drawWatermark();
});
if (environment.production) {
this._instance.Core.setCustomFontURL('https://' + window.location.host + this._convertPath('/assets/pdftron'));
}
this._disableElements();
const request = this._http.get('/assets/pdftron/blank.pdf', {
responseType: 'blob',
});
const blobData = await firstValueFrom(request);
this._instance.UI.loadDocument(blobData, { filename: 'blank.pdf' });
}
private _disableElements() {
this._instance.UI.disableElements(['header', 'toolsHeader', 'pageNavOverlay', 'textPopup']);
}
private async _drawWatermark() {
const pdfNet = this._instance.Core.PDFNet;
const document = await this._instance.Core.documentViewer.getDocument().getPDFDoc();
await stampPDFPage(
document,
pdfNet,
this.form.controls.text.value || '',
this.form.controls.fontSize.value,
this.form.controls.fontType.value,
this.form.controls.orientation.value,
this.form.controls.opacity.value,
this.form.controls.hexColor.value,
[1, 2],
this._licenseService.activeLicenseKey,
);
this._instance.Core.documentViewer.refreshAll();
this._instance.Core.documentViewer.updateView([0, 1], 0);
}
private _getForm() {
get #form() {
const form: FormGroup<AsControl<WatermarkForm>> = this._formBuilder.group({
name: [null],
text: [null],
@ -229,7 +121,121 @@ export class WatermarkScreenComponent {
return form;
}
async ngOnInit() {
await this.#loadViewer();
}
@Debounce()
async configChanged() {
await this.#drawWatermark();
}
async save(): Promise<void> {
const watermark: IWatermark = {
id: this.#watermark.id,
enabled: this.#watermark.id ? this.#watermark.enabled : true,
dossierTemplateId: this.#dossierTemplateId,
...this.form.getRawValue(),
};
this._loadingService.start();
try {
const updatedWatermark = await this._watermarkService.saveWatermark(watermark);
this._toaster.success(
watermark.id ? _('watermark-screen.action.change-success') : _('watermark-screen.action.created-success'),
);
if (!watermark.id) {
await this._router.navigate([`/main/admin/dossier-templates/${this.#dossierTemplateId}/watermarks/${updatedWatermark.id}`]);
}
} catch (error) {
this._toaster.error(_('watermark-screen.action.error'));
}
this._loadingService.stop();
}
async revert() {
this.form.patchValue({ ...this.#watermark });
await this.configChanged();
}
async setValue(type: 'fontType' | 'orientation' | 'hexColor', value: any) {
if (!this.form.get(type).disabled) {
this.form.get(type).setValue(value);
await this.configChanged();
}
}
navigateTo($event: number) {
this._instance.Core.documentViewer.displayPageLocation($event, 0, 0);
this.instance.Core.documentViewer.displayPageLocation($event, 0, 0);
}
async #initForm(watermark: Partial<IWatermark>) {
this.#watermark = { ...watermark, dossierTemplateId: this.#dossierTemplateId };
this.form.patchValue({ ...watermark });
}
async #loadViewer() {
this.instance = await WebViewer(
{
licenseKey: this._licenseService.activeLicenseKey,
path: this._convertPath('/assets/wv-resources'),
css: this._convertPath('/assets/pdftron/stylesheet.css'),
fullAPI: true,
isReadOnly: true,
backendType: 'ems',
},
// use nativeElement instead of document.getElementById('viwer')
// because WebViewer works better with this approach
this._viewer.nativeElement,
);
this.instance.UI.setTheme(this._userPreferenceService.getTheme());
this.instance.Core.documentViewer.addEventListener('documentLoaded', async () => {
this.loaded$.next(true);
this._loadingService.stop();
await this.#drawWatermark();
});
if (environment.production) {
this.instance.Core.setCustomFontURL('https://' + window.location.host + this._convertPath('/assets/pdftron'));
}
this.#disableElements();
await this.#loadDocument();
}
async #loadDocument() {
const request = this._http.get('/assets/pdftron/blank.pdf', {
responseType: 'blob',
});
const blobData = await firstValueFrom(request);
this.instance.UI.loadDocument(blobData, { filename: 'blank.pdf' });
}
#disableElements() {
this.instance.UI.disableElements(['header', 'toolsHeader', 'pageNavOverlay', 'textPopup']);
}
async #drawWatermark() {
const pdfNet = this.instance.Core.PDFNet;
const document = await this.instance.Core.documentViewer.getDocument().getPDFDoc();
await stampPDFPage(
document,
pdfNet,
this.form.controls.text.value || '',
this.form.controls.fontSize.value,
this.form.controls.fontType.value,
this.form.controls.orientation.value,
this.form.controls.opacity.value,
this.form.controls.hexColor.value,
[1, 2],
this._licenseService.activeLicenseKey,
);
this.instance.Core.documentViewer.refreshAll();
this.instance.Core.documentViewer.updateView([0, 1], 0);
}
}