Skip to content
Snippets Groups Projects
Commit 918411f6 authored by Fadil's avatar Fadil Committed by bouhaddouzay
Browse files

[US TRTL-514] Improve tenant selection architecture

parent 1c587df9
No related branches found
No related tags found
No related merge requests found
import { Component, OnDestroy, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { SafeResourceUrl, SafeUrl } from '@angular/platform-browser';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { ActivatedRoute, ActivationStart, Router } from '@angular/router';
import { Subject, Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ApplicationService } from '../../application.service';
import { AuthService } from '../../auth.service';
import { CustomerSelectionService } from '../../customer-selection.service';
......@@ -15,7 +15,7 @@ import { ThemeService } from '../../theme.service';
import { MenuOption } from '../navbar/customer-menu/menu-option.interface';
import { ApplicationId } from './../../application-id.enum';
import { SubrogationService } from './../../subrogation/subrogation.service';
import { TenantSelectionService } from './../../tenant-selection.service';
import { TenantSelectionService, TENANT_SELECTION_URL_CONDITION } from './../../tenant-selection.service';
import { MenuOverlayService } from './menu/menu-overlay.service';
import { SelectTenantDialogComponent } from './select-tenant-dialog/select-tenant-dialog.component';
......@@ -50,6 +50,7 @@ export class HeaderComponent implements OnInit, OnDestroy {
private themeService: ThemeService,
private matDialog: MatDialog,
private router: Router,
private route: ActivatedRoute,
private applicationService: ApplicationService,
private globalEventService: GlobalEventService) { }
......@@ -82,40 +83,7 @@ export class HeaderComponent implements OnInit, OnDestroy {
}
});
if (this.router.events) {
// Show or hide the tenant selection component from the header when needed
this.router.events.pipe(takeUntil(this.destroyer$), debounceTime(200)).subscribe((data: any) => {
const url = data && data.routerEvent ? data.routerEvent.url : undefined;
this.hasTenantSelection = this.tenantService.hasTenantSelection(url);
});
}
// Subcribe to active tenant changes
this.tenantService.getSelectedTenant$()
.pipe(takeUntil(this.destroyer$))
.subscribe((tenant: Tenant) => {
if (!this.selectedTenant) {
this.selectedTenant = {value: tenant, label: tenant.name};
} else {
if (this.selectedTenant.value.identifier !== tenant.identifier) {
this.selectedTenant = {value: tenant, label: tenant.name};
this.tenantService.saveSelectedTenant(tenant).toPromise();
}
}
});
// Init last tenant only if there is no active tenant.
// The subscription will stop when a tenant is set as active.
this.tenantService.getLastTenantIdentifier$()
.pipe(takeUntil(this.tenantService.getSelectedTenant$()), takeUntil(this.destroyer$))
.subscribe((identifier: number) => {
const lastTenant = this.tenants.find((option: MenuOption) => option.value.identifier === identifier);
if (!this.selectedTenant && lastTenant) {
this.tenantService.setSelectedTenant(lastTenant.value);
}
});
// When an application id change is detected, we have to check if we need to display customer selection or not
this.initTenantSelection();
this.initCustomerSelection();
}
......@@ -145,10 +113,69 @@ export class HeaderComponent implements OnInit, OnDestroy {
}
/**
* Init customer selection feature & listeners if the
* current opened application requires it
* Init tenant selection feature & listeners if the current opened application requires it.
*/
private initTenantSelection(): void {
if (this.router.events) {
let eventsObsRef: Subscription;
// Show or hide the tenant selection component from the header when needed
this.tenantService.hasTenantSelection().subscribe((result: boolean) => {
this.hasTenantSelection = result;
if (this.hasTenantSelection && !eventsObsRef) {
eventsObsRef = this.router.events.pipe(takeUntil(this.destroyer$)).subscribe((data: any) => {
if (data instanceof ActivationStart) {
const tenantIdentifier = +data.snapshot.params.tenantIdentifier;
if (tenantIdentifier) {
this.tenantService.setSelectedTenantByIdentifier(tenantIdentifier);
this.tenantService.getSelectedTenant$().pipe(takeUntil(this.destroyer$)).subscribe((tenant: Tenant) => {
if (tenant.identifier !== tenantIdentifier) {
this.changeTenant(tenant.identifier);
}
});
}
}
});
}
});
}
// Subcribe to active tenant changes
this.tenantService.getSelectedTenant$().pipe(takeUntil(this.destroyer$)).subscribe((tenant: Tenant) => {
if (!this.selectedTenant) {
this.selectedTenant = {value: tenant, label: tenant.name};
} else {
if (this.selectedTenant.value.identifier !== tenant.identifier) {
this.selectedTenant = {value: tenant, label: tenant.name};
this.tenantService.saveSelectedTenant(tenant).toPromise();
}
}
});
this.initLastTenantIdentifier();
}
/**
* Init last tenant only if there is no active tenant.
* The subscription will stop when a tenant is set as active.
*/
private initCustomerSelection() {
private initLastTenantIdentifier() {
this.tenantService.getLastTenantIdentifier$()
.pipe(takeUntil(this.tenantService.getSelectedTenant$()), takeUntil(this.destroyer$))
.subscribe((identifier: number) => {
const lastTenant = this.tenants.find((option: MenuOption) => option.value.identifier === identifier);
if (!this.selectedTenant && lastTenant) {
this.tenantService.setSelectedTenant(lastTenant.value);
}
});
}
/**
* Init customer selection feature & listeners if the current opened application requires it.
*/
private initCustomerSelection(): void {
this.tenantService.currentAppId$.pipe(takeUntil(this.destroyer$)).subscribe((appIdentifier: string) => {
this.hasCustomerSelection = false;
if (appIdentifier) {
......@@ -172,4 +199,8 @@ export class HeaderComponent implements OnInit, OnDestroy {
}
});
}
private changeTenant(tenantIdentifier: Number): void {
this.router.navigate([this.route.firstChild.snapshot.url[0].path + TENANT_SELECTION_URL_CONDITION, tenantIdentifier], { relativeTo: this.route });
}
}
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';
......@@ -7,14 +6,14 @@ import { ApplicationId } from './application-id.enum';
import { AuthService } from './auth.service';
import { Tenant } from './models/customer/tenant.interface';
/** Keyword in url that indicate the selected tenant identifier */
export const TENANT_SELECTION_URL_CONDITION = '/tenant/';
@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 */
......@@ -149,10 +148,15 @@ export class TenantSelectionService {
});
}
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);
public hasTenantSelection(url?: string): Observable<boolean> {
return new Observable((observer) => {
if (!url) {
url = window.location.href;
}
this.currentAppId$.subscribe((appId: ApplicationId) => {
observer.next((url.includes(TENANT_SELECTION_URL_CONDITION) || appId === ApplicationId.PORTAL_APP));
})
});
}
}
<vitamui-common-header></vitamui-common-header>
<vitamui-common-body>
<router-outlet></router-outlet>
</vitamui-common-body>
<vitamui-common-footer></vitamui-common-footer>
<vitamui-common-subrogation-banner></vitamui-common-subrogation-banner>
......@@ -41,18 +41,14 @@ import { StartupService } from 'ui-frontend-common';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
title = 'Identity App';
subrogating = false;
constructor(titleService: Title, startupService: StartupService) {
titleService.setTitle(startupService.getPlatformName());
}
constructor(private titleService: Title, private startupService: StartupService) { }
ngOnInit() {
this.titleService.setTitle(this.startupService.getPlatformName());
}
}
......@@ -34,16 +34,10 @@
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { takeUntil } from 'rxjs/operators';
import {
GlobalEventService,
Profile, SidenavPage,
Tenant,
TenantSelectionService } from 'ui-frontend-common';
import { ActivatedRoute } from '@angular/router';
import { GlobalEventService, Profile, SidenavPage } from 'ui-frontend-common';
import { HierarchyCreateComponent } from './hierarchy-create/hierarchy-create.component';
import { HierarchyListComponent } from './hierarchy-list/hierarchy-list.component';
......@@ -52,49 +46,34 @@ import { HierarchyListComponent } from './hierarchy-list/hierarchy-list.componen
templateUrl: './hierarchy.component.html',
styleUrls: ['./hierarchy.component.scss']
})
export class HierarchyComponent extends SidenavPage<Profile> implements OnInit, OnDestroy {
export class HierarchyComponent extends SidenavPage<Profile> implements OnInit {
public profiles: Profile[];
public search: string;
private tenantIdentifier: number;
private destroyer$ = new Subject();
@ViewChild(HierarchyListComponent, { static: true }) hierarchyListComponent: HierarchyListComponent;
constructor(public dialog: MatDialog, private route: ActivatedRoute, private router: Router,
public globalEventService: GlobalEventService, private tenantService: TenantSelectionService) {
constructor(public dialog: MatDialog, private route: ActivatedRoute, public globalEventService: GlobalEventService) {
super(route, globalEventService);
}
ngOnInit() {
this.route.paramMap.subscribe((paramMap) => {
this.tenantIdentifier = +paramMap.get('tenantIdentifier');
this.tenantService.setSelectedTenantByIdentifier(this.tenantIdentifier);
this.tenantService.getSelectedTenant$().pipe(takeUntil(this.destroyer$)).subscribe((tenant: Tenant) => {
this.changeTenant(tenant.identifier);
});
});
}
ngOnDestroy() {
this.destroyer$.next();
this.destroyer$.complete();
}
public changeTenant(tenantIdentifier: number): void {
this.router.navigate(['..', tenantIdentifier], { relativeTo: this.route });
}
public openHierarchyDuplicateDialog(): void {
const dialogRef = this.dialog.open(HierarchyCreateComponent, {
this.dialog.open(HierarchyCreateComponent, {
panelClass: 'vitamui-modal',
disableClose: true,
data: {
tenantId: this.tenantIdentifier
}},
);
dialogRef.afterClosed().subscribe((result) => {
if (result) { this.refreshList(); }
data: { tenantId: this.tenantIdentifier }
}).afterClosed().subscribe((result) => {
if (result) {
this.refreshList();
}
});
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment