From 054573f86cb4eb8b7880620ad7e04ac6ffcdf93a Mon Sep 17 00:00:00 2001 From: mbritense <79840403+mbritense@users.noreply.github.com> Date: Wed, 8 May 2024 14:27:17 +0200 Subject: [PATCH] cherrypick (#984) --- .../components/form-io/form-io.component.ts | 22 +++--- .../services/form-io-local-storage.service.ts | 68 +++++++++++++++++++ 2 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 projects/valtimo/components/src/lib/components/form-io/services/form-io-local-storage.service.ts diff --git a/projects/valtimo/components/src/lib/components/form-io/form-io.component.ts b/projects/valtimo/components/src/lib/components/form-io/form-io.component.ts index 358a4b8eb..3a70a121a 100644 --- a/projects/valtimo/components/src/lib/components/form-io/form-io.component.ts +++ b/projects/valtimo/components/src/lib/components/form-io/form-io.component.ts @@ -32,10 +32,9 @@ import { Formio, FormioComponent as FormIoSourceComponent, FormioOptions, + FormioRefreshValue, FormioSubmission, - FormioUtils, } from '@formio/angular'; -import {FormioRefreshValue} from '@formio/angular/formio.common'; import {jwtDecode} from 'jwt-decode'; import {NGXLogger} from 'ngx-logger'; import {BehaviorSubject, combineLatest, Observable, Subject, Subscription, timer} from 'rxjs'; @@ -43,6 +42,7 @@ import {distinctUntilChanged, map, switchMap, take, tap} from 'rxjs/operators'; import {FormIoStateService} from './services/form-io-state.service'; import {ActivatedRoute} from '@angular/router'; import {TranslateService} from '@ngx-translate/core'; +import {FormIoLocalStorageService} from './services/form-io-local-storage.service'; import {deepmerge} from 'deepmerge-ts'; import {ConfigService, ValtimoConfig} from '@valtimo/config'; @@ -50,6 +50,7 @@ import {ConfigService, ValtimoConfig} from '@valtimo/config'; selector: 'valtimo-form-io', templateUrl: './form-io.component.html', styleUrls: ['./form-io.component.css'], + providers: [FormIoLocalStorageService], }) export class FormioComponent implements OnInit, OnChanges, OnDestroy { @Input() set options(optionsValue: ValtimoFormioOptions) { @@ -73,7 +74,7 @@ export class FormioComponent implements OnInit, OnChanges, OnDestroy { @HostListener('window:beforeunload', ['$event']) private handleBeforeUnload() { - this.clearTokenFromLocalStorage(); + this.localStorageService.clearTokenFromLocalStorage(); } public refreshForm = new EventEmitter(); @@ -83,7 +84,6 @@ export class FormioComponent implements OnInit, OnChanges, OnDestroy { public readonly options$ = new BehaviorSubject(undefined); public readonly readOnly$ = new BehaviorSubject(false); public readonly errors$ = new BehaviorSubject>([]); - public readonly tokenSetInLocalStorage$ = new BehaviorSubject(false); public readonly currentLanguage$ = this.translateService.stream('key').pipe( map(() => this.translateService.currentLang), @@ -115,19 +115,20 @@ export class FormioComponent implements OnInit, OnChanges, OnDestroy { tap(options => this.logger.debug('Form.IO options used', options)) ); + public readonly tokenSetInLocalStorage$ = this.localStorageService.tokenSetInLocalStorage$; + private _tokenRefreshTimerSubscription!: Subscription; private _formRefreshSubscription!: Subscription; private readonly _subscriptions = new Subscription(); private readonly _tokenTimerSubscription = new Subscription(); - private readonly _FORMIO_TOKEN_LOCAL_STORAGE_KEY = 'formioToken'; - constructor( private readonly userProviderService: UserProviderService, private readonly logger: NGXLogger, private readonly stateService: FormIoStateService, private readonly route: ActivatedRoute, private readonly translateService: TranslateService, + private readonly localStorageService: FormIoLocalStorageService, private readonly modalService: ValtimoModalService, private readonly configService: ConfigService ) { @@ -157,7 +158,7 @@ export class FormioComponent implements OnInit, OnChanges, OnDestroy { this.unsubscribeFormRefresh(); this._tokenRefreshTimerSubscription?.unsubscribe(); this._subscriptions.unsubscribe(); - this.clearTokenFromLocalStorage(); + this.localStorageService.clearTokenFromLocalStorage(); } public showErrors(errors: string[]): void { @@ -218,9 +219,8 @@ export class FormioComponent implements OnInit, OnChanges, OnDestroy { private setToken(token: string): void { Formio.setUser(jwtDecode(token)); Formio.setToken(token); - localStorage.setItem(this._FORMIO_TOKEN_LOCAL_STORAGE_KEY, token); this.setTimerForTokenRefresh(token); - this.tokenSetInLocalStorage$.next(true); + this.localStorageService.setTokenInLocalStorage(token); this.logger.debug('New token set for form.io.'); } @@ -277,10 +277,6 @@ export class FormioComponent implements OnInit, OnChanges, OnDestroy { ); } - private clearTokenFromLocalStorage(): void { - localStorage.removeItem(this._FORMIO_TOKEN_LOCAL_STORAGE_KEY); - } - private setOverrideOptions(config: ValtimoConfig): void { if (!config.formioOptions) return; diff --git a/projects/valtimo/components/src/lib/components/form-io/services/form-io-local-storage.service.ts b/projects/valtimo/components/src/lib/components/form-io/services/form-io-local-storage.service.ts new file mode 100644 index 000000000..43a1afd85 --- /dev/null +++ b/projects/valtimo/components/src/lib/components/form-io/services/form-io-local-storage.service.ts @@ -0,0 +1,68 @@ +/* + * Copyright 2015-2024 Ritense BV, the Netherlands. + * + * Licensed under EUPL, Version 1.2 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Injectable} from '@angular/core'; +import {BehaviorSubject, Observable} from 'rxjs'; + +@Injectable() +export class FormIoLocalStorageService { + private readonly _FORMIO_TOKEN_LOCAL_STORAGE_KEY = 'formioToken'; + private readonly _tokenSetInLocalStorage$ = new BehaviorSubject(false); + + public get tokenSetInLocalStorage$(): Observable { + return this._tokenSetInLocalStorage$.asObservable(); + } + + public setTokenInLocalStorage(token: string): void { + setTimeout(() => { + localStorage.setItem(this._FORMIO_TOKEN_LOCAL_STORAGE_KEY, token); + this.checkIfTokenExistsInLocalStorage(); + }); + } + + public clearTokenFromLocalStorage(): void { + localStorage.removeItem(this._FORMIO_TOKEN_LOCAL_STORAGE_KEY); + this.checkIfTokenIsRemovedFromLocalStorage(); + } + + private getTokenFromLocalStorage(): string | null { + return localStorage.getItem(this._FORMIO_TOKEN_LOCAL_STORAGE_KEY); + } + + private checkIfTokenExistsInLocalStorage(): void { + const maxChecks = 100; + let checks = 0; + + if (this.getTokenFromLocalStorage()) { + this._tokenSetInLocalStorage$.next(true); + } else if (checks <= maxChecks) { + checks++; + this.checkIfTokenExistsInLocalStorage(); + } + } + + private checkIfTokenIsRemovedFromLocalStorage(): void { + const maxChecks = 100; + let checks = 0; + + if (this.getTokenFromLocalStorage() && checks <= maxChecks) { + checks++; + this.checkIfTokenIsRemovedFromLocalStorage(); + } else { + this._tokenSetInLocalStorage$.next(false); + } + } +}