mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
feat: implement user storage provider with clear functionality and update root state service for local storage integration
This commit is contained in:
@@ -1,28 +1,32 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Logger, LogLevel } from '@core/logger';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { UserStateService } from '@generated/swagger/isa-api';
|
||||
import { debounceTime, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { RootState } from './root.state';
|
||||
import packageInfo from 'packageJson';
|
||||
import { environment } from '../../environments/environment';
|
||||
import { Subject } from 'rxjs';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { injectStorage, UserStorageProvider } from '@isa/core/storage';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class RootStateService {
|
||||
static LOCAL_STORAGE_KEY = 'ISA_APP_INITIALSTATE';
|
||||
|
||||
#storage = injectStorage(UserStorageProvider);
|
||||
|
||||
private _cancelSave = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private readonly _authService: AuthService,
|
||||
private readonly _userStateService: UserStateService,
|
||||
private _logger: Logger,
|
||||
private _store: Store,
|
||||
) {
|
||||
if (!environment.production) {
|
||||
console.log('Die UserState kann in der Konsole mit der Funktion "clearUserState()" geleert werden.');
|
||||
console.log(
|
||||
'Die UserState kann in der Konsole mit der Funktion "clearUserState()" geleert werden.',
|
||||
);
|
||||
}
|
||||
|
||||
window['clearUserState'] = () => {
|
||||
@@ -43,13 +47,17 @@ export class RootStateService {
|
||||
takeUntil(this._cancelSave),
|
||||
debounceTime(1000),
|
||||
switchMap((state) => {
|
||||
const raw = JSON.stringify({
|
||||
const data = {
|
||||
...state,
|
||||
version: packageInfo.version,
|
||||
sub: this._authService.getClaimByKey('sub'),
|
||||
};
|
||||
RootStateService.SaveToLocalStorageRaw(JSON.stringify(data));
|
||||
return this.#storage.set('state', {
|
||||
...state,
|
||||
version: packageInfo.version,
|
||||
sub: this._authService.getClaimByKey('sub'),
|
||||
});
|
||||
RootStateService.SaveToLocalStorageRaw(raw);
|
||||
return this._userStateService.UserStateSetUserState({ content: raw });
|
||||
}),
|
||||
)
|
||||
.subscribe();
|
||||
@@ -60,16 +68,15 @@ export class RootStateService {
|
||||
*/
|
||||
async load(): Promise<boolean> {
|
||||
try {
|
||||
const res = await this._userStateService.UserStateGetUserState().toPromise();
|
||||
const res = await this.#storage.get('state');
|
||||
|
||||
const resContent = res?.result?.content ?? null;
|
||||
const storageContent = RootStateService.LoadFromLocalStorageRaw();
|
||||
|
||||
if (resContent) {
|
||||
RootStateService.SaveToLocalStorageRaw(res.result.content);
|
||||
if (res) {
|
||||
RootStateService.SaveToLocalStorageRaw(JSON.stringify(res));
|
||||
}
|
||||
|
||||
if (resContent !== storageContent) {
|
||||
if (!isEqual(res, storageContent)) {
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -81,7 +88,7 @@ export class RootStateService {
|
||||
async clear() {
|
||||
try {
|
||||
this._cancelSave.next();
|
||||
await this._userStateService.UserStateResetUserState().toPromise();
|
||||
await this.#storage.clear('state');
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
RootStateService.RemoveFromLocalStorage();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
@@ -4,3 +4,4 @@ export * from './lib/session.storage-provider';
|
||||
export * from './lib/signal-store-feature';
|
||||
export * from './lib/storage-provider';
|
||||
export * from './lib/storage';
|
||||
export * from './lib/user.storage-provider';
|
||||
|
||||
@@ -58,4 +58,14 @@ export class IDBStorageProvider implements StorageProvider {
|
||||
request.onerror = (event) => reject(event);
|
||||
});
|
||||
}
|
||||
|
||||
async clear(key: string): Promise<void> {
|
||||
const store = await this.getObjectStore('readwrite');
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const request = store.delete(key);
|
||||
request.onsuccess = () => resolve();
|
||||
request.onerror = (event) => reject(event);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,8 @@ export class LocalStorageProvider implements StorageProvider {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
async clear(key: string): Promise<void> {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,4 +13,8 @@ export class SessionStorageProvider implements StorageProvider {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
async clear(key: string): Promise<void> {
|
||||
sessionStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,6 @@ export interface StorageProvider {
|
||||
set(key: string, value: unknown): Promise<void>;
|
||||
|
||||
get(key: string): Promise<unknown>;
|
||||
|
||||
clear(key: string): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,18 @@ export class Storage {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
async clear(token: string | object): Promise<void> {
|
||||
let key: string;
|
||||
|
||||
if (typeof token === 'string') {
|
||||
key = token;
|
||||
} else {
|
||||
key = hash(token);
|
||||
}
|
||||
|
||||
return this.storageProvider.clear(key);
|
||||
}
|
||||
}
|
||||
|
||||
const storageMap = new WeakMap<Type<StorageProvider>, Storage>();
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { StorageProvider } from './storage-provider';
|
||||
import { UserStateService } from '@generated/swagger/isa-api';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { firstValueFrom, map, shareReplay } from 'rxjs';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class UserStorageProvider implements StorageProvider {
|
||||
#userStateService = inject(UserStateService);
|
||||
|
||||
private state$ = this.#userStateService.UserStateGetUserState().pipe(
|
||||
map((res) => {
|
||||
if (res.result?.content) {
|
||||
return JSON.parse(res.result.content);
|
||||
}
|
||||
return {};
|
||||
}),
|
||||
shareReplay(1),
|
||||
);
|
||||
|
||||
async set(key: string, value: unknown): Promise<void> {
|
||||
const current = (await this.get(key)) || {};
|
||||
const current = await firstValueFrom(this.state$);
|
||||
firstValueFrom(
|
||||
this.#userStateService.UserStateSetUserState({
|
||||
content: JSON.stringify({ ...current, [key]: value }),
|
||||
@@ -17,12 +27,14 @@ export class UserStorageProvider implements StorageProvider {
|
||||
}
|
||||
|
||||
async get(key: string): Promise<unknown> {
|
||||
const res = await firstValueFrom(this.#userStateService.UserStateGetUserState());
|
||||
const userState = await firstValueFrom(this.state$);
|
||||
return userState[key];
|
||||
}
|
||||
|
||||
if (res.result?.content) {
|
||||
return JSON.parse(res.result.content)[key];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
async clear(key: string): Promise<void> {
|
||||
|
||||
const current = await firstValueFrom(this.state$);
|
||||
delete current[key];
|
||||
firstValueFrom(this.#userStateService.UserStateResetUserState());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user