1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-06 11:43:51 +00:00

Refactor the code to reactive

This commit is contained in:
Cy Okeke
2025-07-25 15:29:15 +01:00
parent 56a476bb4c
commit 5444346c51
4 changed files with 112 additions and 88 deletions

View File

@@ -1,3 +1,4 @@
@let isSuspensionActive = suspensionActive$ | async;
<app-header>
<bit-search
class="tw-grow"
@@ -9,7 +10,6 @@
routerLink="create"
*ngIf="manageOrganizations && isSuspensionActive"
buttonType="primary"
[title]="addSuspensionTooltip"
>
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
{{ "newClient" | i18n }}
@@ -20,7 +20,7 @@
bitButton
buttonType="primary"
[disabled]="true"
[title]="addSuspensionTooltip"
[title]="'providerIsDisabled' | i18n"
>
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
{{ "newClient" | i18n }}
@@ -29,7 +29,7 @@
type="button"
bitButton
[disabled]="isSuspensionActive"
[title]="addSuspensionTooltip"
[title]="isSuspensionActive ? ('providerIsDisabled' | i18n) : ''"
(click)="addExistingOrganization()"
*ngIf="manageOrganizations && showAddExisting"
>

View File

@@ -3,8 +3,8 @@ import { Component } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { FormControl } from "@angular/forms";
import { ActivatedRoute, Router, RouterModule } from "@angular/router";
import { firstValueFrom, from, map } from "rxjs";
import { debounceTime, first, switchMap } from "rxjs/operators";
import { firstValueFrom, from, map, combineLatest, switchMap, Observable } from "rxjs";
import { debounceTime, first } from "rxjs/operators";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
@@ -62,15 +62,44 @@ export class ClientsComponent {
addableOrganizations: Organization[] = [];
loading = true;
manageOrganizations = false;
isAdminOrServiceUser = false;
showAddExisting = false;
dataSource: TableDataSource<ProviderOrganizationOrganizationDetailsResponse> =
new TableDataSource();
protected searchControl = new FormControl("", { nonNullable: true });
protected providerId$: Observable<string> =
this.activatedRoute.parent?.params.pipe(map((params) => params.providerId as string)) ??
new Observable();
protected provider$ = this.providerId$.pipe(
switchMap((providerId) => {
this.providerId = providerId;
return this.providerService.get$(providerId);
}),
);
protected isAdminOrServiceUser$ = this.provider$.pipe(
map(
(provider) =>
provider?.type === ProviderUserType.ProviderAdmin ||
provider?.type === ProviderUserType.ServiceUser,
),
);
protected providerPortalTakeover$ = this.configService.getFeatureFlag$(
FeatureFlag.PM21821_ProviderPortalTakeover,
);
private providerPortalTakeoverEnabled = false;
protected suspensionActive$ = combineLatest([
this.isAdminOrServiceUser$,
this.providerPortalTakeover$,
this.provider$.pipe(map((provider) => provider?.enabled ?? false)),
]).pipe(
map(
([isAdminOrServiceUser, portalTakeoverEnabled, providerEnabled]) =>
isAdminOrServiceUser && portalTakeoverEnabled && !providerEnabled,
),
);
constructor(
private router: Router,
@@ -91,34 +120,21 @@ export class ClientsComponent {
this.searchControl.setValue(queryParams.search);
});
this.providerPortalTakeover$.pipe(takeUntilDestroyed()).subscribe((enabled) => {
this.providerPortalTakeoverEnabled = enabled;
});
this.activatedRoute.parent?.params
?.pipe(
switchMap((params) => {
this.providerId = params.providerId;
return this.providerService.get$(this.providerId).pipe(
map((provider) => {
this.provider = provider;
this.isAdminOrServiceUser =
provider.type === ProviderUserType.ProviderAdmin ||
provider.type === ProviderUserType.ServiceUser;
return provider?.providerStatus === ProviderStatusType.Billable;
}),
map((isBillable) => {
if (isBillable) {
return from(
this.router.navigate(["../manage-client-organizations"], {
relativeTo: this.activatedRoute,
}),
);
} else {
return from(this.load());
}
}),
);
this.provider$
.pipe(
map((provider) => {
this.provider = provider;
this.manageOrganizations =
provider.type === ProviderUserType.ProviderAdmin ||
provider.type === ProviderUserType.ServiceUser;
if (provider?.providerStatus === ProviderStatusType.Billable) {
return from(
this.router.navigate(["../manage-client-organizations"], {
relativeTo: this.activatedRoute,
}),
);
}
return from(this.load());
}),
takeUntilDestroyed(),
)
@@ -185,14 +201,4 @@ export class ClientsComponent {
await this.load();
}
}
get isSuspensionActive(): boolean {
return (
this.isAdminOrServiceUser && this.providerPortalTakeoverEnabled && !this.provider?.enabled
);
}
get addSuspensionTooltip(): string {
return this.isSuspensionActive ? this.i18nService.t("providerIsDisabled") : "";
}
}

View File

@@ -1,3 +1,4 @@
@let isSuspensionActive = suspensionActive$ | async;
<app-header [title]="pageTitle">
<bit-search [placeholder]="'search' | i18n" [formControl]="searchControl"></bit-search>
<button
@@ -6,8 +7,10 @@
type="button"
[bitMenuTriggerFor]="clientMenu"
[disabled]="isSuspensionActive"
[title]="suspendedTooltip"
appA11yTitle="{{ isSuspensionActive ? ('add' | i18n) : suspendedTooltip }}"
[title]="isSuspensionActive ? ('providerIsDisabled' | i18n) : ''"
appA11yTitle="{{
isSuspensionActive ? ('add' | i18n) : isSuspensionActive ? ('providerIsDisabled' | i18n) : ''
}}"
>
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
{{ "add" | i18n }}
@@ -17,7 +20,7 @@
type="button"
bitMenuItem
[disabled]="isSuspensionActive"
[title]="suspendedTooltip"
[title]="isSuspensionActive ? ('providerIsDisabled' | i18n) : ''"
(click)="createClient()"
>
<i aria-hidden="true" class="bwi bwi-business"></i>
@@ -27,7 +30,7 @@
type="button"
bitMenuItem
[disabled]="isSuspensionActive"
[title]="suspendedTooltip"
[title]="isSuspensionActive ? ('providerIsDisabled' | i18n) : ''"
(click)="addExistingOrganization()"
>
<i aria-hidden="true" class="bwi bwi-filter"></i>
@@ -91,7 +94,7 @@
type="button"
bitMenuItem
[disabled]="isSuspensionActive"
[title]="suspendedTooltip"
[title]="isSuspensionActive ? ('providerIsDisabled' | i18n) : ''"
(click)="manageClientName(row)"
>
<i aria-hidden="true" class="bwi bwi-pencil-square"></i>
@@ -101,7 +104,7 @@
type="button"
bitMenuItem
[disabled]="isSuspensionActive"
[title]="suspendedTooltip"
[title]="isSuspensionActive ? ('providerIsDisabled' | i18n) : ''"
(click)="manageClientSubscription(row)"
>
<i aria-hidden="true" class="bwi bwi-family"></i>

