diff --git a/src/lib/services/generic.service.ts b/src/lib/services/generic.service.ts index 50cf23e..62f307e 100644 --- a/src/lib/services/generic.service.ts +++ b/src/lib/services/generic.service.ts @@ -18,9 +18,7 @@ export interface QueryParam { */ export abstract class GenericService { protected readonly _http = inject(HttpClient); - protected readonly _lastCheckedForChanges = new Map([ - [ROOT_CHANGES_KEY, new Date(Date.now()).toISOString()], - ]); + protected readonly _lastCheckedForChanges = new Map([[ROOT_CHANGES_KEY, new Date(Date.now()).toISOString()]]); protected abstract readonly _defaultModelPath: string; protected readonly _serviceName: string = 'redaction-gateway-v1'; @@ -40,7 +38,7 @@ export abstract class GenericService { headers: HeadersConfiguration.getHeaders({ contentType: false }), observe: 'body', params: this._queryParams(queryParams), - }) + }); } getFor(entityId: string, queryParams?: List): Observable { diff --git a/src/lib/services/iqser-config.service.ts b/src/lib/services/iqser-config.service.ts index 5b4636c..3336306 100644 --- a/src/lib/services/iqser-config.service.ts +++ b/src/lib/services/iqser-config.service.ts @@ -3,6 +3,8 @@ import { Title } from '@angular/platform-browser'; import { CacheApiService } from '../caching/cache-api.service'; import { wipeAllCaches } from '../caching/cache-utils'; import { IqserAppConfig } from '../utils/iqser-app-config'; +import { THEME_DIRECTORIES } from '../utils/constants'; +import { IStoredTenantId } from '../tenants'; @Injectable() export class IqserConfigService { @@ -23,6 +25,15 @@ export class IqserConfigService { this._titleService.setTitle(this._values.APP_NAME); } + updateIsDocumine(tenant: IStoredTenantId): void { + const isDocumine = tenant.documine; + this._values = { + ...this._values, + IS_DOCUMINE: isDocumine, + THEME: !isDocumine ? THEME_DIRECTORIES.REDACT : THEME_DIRECTORIES.SCM, + }; + } + protected _checkFrontendVersion(): void { this._cacheApiService.getCachedValue('FRONTEND_APP_VERSION').then(async lastVersion => { const version = this._values.FRONTEND_APP_VERSION; diff --git a/src/lib/shared/logo/logo.component.ts b/src/lib/shared/logo/logo.component.ts index adccb87..fef5d0b 100644 --- a/src/lib/shared/logo/logo.component.ts +++ b/src/lib/shared/logo/logo.component.ts @@ -1,9 +1,10 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; import { MatIconModule } from '@angular/material/icon'; +import { NgClass } from '@angular/common'; @Component({ selector: 'iqser-logo', - template: ` `, + template: ``, styles: [ ` :host { @@ -18,8 +19,8 @@ import { MatIconModule } from '@angular/material/icon'; ], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [MatIconModule], + imports: [MatIconModule, NgClass], }) export class LogoComponent { - @Input({ required: true }) icon!: string; + icon = input.required(); } diff --git a/src/lib/tenants/services/tenants.service.ts b/src/lib/tenants/services/tenants.service.ts index a8ee92c..ed331b8 100644 --- a/src/lib/tenants/services/tenants.service.ts +++ b/src/lib/tenants/services/tenants.service.ts @@ -1,14 +1,18 @@ import { inject, Injectable, signal } from '@angular/core'; import dayjs from 'dayjs'; import { NGXLogger } from 'ngx-logger'; -import { Observable } from 'rxjs'; +import { firstValueFrom, Observable, take } from 'rxjs'; import { GenericService } from '../../services'; import { List } from '../../utils'; import { Tenant, TenantDetails } from '../types'; +import { APPLICATION_TYPES } from '../../utils/constants'; +import { toObservable } from '@angular/core/rxjs-interop'; +import { filter } from 'rxjs/operators'; export interface IStoredTenantId { readonly tenantId: string; readonly created: string; + readonly documine: boolean; } export type StoredTenantIds = List; @@ -27,6 +31,8 @@ export class TenantsService extends GenericService { key: localStorage.key.bind(localStorage), }; readonly #activeTenantId = signal(''); + readonly #tenantSet = signal(false); + readonly tenantSet$ = toObservable(this.#tenantSet); protected readonly _defaultModelPath = 'tenants'; protected override readonly _serviceName: string = 'tenant-user-management'; @@ -34,18 +40,26 @@ export class TenantsService extends GenericService { return this.#activeTenantId(); } + get activeTenant() { + return this.getStoredTenants().find(t => t.tenantId === this.activeTenantId); + } + async selectTenant(tenantId: string): Promise { this.#mutateStorage(tenantId); this.#setActiveTenantId(tenantId); return true; } - storeTenant() { + async storeTenant() { const storedTenants = this.getStoredTenants(); const activeTenantId = this.#activeTenantId(); const existing = storedTenants.find(s => s.tenantId === activeTenantId); + + const tenant = await firstValueFrom(this.getActiveTenant()); + if (existing) { this.#logger.info('[TENANTS] Stored tenant exists: ', storedTenants); + this.#tenantSet.set(true); return; } @@ -54,8 +68,13 @@ export class TenantsService extends GenericService { return; } - storedTenants.push({ tenantId: activeTenantId, created: new Date().toISOString() }); + storedTenants.push({ + tenantId: activeTenantId, + created: new Date().toISOString(), + documine: tenant.applicationType === APPLICATION_TYPES.DOCUMINE, + }); this.#storageReference.setItem(STORED_TENANTS_KEY, JSON.stringify(storedTenants)); + this.#tenantSet.set(true); this.#logger.info('[TENANTS] Stored tenants: ', storedTenants); } @@ -104,6 +123,13 @@ export class TenantsService extends GenericService { return this._getOne([this.activeTenantId]); } + waitForSettingTenant(): Observable { + return this.tenantSet$.pipe( + filter(tenantSet => tenantSet), + take(1), + ); + } + #setActiveTenantId(tenantId: string) { this.#logger.info('[TENANTS] Set current tenant id: ', tenantId); this.#activeTenantId.set(tenantId); diff --git a/src/lib/tenants/tenant-select/tenant-select.component.html b/src/lib/tenants/tenant-select/tenant-select.component.html index b1c5ff9..b3f0fca 100644 --- a/src/lib/tenants/tenant-select/tenant-select.component.html +++ b/src/lib/tenants/tenant-select/tenant-select.component.html @@ -21,7 +21,7 @@
@for (stored of storedTenants; track stored) {
- +
{{ stored.tenantId }}
diff --git a/src/lib/tenants/tenant-select/tenant-select.component.ts b/src/lib/tenants/tenant-select/tenant-select.component.ts index 57c74ea..cad098f 100644 --- a/src/lib/tenants/tenant-select/tenant-select.component.ts +++ b/src/lib/tenants/tenant-select/tenant-select.component.ts @@ -38,6 +38,10 @@ export class TenantSelectComponent { this.#loadStoredTenants(); } + protected tenantIcon(tenant: IStoredTenantId) { + return `red:${tenant.documine ? 'documine' : 'redaction'}-logo`; + } + updateTenantSelection() { const tenantId = this.form.controls.tenantId.value; if (!tenantId) { diff --git a/src/lib/tenants/types/tenant.ts b/src/lib/tenants/types/tenant.ts index 756e100..41696c6 100644 --- a/src/lib/tenants/types/tenant.ts +++ b/src/lib/tenants/types/tenant.ts @@ -1,7 +1,10 @@ +import { ApplicationType } from '../../utils/constants'; + export type TenantDetails = Record; export interface Tenant { tenantId: string; displayName: string; + applicationType: ApplicationType; details: TD; } diff --git a/src/lib/translations/http-loader-factory.ts b/src/lib/translations/http-loader-factory.ts index 4d86ea8..73cd608 100644 --- a/src/lib/translations/http-loader-factory.ts +++ b/src/lib/translations/http-loader-factory.ts @@ -2,11 +2,13 @@ import { HttpClient } from '@angular/common/http'; import { inject } from '@angular/core'; import { getConfig } from '../services'; import { PruningTranslationLoader } from '../utils'; +import { TenantsService } from '../tenants'; export function pruningTranslationLoaderFactory(pathPrefix: string): PruningTranslationLoader { const httpClient = inject(HttpClient); + const tenantService = inject(TenantsService); const config = getConfig(); const version = config.FRONTEND_APP_VERSION; - return new PruningTranslationLoader(httpClient, pathPrefix, `.json?version=${version}`); + return new PruningTranslationLoader(httpClient, tenantService, pathPrefix, `.json?version=${version}`); } diff --git a/src/lib/translations/pruning-translation-loader.ts b/src/lib/translations/pruning-translation-loader.ts index b9c76f7..d9b835b 100644 --- a/src/lib/translations/pruning-translation-loader.ts +++ b/src/lib/translations/pruning-translation-loader.ts @@ -1,7 +1,11 @@ import { HttpClient } from '@angular/common/http'; import { TranslateLoader } from '@ngx-translate/core'; -import { map } from 'rxjs/operators'; +import { map, switchMap } from 'rxjs/operators'; import { Observable } from 'rxjs'; +import { TenantsService } from '../tenants'; +import { APP_TYPE_PATHS } from '../utils/constants'; +import { inject } from '@angular/core'; +import { GET_TENANT_FROM_PATH_FN } from '../utils'; interface T { [key: string]: string | T; @@ -10,12 +14,30 @@ interface T { export class PruningTranslationLoader implements TranslateLoader { constructor( private readonly _http: HttpClient, + private readonly _tenantService: TenantsService, private readonly _prefix: string, private readonly _suffix: string, ) {} getTranslation(lang: string): Observable { - return this._http.get(`${this._prefix}${lang}${this._suffix}`).pipe(map(result => this._process(result as T))); + const tenant = inject(GET_TENANT_FROM_PATH_FN)(); + + if (tenant) { + return this._tenantService.waitForSettingTenant().pipe( + switchMap(() => { + const tenant = this._tenantService.activeTenant; + const translationPath = tenant?.documine ? APP_TYPE_PATHS.SCM : APP_TYPE_PATHS.REDACT; + + return this._http + .get(`${this._prefix}${translationPath}/${lang}${this._suffix}`) + .pipe(map(result => this._process(result as T))); + }), + ); + } + + return this._http + .get(`${this._prefix}${APP_TYPE_PATHS.REDACT}/${lang}${this._suffix}`) + .pipe(map(result => this._process(result as T))); } private _process(object: T): T { diff --git a/src/lib/utils/constants.ts b/src/lib/utils/constants.ts index 18d54ee..88674d4 100644 --- a/src/lib/utils/constants.ts +++ b/src/lib/utils/constants.ts @@ -51,3 +51,26 @@ export const ICONS = new Set([ 'visibility', 'visibility-off', ]); + +export const LANDING_PAGE_THEMES = { + REDACT_MANAGER: 'redactmanager', + DOCUMINE: 'documine', + MIXED: 'mixed', +} as const; + +export const THEME_DIRECTORIES = { + REDACT: 'redact', + SCM: 'scm', +} as const; + +export const APP_TYPE_PATHS = { + REDACT: 'redact', + SCM: 'scm', +} as const; + +export const APPLICATION_TYPES = { + REDACT_MANAGER: 'RedactManager', + DOCUMINE: 'DocuMine', +} as const; + +export type ApplicationType = (typeof APPLICATION_TYPES)[keyof typeof APPLICATION_TYPES]; diff --git a/src/lib/utils/iqser-app-config.ts b/src/lib/utils/iqser-app-config.ts index 29b5c2f..59cc363 100644 --- a/src/lib/utils/iqser-app-config.ts +++ b/src/lib/utils/iqser-app-config.ts @@ -8,4 +8,5 @@ export interface IqserAppConfig { readonly OAUTH_URL: string; readonly MANUAL_BASE_URL: string; readonly BASE_TRANSLATIONS_DIRECTORY?: string; + readonly LANDING_PAGE_THEME: 'redactmanager' | 'documine' | 'mixed'; }