-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PM-13347] Web app impacts on the Remove Bitwarden Families policy (#…
…12056) * Changes for web impact by the policy * Changes to address PR comments * refactoring changes from pr comments * Resolve the complex conditionals comment * resolve the complex conditionals comment * Resolve the pr comments on user layout * revert on wanted change * Refactor and move logic and template into its own component * Move to a folder owned by the Billing team
- Loading branch information
1 parent
5968634
commit d76b5b6
Showing
8 changed files
with
231 additions
and
17 deletions.
There are no files selected for viewing
125 changes: 125 additions & 0 deletions
125
apps/web/src/app/billing/services/free-families-policy.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import { Injectable } from "@angular/core"; | ||
import { combineLatest, filter, from, map, Observable, of, switchMap } from "rxjs"; | ||
|
||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; | ||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; | ||
import { PolicyType } from "@bitwarden/common/admin-console/enums"; | ||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; | ||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; | ||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; | ||
|
||
interface EnterpriseOrgStatus { | ||
isFreeFamilyPolicyEnabled: boolean; | ||
belongToOneEnterpriseOrgs: boolean; | ||
belongToMultipleEnterpriseOrgs: boolean; | ||
} | ||
|
||
@Injectable({ providedIn: "root" }) | ||
export class FreeFamiliesPolicyService { | ||
protected enterpriseOrgStatus: EnterpriseOrgStatus = { | ||
isFreeFamilyPolicyEnabled: false, | ||
belongToOneEnterpriseOrgs: false, | ||
belongToMultipleEnterpriseOrgs: false, | ||
}; | ||
|
||
constructor( | ||
private policyService: PolicyService, | ||
private organizationService: OrganizationService, | ||
private configService: ConfigService, | ||
) {} | ||
|
||
get showFreeFamilies$(): Observable<boolean> { | ||
return this.isFreeFamilyFlagEnabled$.pipe( | ||
switchMap((isFreeFamilyFlagEnabled) => | ||
isFreeFamilyFlagEnabled | ||
? this.getFreeFamiliesVisibility$() | ||
: this.organizationService.canManageSponsorships$, | ||
), | ||
); | ||
} | ||
|
||
private getFreeFamiliesVisibility$(): Observable<boolean> { | ||
return combineLatest([ | ||
this.checkEnterpriseOrganizationsAndFetchPolicy(), | ||
this.organizationService.canManageSponsorships$, | ||
]).pipe( | ||
map(([orgStatus, canManageSponsorships]) => | ||
this.shouldShowFreeFamilyLink(orgStatus, canManageSponsorships), | ||
), | ||
); | ||
} | ||
|
||
private shouldShowFreeFamilyLink( | ||
orgStatus: EnterpriseOrgStatus | null, | ||
canManageSponsorships: boolean, | ||
): boolean { | ||
if (!orgStatus) { | ||
return false; | ||
} | ||
const { belongToOneEnterpriseOrgs, isFreeFamilyPolicyEnabled } = orgStatus; | ||
return canManageSponsorships && !(belongToOneEnterpriseOrgs && isFreeFamilyPolicyEnabled); | ||
} | ||
|
||
checkEnterpriseOrganizationsAndFetchPolicy(): Observable<EnterpriseOrgStatus> { | ||
return this.organizationService.organizations$.pipe( | ||
filter((organizations) => Array.isArray(organizations) && organizations.length > 0), | ||
switchMap((organizations) => this.fetchEnterpriseOrganizationPolicy(organizations)), | ||
); | ||
} | ||
|
||
private fetchEnterpriseOrganizationPolicy( | ||
organizations: Organization[], | ||
): Observable<EnterpriseOrgStatus> { | ||
const { belongToOneEnterpriseOrgs, belongToMultipleEnterpriseOrgs } = | ||
this.evaluateEnterpriseOrganizations(organizations); | ||
|
||
if (!belongToOneEnterpriseOrgs) { | ||
return of({ | ||
isFreeFamilyPolicyEnabled: false, | ||
belongToOneEnterpriseOrgs, | ||
belongToMultipleEnterpriseOrgs, | ||
}); | ||
} | ||
|
||
const organizationId = this.getOrganizationIdForOneEnterprise(organizations); | ||
if (!organizationId) { | ||
return of({ | ||
isFreeFamilyPolicyEnabled: false, | ||
belongToOneEnterpriseOrgs, | ||
belongToMultipleEnterpriseOrgs, | ||
}); | ||
} | ||
|
||
return this.policyService.getAll$(PolicyType.FreeFamiliesSponsorshipPolicy).pipe( | ||
map((policies) => ({ | ||
isFreeFamilyPolicyEnabled: policies.some( | ||
(policy) => policy.organizationId === organizationId && policy.enabled, | ||
), | ||
belongToOneEnterpriseOrgs, | ||
belongToMultipleEnterpriseOrgs, | ||
})), | ||
); | ||
} | ||
|
||
private evaluateEnterpriseOrganizations(organizations: any[]): { | ||
belongToOneEnterpriseOrgs: boolean; | ||
belongToMultipleEnterpriseOrgs: boolean; | ||
} { | ||
const enterpriseOrganizations = organizations.filter((org) => org.canManageSponsorships); | ||
const count = enterpriseOrganizations.length; | ||
|
||
return { | ||
belongToOneEnterpriseOrgs: count === 1, | ||
belongToMultipleEnterpriseOrgs: count > 1, | ||
}; | ||
} | ||
|
||
private getOrganizationIdForOneEnterprise(organizations: any[]): string | null { | ||
const enterpriseOrganizations = organizations.filter((org) => org.canManageSponsorships); | ||
return enterpriseOrganizations.length === 1 ? enterpriseOrganizations[0].id : null; | ||
} | ||
|
||
private get isFreeFamilyFlagEnabled$(): Observable<boolean> { | ||
return from(this.configService.getFeatureFlag(FeatureFlag.DisableFreeFamiliesSponsorship)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
apps/web/src/app/billing/shared/billing-free-families-nav-item.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<bit-nav-item | ||
[text]="'sponsoredFamilies' | i18n" | ||
route="settings/sponsored-families" | ||
*ngIf="showFreeFamilies$ | async" | ||
></bit-nav-item> |
22 changes: 22 additions & 0 deletions
22
apps/web/src/app/billing/shared/billing-free-families-nav-item.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { Component } from "@angular/core"; | ||
import { Observable } from "rxjs"; | ||
|
||
import { NavigationModule } from "@bitwarden/components"; | ||
|
||
import { FreeFamiliesPolicyService } from "../services/free-families-policy.service"; | ||
|
||
import { BillingSharedModule } from "./billing-shared.module"; | ||
|
||
@Component({ | ||
selector: "billing-free-families-nav-item", | ||
templateUrl: "./billing-free-families-nav-item.component.html", | ||
standalone: true, | ||
imports: [NavigationModule, BillingSharedModule], | ||
}) | ||
export class BillingFreeFamiliesNavItemComponent { | ||
showFreeFamilies$: Observable<boolean>; | ||
|
||
constructor(private freeFamiliesPolicyService: FreeFamiliesPolicyService) { | ||
this.showFreeFamilies$ = this.freeFamiliesPolicyService.showFreeFamilies$; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters