From 3739e7a46891a7f4fddc6da2bd7b913aedae71a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Thu, 5 May 2022 18:01:47 +0300 Subject: [PATCH] RED-3796: Dossiers cache for notifications --- apps/red-ui/src/app/app-routing.module.ts | 5 +- .../notifications/notifications.component.ts | 7 ++- .../app/modules/dashboard/dashboard.module.ts | 5 -- .../dossiers/dossiers-cache.service.ts | 49 +++++++++++++++++++ .../src/app/services/notifications.service.ts | 16 +++--- .../src/lib/dossiers/dossier.model.ts | 15 +++--- 6 files changed, 73 insertions(+), 24 deletions(-) create mode 100644 apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index fde2d9f9c..e4ae72779 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -12,6 +12,7 @@ import { FeaturesGuard } from '@guards/features-guard.service'; import { ARCHIVE_ROUTE, DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE, DOSSIERS_ROUTE } from '@utils/constants'; import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; import { DossierTemplateExistsGuard } from '@guards/dossier-template-exists.guard'; +import { DashboardGuard } from '@guards/dashboard-guard.service'; const routes: Routes = [ { @@ -41,7 +42,7 @@ const routes: Routes = [ loadChildren: () => import('./modules/dashboard/dashboard.module').then(m => m.DashboardModule), canActivate: [CompositeRouteGuard], data: { - routeGuards: [AuthGuard, RedRoleGuard], + routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard, DashboardGuard], requiredRoles: ['RED_USER', 'RED_MANAGER'], }, }, @@ -75,7 +76,7 @@ const routes: Routes = [ ], canActivate: [CompositeRouteGuard], data: { - routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard, DossierTemplateExistsGuard], + routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard, DashboardGuard, DossierTemplateExistsGuard], requiredRoles: ['RED_USER', 'RED_MANAGER'], }, }, diff --git a/apps/red-ui/src/app/components/notifications/notifications.component.ts b/apps/red-ui/src/app/components/notifications/notifications.component.ts index e86ba6b10..ea129b453 100644 --- a/apps/red-ui/src/app/components/notifications/notifications.component.ts +++ b/apps/red-ui/src/app/components/notifications/notifications.component.ts @@ -5,6 +5,7 @@ import { Notification } from '@red/domain'; import { distinctUntilChanged, map } from 'rxjs/operators'; import { firstValueFrom, Observable } from 'rxjs'; import { shareLast } from '@iqser/common-ui'; +import { DossiersCacheService } from '@services/dossiers/dossiers-cache.service'; interface NotificationsGroup { date: string; @@ -21,7 +22,11 @@ export class NotificationsComponent { readonly hasUnreadNotifications$: Observable; readonly groupedNotifications$: Observable; - constructor(private readonly _notificationsService: NotificationsService, private readonly _datePipe: DatePipe) { + constructor( + private readonly _notificationsService: NotificationsService, + private readonly _datePipe: DatePipe, + private readonly _dossiersCacheService: DossiersCacheService, + ) { this.groupedNotifications$ = this._notificationsService.all$.pipe(map(notifications => this._groupNotifications(notifications))); this.hasUnreadNotifications$ = this._hasUnreadNotifications$; } diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts b/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts index 3fcc0de17..db67fc124 100644 --- a/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts +++ b/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts @@ -4,20 +4,15 @@ import { DashboardScreenComponent } from './dashboard-screen/dashboard-screen.co import { RouterModule } from '@angular/router'; import { SharedModule } from '../shared/shared.module'; import { TemplateStatsComponent } from './components/template-stats/template-stats.component'; -import { CompositeRouteGuard } from '@iqser/common-ui'; import { SharedDossiersModule } from '../dossier/shared/shared-dossiers.module'; import { BreadcrumbTypes } from '@red/domain'; -import { DossierTemplatesGuard } from '../../guards/dossier-templates.guard'; -import { DashboardGuard } from '../../guards/dashboard-guard.service'; const routes = [ { path: '', component: DashboardScreenComponent, - canActivate: [CompositeRouteGuard], data: { breadcrumbs: [BreadcrumbTypes.dashboard], - routeGuards: [DossierTemplatesGuard, DashboardGuard], }, }, ]; diff --git a/apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts b/apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts new file mode 100644 index 000000000..72b955c21 --- /dev/null +++ b/apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts @@ -0,0 +1,49 @@ +import { EventEmitter, Injectable } from '@angular/core'; +import { ActiveDossiersService } from './active-dossiers.service'; +import { ArchivedDossiersService } from './archived-dossiers.service'; +import { firstValueFrom, forkJoin, merge } from 'rxjs'; +import { map, skip, take } from 'rxjs/operators'; +import { flatten } from 'lodash-es'; +import { Dossier } from '@red/domain'; + +@Injectable({ + providedIn: 'root', +}) +export class DossiersCacheService { + readonly changed$ = new EventEmitter(); + private _dossiers: Dossier[] = JSON.parse(localStorage.getItem('dossiers')) || []; + + constructor( + private readonly _activeDossiersService: ActiveDossiersService, + private readonly _archivedDossiersService: ArchivedDossiersService, + ) { + // Skip 1 to avoid clearing the cache when the dossier services are initialized + merge(_activeDossiersService.all$.pipe(skip(1)), _archivedDossiersService.all$.pipe(skip(1))).subscribe(() => { + this.set(); + }); + } + + get empty(): boolean { + return !localStorage.getItem('dossiers'); + } + + async load(): Promise { + await firstValueFrom( + forkJoin([this._activeDossiersService.loadAll().pipe(take(1)), this._archivedDossiersService.loadAll().pipe(take(1))]).pipe( + map(list => flatten(list)), + ), + ); + this.set(); + } + + set(): void { + const dossiers = flatten([this._activeDossiersService.all, this._archivedDossiersService.all]); + this._dossiers = dossiers; + localStorage.setItem('dossiers', JSON.stringify(dossiers)); + this.changed$.emit(); + } + + get(dossierId: string) { + return this._dossiers.find(dossier => dossier.dossierId === dossierId); + } +} diff --git a/apps/red-ui/src/app/services/notifications.service.ts b/apps/red-ui/src/app/services/notifications.service.ts index e68359f12..2356cd6c1 100644 --- a/apps/red-ui/src/app/services/notifications.service.ts +++ b/apps/red-ui/src/app/services/notifications.service.ts @@ -6,12 +6,11 @@ import { Dossier, INotification, Notification, NotificationTypes } from '@red/do import { map, switchMap, tap } from 'rxjs/operators'; import { notificationsTranslations } from '../translations/notifications-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { ActiveDossiersService } from './dossiers/active-dossiers.service'; import { UserService } from '@services/user.service'; import dayjs from 'dayjs'; import { CHANGED_CHECK_INTERVAL } from '@utils/constants'; import { BASE_HREF } from '../tokens'; -import { ArchivedDossiersService } from '@services/dossiers/archived-dossiers.service'; +import { DossiersCacheService } from '@services/dossiers/dossiers-cache.service'; const INCLUDE_SEEN = false; @@ -23,19 +22,22 @@ export class NotificationsService extends EntitiesService (this._activeDossiersService.all.length ? of(null) : this._activeDossiersService.loadAll())), - switchMap(() => (this._archivedDossiersService.all.length ? of(null) : this._archivedDossiersService.loadAll())), + switchMap(() => (this._dossiersCacheService.empty ? this._dossiersCacheService.load() : of(null))), switchMap(() => this.#loadNotificationsIfChanged()), ) .subscribe(); + + // Rebuild notifications when cached dossiers are updated + this._dossiersCacheService.changed$.subscribe(() => { + this.setEntities(this.all.map(e => this._new(e))); + }); } @Validate() @@ -75,7 +77,7 @@ export class NotificationsService extends EntitiesService 1; + + const routerPath = (this.isArchived ? ARCHIVE_ROUTE : DOSSIERS_ROUTE) as string; + this.dossiersListRouterLink = `/main/${this.dossierTemplateId}/${routerPath}`; + this.routerLink = `${this.dossiersListRouterLink}/${this.dossierId}`; } get id(): string { return this.dossierId; } - get routerLink(): string { - return `${this.dossiersListRouterLink}/${this.dossierId}`; - } - - get dossiersListRouterLink(): string { - const routerPath = this.isArchived ? ARCHIVE_ROUTE : DOSSIERS_ROUTE; - return `/main/${this.dossierTemplateId}/${routerPath}`; - } - get searchKey(): string { return this.dossierName; }