import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { map } from 'rxjs/operators'; import { UserApiService } from './api/user-api.service'; import { ApplicationId } from './application-id.enum'; import { AuthService } from './auth.service'; import { Tenant } from './models/customer/tenant.interface'; @Injectable({ providedIn: 'root' }) export class TenantSelectionService { /** Keyword in url that indicate the selected tenant identifier */ private readonly TENANT_SELECTION_URL_CONDITION = '/tenant/'; public currentAppId$ = new BehaviorSubject(undefined); /** Contain data about the current selected tenant */ private selectedTenant: Tenant; /** Provide selected tenant subscriptions */ private selectedTenant$ = new BehaviorSubject(undefined); /** Contain the last persisted tenant identifier in DB */ private lastTenantIdentifier: number; /** Provide last tenant identifier subscriptions */ private lastTenantIdentifier$ = new Subject(); /** Contain a list of all existing tenant for the current logged in user */ private tenants: Tenant[]; constructor(private authService: AuthService, private userApiService: UserApiService) { } public getSelectedTenant(): Tenant { return this.selectedTenant; } public setSelectedTenant(tenant: Tenant): void { if (!this.selectedTenant || this.selectedTenant.identifier !== tenant.identifier) { this.selectedTenant = tenant; this.selectedTenant$.next(tenant); } } public setSelectedTenantByIdentifier(tenantIdentifier: number): void { if (tenantIdentifier) { const tenant: Tenant = this.getTenants().find(value => value.identifier === tenantIdentifier); if (tenant) { this.setSelectedTenant(tenant); } } } public getSelectedTenant$(): Observable<Tenant> { if (this.selectedTenant$.getValue()) { return this.selectedTenant$.asObservable(); } else { // Return a new observable if there is no value, // so we are only notified when a value is defined in the selected tenant BehaviorSubject return new Observable(observer => { this.selectedTenant$.asObservable().subscribe((tenant: Tenant) => { if (tenant) { observer.next(tenant); } }); }); } } public getLastTenantIdentifier(): number { return this.lastTenantIdentifier; } public getLastTenantIdentifier$(): Observable<number> { return this.lastTenantIdentifier$.asObservable() as Observable<number>; } public setLastTenantIdentifier(identifier: number): void { this.lastTenantIdentifier = identifier; this.lastTenantIdentifier$.next(identifier); } public getTenants(): Tenant[] { if (!this.tenants) { const currentUser = this.authService.user; this.tenants = []; if (currentUser && currentUser.tenantsByApp) { currentUser.tenantsByApp.forEach((element: { name: string, tenants: Tenant[] }) => { if (element.tenants) { element.tenants.forEach((tenant: Tenant) => { if (this.tenants.findIndex(value => value.identifier === tenant.identifier) === -1) { this.tenants.push(tenant); } }); } }); } } return this.tenants; } /** * Persist the current active tenant (only if the current opened app is not portal). * Can also define & persist a new tenant by passing it in entry. * @param tenant - the new selected tenant */ public saveSelectedTenant(tenant?: Tenant): Observable<number> { return new Observable((observer) => { if (!tenant) { tenant = this.getSelectedTenant(); } // If the last tenantIdentifier is the same, no need to persist if (this.lastTenantIdentifier === tenant.identifier) { observer.next(tenant.identifier); } else { // In portal APP, just update the selected tenant without doing anything else. // In other apps, persist the new tenant identifier if (this.currentAppId$.value === ApplicationId.PORTAL_APP) { this.setSelectedTenant(tenant); observer.next(tenant.identifier); } else { this.saveTenantIdentifier(tenant.identifier).subscribe((identifier: number) => { observer.next(identifier); }); } } }); } public saveTenantIdentifier(identifier?: number): Observable<number> { return new Observable((observer) => { if (!identifier) { if (this.selectedTenant) { identifier = this.selectedTenant.identifier; } else { identifier = this.lastTenantIdentifier; } } this.userApiService.analytics({lastTenantIdentifier: identifier}) .pipe(map((value) => value.analytics.lastTenantIdentifier)).subscribe((tenantIdentifier: number) => { this.setLastTenantIdentifier(tenantIdentifier); observer.next(tenantIdentifier); }); }); } public hasTenantSelection(url: string): boolean { if (!url) { url = window.location.href; } return (url.includes(this.TENANT_SELECTION_URL_CONDITION) || this.currentAppId$.value === ApplicationId.PORTAL_APP); } }