View File

@@ -2,8 +2,16 @@ import { Component } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { FormControl } from "@angular/forms";
import { ActivatedRoute, Router } from "@angular/router";
import { firstValueFrom, from, lastValueFrom, map } from "rxjs";
import { debounceTime, first, switchMap } from "rxjs/operators";
import {
firstValueFrom,
from,
lastValueFrom,
map,
combineLatest,
switchMap,
Observable,
} from "rxjs";
import { debounceTime, first } from "rxjs/operators";
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
import {
@@ -78,10 +86,39 @@ export class ManageClientsComponent {
clientColumnHeader = this.i18nService.t("client");
newClientButtonLabel = this.i18nService.t("newClient");
protected providerId$: Observable<string> =
this.activatedRoute.parent?.params.pipe(map((params) => params.providerId as string)) ??
new Observable();
protected provider$ = this.providerId$.pipe(
switchMap((providerId) => {
this.providerId = providerId;
return this.providerService.get$(providerId);
}),
);
protected isAdminOrServiceUser$ = this.provider$.pipe(
map(
(provider) =>
provider?.type === ProviderUserType.ProviderAdmin ||
provider?.type === ProviderUserType.ServiceUser,
),
);
protected providerPortalTakeover$ = this.configService.getFeatureFlag$(
FeatureFlag.PM21821_ProviderPortalTakeover,
);
private providerPortalTakeoverEnabled = false;
protected suspensionActive$ = combineLatest([
this.isAdminOrServiceUser$,
this.providerPortalTakeover$,
this.provider$.pipe(map((provider) => provider?.enabled ?? false)),
]).pipe(
map(
([isAdminOrServiceUser, portalTakeoverEnabled, providerEnabled]) =>
isAdminOrServiceUser && portalTakeoverEnabled && !providerEnabled,
),
);
constructor(
private billingApiService: BillingApiServiceAbstraction,
@@ -100,28 +137,18 @@ export class ManageClientsComponent {
this.searchControl.setValue(queryParams.search);
});
this.providerPortalTakeover$.pipe(takeUntilDestroyed()).subscribe((enabled) => {
this.providerPortalTakeoverEnabled = enabled;
});
this.activatedRoute.parent?.params
?.pipe(
switchMap((params) => {
this.providerId = params.providerId;
return this.providerService.get$(this.providerId).pipe(
map((provider: Provider) => provider?.providerStatus === ProviderStatusType.Billable),
map((isBillable) => {
if (!isBillable) {
return from(
this.router.navigate(["../clients"], {
relativeTo: this.activatedRoute,
}),
);
} else {
return from(this.load());
}
}),
);
this.provider$
.pipe(
map((provider: Provider) => {
if (provider?.providerStatus !== ProviderStatusType.Billable) {
return from(
this.router.navigate(["../clients"], {
relativeTo: this.activatedRoute,
}),
);
} else {
return from(this.load());
}
}),
takeUntilDestroyed(),
)
@@ -245,16 +272,4 @@ export class ManageClientsComponent {
this.validationService.showError(e);
}
}
get isSuspensionActive(): boolean {
return (
(this.isProviderAdmin || this.isServiceUser) &&
this.providerPortalTakeoverEnabled &&
!this.provider?.enabled
);
}
get suspendedTooltip(): string {
return this.isSuspensionActive ? this.i18nService.t("providerIsDisabled") : "";
}
}