113 lines
4.0 KiB
TypeScript
113 lines
4.0 KiB
TypeScript
import { computed, inject, Injectable, signal } from '@angular/core';
|
|
import { HttpClient } from '@angular/common/http';
|
|
import { firstValueFrom } from 'rxjs';
|
|
import { NGXLogger } from 'ngx-logger';
|
|
import { BASE_HREF } from '../../utils';
|
|
import { Router } from '@angular/router';
|
|
|
|
export interface IBaseTenant {
|
|
readonly tenantId: string;
|
|
readonly displayName: string;
|
|
readonly guid: string;
|
|
}
|
|
|
|
@Injectable({ providedIn: 'root' })
|
|
export class TenantsService {
|
|
readonly tenants = signal<IBaseTenant[] | undefined>(undefined);
|
|
readonly hasMultiple = computed(() => {
|
|
const tenants = this.tenants();
|
|
return tenants ? tenants.length > 1 : false;
|
|
});
|
|
readonly #http = inject(HttpClient);
|
|
readonly #router = inject(Router);
|
|
readonly #logger = inject(NGXLogger);
|
|
readonly #baseHref = inject(BASE_HREF);
|
|
readonly #storageReference: Storage = {
|
|
length: localStorage.length,
|
|
clear: localStorage.clear.bind(localStorage),
|
|
getItem: localStorage.getItem.bind(localStorage),
|
|
setItem: localStorage.setItem.bind(localStorage),
|
|
removeItem: localStorage.removeItem.bind(localStorage),
|
|
key: localStorage.key.bind(localStorage),
|
|
};
|
|
readonly #activeTenantId = signal<string>('');
|
|
|
|
get currentTenant() {
|
|
return this.#activeTenantId();
|
|
}
|
|
|
|
async loadTenants() {
|
|
this.#logger.info('[TENANTS] Loading tenants...');
|
|
const tenants = await firstValueFrom(this.#http.get<IBaseTenant[]>('/tenants/simple'));
|
|
this.tenants.set(tenants);
|
|
|
|
const tenant = this.getTenantFromRoute();
|
|
if (tenant) {
|
|
this.#logger.info('[TENANTS] Tenant from route: ', tenant);
|
|
if (await this.selectTenant(tenant)) {
|
|
await this.#executeMainResolverAndRedirect(tenant);
|
|
}
|
|
return;
|
|
}
|
|
|
|
this.#logger.info('[TENANTS] No tenant in route');
|
|
|
|
if (!this.hasMultiple) {
|
|
this.#logger.info('[TENANTS] Only one tenant loaded, auto-select it and redirect to login page');
|
|
const tenant = tenants[0].tenantId;
|
|
if (await this.selectTenant(tenant)) {
|
|
await this.#executeMainResolverAndRedirect(tenant);
|
|
}
|
|
}
|
|
}
|
|
|
|
getTenantFromRoute() {
|
|
const path = window.location.pathname;
|
|
const nextSlash = path.indexOf('/', this.#baseHref.length + 1);
|
|
return path.substring(this.#baseHref.length + 1, nextSlash >= 0 ? nextSlash : path.length);
|
|
}
|
|
|
|
async selectTenant(tenantId: string) {
|
|
const tenants = this.tenants();
|
|
if (!tenants) {
|
|
throw new Error('Tenants not loaded!');
|
|
}
|
|
|
|
const unknownTenant = !tenants.map(t => t.tenantId).includes(tenantId);
|
|
|
|
if (unknownTenant) {
|
|
this.#logger.info('[TENANTS] Unknown tenant, redirecting to select tenant page');
|
|
await this.#router.navigate(['/']);
|
|
return false;
|
|
}
|
|
|
|
this.#mutateStorage(tenantId);
|
|
this.#setCurrentTenantId(tenantId);
|
|
return true;
|
|
}
|
|
|
|
#setCurrentTenantId(tenantId: string) {
|
|
this.#logger.info('[TENANTS] Set current tenant id: ', tenantId);
|
|
this.#activeTenantId.set(tenantId);
|
|
}
|
|
|
|
#mutateStorage(tenant: string) {
|
|
localStorage.getItem = (key: string) => {
|
|
return this.#storageReference.getItem(tenant + ':' + key);
|
|
};
|
|
localStorage.setItem = (key: string, value: string) => {
|
|
this.#storageReference.setItem(tenant + ':' + key, value);
|
|
};
|
|
localStorage.removeItem = (key: string) => {
|
|
this.#storageReference.removeItem(tenant + ':' + key);
|
|
};
|
|
}
|
|
|
|
async #executeMainResolverAndRedirect(tenant: string) {
|
|
const intendedPath = window.location.pathname.replace(this.#baseHref, '');
|
|
// TODO: Load roles in child routes canLoad functions so we can redirect straight to wanted URL
|
|
await this.#router.navigate([tenant], { skipLocationChange: true });
|
|
await this.#router.navigate([intendedPath]);
|
|
}
|
|
}
|