mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-07 19:07:45 +01:00
[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
This commit is contained in:
parent
59686346d4
commit
d76b5b672c
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -8,13 +8,17 @@ import {
|
|||||||
AsyncValidatorFn,
|
AsyncValidatorFn,
|
||||||
ValidationErrors,
|
ValidationErrors,
|
||||||
} from "@angular/forms";
|
} from "@angular/forms";
|
||||||
import { firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs";
|
import { combineLatest, firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
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 { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { PlanSponsorshipType } from "@bitwarden/common/billing/enums";
|
import { PlanSponsorshipType } from "@bitwarden/common/billing/enums";
|
||||||
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
@ -31,6 +35,7 @@ interface RequestSponsorshipForm {
|
|||||||
})
|
})
|
||||||
export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
||||||
loading = false;
|
loading = false;
|
||||||
|
isFreeFamilyFlagEnabled: boolean;
|
||||||
|
|
||||||
availableSponsorshipOrgs$: Observable<Organization[]>;
|
availableSponsorshipOrgs$: Observable<Organization[]>;
|
||||||
activeSponsorshipOrgs$: Observable<Organization[]>;
|
activeSponsorshipOrgs$: Observable<Organization[]>;
|
||||||
@ -53,6 +58,8 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
|||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
|
private configService: ConfigService,
|
||||||
|
private policyService: PolicyService,
|
||||||
) {
|
) {
|
||||||
this.sponsorshipForm = this.formBuilder.group<RequestSponsorshipForm>({
|
this.sponsorshipForm = this.formBuilder.group<RequestSponsorshipForm>({
|
||||||
selectedSponsorshipOrgId: new FormControl("", {
|
selectedSponsorshipOrgId: new FormControl("", {
|
||||||
@ -72,9 +79,33 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
|
this.isFreeFamilyFlagEnabled = await this.configService.getFeatureFlag(
|
||||||
|
FeatureFlag.DisableFreeFamiliesSponsorship,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.isFreeFamilyFlagEnabled) {
|
||||||
|
this.availableSponsorshipOrgs$ = combineLatest([
|
||||||
|
this.organizationService.organizations$,
|
||||||
|
this.policyService.getAll$(PolicyType.FreeFamiliesSponsorshipPolicy),
|
||||||
|
]).pipe(
|
||||||
|
map(([organizations, policies]) =>
|
||||||
|
organizations
|
||||||
|
.filter((org) => org.familySponsorshipAvailable)
|
||||||
|
.map((org) => ({
|
||||||
|
organization: org,
|
||||||
|
isPolicyEnabled: policies.some(
|
||||||
|
(policy) => policy.organizationId === org.id && policy.enabled,
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
.filter(({ isPolicyEnabled }) => !isPolicyEnabled)
|
||||||
|
.map(({ organization }) => organization),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
this.availableSponsorshipOrgs$ = this.organizationService.organizations$.pipe(
|
this.availableSponsorshipOrgs$ = this.organizationService.organizations$.pipe(
|
||||||
map((orgs) => orgs.filter((o) => o.familySponsorshipAvailable)),
|
map((orgs) => orgs.filter((o) => o.familySponsorshipAvailable)),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.availableSponsorshipOrgs$.pipe(takeUntil(this._destroy)).subscribe((orgs) => {
|
this.availableSponsorshipOrgs$.pipe(takeUntil(this._destroy)).subscribe((orgs) => {
|
||||||
if (orgs.length === 1) {
|
if (orgs.length === 1) {
|
||||||
|
@ -18,7 +18,11 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
bitMenuItem
|
bitMenuItem
|
||||||
*ngIf="!isSelfHosted && !sponsoringOrg.familySponsorshipValidUntil"
|
*ngIf="
|
||||||
|
!isSelfHosted &&
|
||||||
|
!sponsoringOrg.familySponsorshipValidUntil &&
|
||||||
|
!(isFreeFamilyPolicyEnabled$ | async)
|
||||||
|
"
|
||||||
(click)="resendEmail()"
|
(click)="resendEmail()"
|
||||||
[attr.aria-label]="'resendEmailLabel' | i18n: sponsoringOrg.familySponsorshipFriendlyName"
|
[attr.aria-label]="'resendEmailLabel' | i18n: sponsoringOrg.familySponsorshipFriendlyName"
|
||||||
>
|
>
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import { formatDate } from "@angular/common";
|
import { formatDate } from "@angular/common";
|
||||||
import { Component, EventEmitter, Input, Output, OnInit } from "@angular/core";
|
import { Component, EventEmitter, Input, Output, OnInit } from "@angular/core";
|
||||||
import { firstValueFrom } from "rxjs";
|
import { firstValueFrom, map, Observable } from "rxjs";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
|
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 { 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";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@ -21,7 +25,8 @@ export class SponsoringOrgRowComponent implements OnInit {
|
|||||||
|
|
||||||
statusMessage = "loading";
|
statusMessage = "loading";
|
||||||
statusClass: "tw-text-success" | "tw-text-danger" = "tw-text-success";
|
statusClass: "tw-text-success" | "tw-text-danger" = "tw-text-success";
|
||||||
|
isFreeFamilyPolicyEnabled$: Observable<boolean>;
|
||||||
|
isFreeFamilyFlagEnabled: boolean;
|
||||||
private locale = "";
|
private locale = "";
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -31,6 +36,8 @@ export class SponsoringOrgRowComponent implements OnInit {
|
|||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
|
private configService: ConfigService,
|
||||||
|
private policyService: PolicyService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@ -42,6 +49,23 @@ export class SponsoringOrgRowComponent implements OnInit {
|
|||||||
this.sponsoringOrg.familySponsorshipValidUntil,
|
this.sponsoringOrg.familySponsorshipValidUntil,
|
||||||
this.sponsoringOrg.familySponsorshipLastSyncDate,
|
this.sponsoringOrg.familySponsorshipLastSyncDate,
|
||||||
);
|
);
|
||||||
|
this.isFreeFamilyFlagEnabled = await this.configService.getFeatureFlag(
|
||||||
|
FeatureFlag.DisableFreeFamiliesSponsorship,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.isFreeFamilyFlagEnabled) {
|
||||||
|
this.isFreeFamilyPolicyEnabled$ = this.policyService
|
||||||
|
.getAll$(PolicyType.FreeFamiliesSponsorshipPolicy)
|
||||||
|
.pipe(
|
||||||
|
map(
|
||||||
|
(policies) =>
|
||||||
|
Array.isArray(policies) &&
|
||||||
|
policies.some(
|
||||||
|
(policy) => policy.organizationId === this.sponsoringOrg.id && policy.enabled,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async revokeSponsorship() {
|
async revokeSponsorship() {
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
<bit-nav-item
|
||||||
|
[text]="'sponsoredFamilies' | i18n"
|
||||||
|
route="settings/sponsored-families"
|
||||||
|
*ngIf="showFreeFamilies$ | async"
|
||||||
|
></bit-nav-item>
|
@ -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$;
|
||||||
|
}
|
||||||
|
}
|
@ -24,11 +24,7 @@
|
|||||||
[text]="'emergencyAccess' | i18n"
|
[text]="'emergencyAccess' | i18n"
|
||||||
route="settings/emergency-access"
|
route="settings/emergency-access"
|
||||||
></bit-nav-item>
|
></bit-nav-item>
|
||||||
<bit-nav-item
|
<billing-free-families-nav-item></billing-free-families-nav-item>
|
||||||
[text]="'sponsoredFamilies' | i18n"
|
|
||||||
route="settings/sponsored-families"
|
|
||||||
*ngIf="hasFamilySponsorshipAvailable$ | async"
|
|
||||||
></bit-nav-item>
|
|
||||||
</bit-nav-group>
|
</bit-nav-group>
|
||||||
</app-side-nav>
|
</app-side-nav>
|
||||||
|
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { RouterModule } from "@angular/router";
|
import { RouterModule } from "@angular/router";
|
||||||
import { Observable, combineLatest, concatMap } from "rxjs";
|
import { Observable, concatMap, combineLatest } from "rxjs";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||||
import { IconModule } from "@bitwarden/components";
|
import { IconModule } from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { BillingFreeFamiliesNavItemComponent } from "../billing/shared/billing-free-families-nav-item.component";
|
||||||
|
|
||||||
import { PasswordManagerLogo } from "./password-manager-logo";
|
import { PasswordManagerLogo } from "./password-manager-logo";
|
||||||
import { WebLayoutModule } from "./web-layout.module";
|
import { WebLayoutModule } from "./web-layout.module";
|
||||||
|
|
||||||
@ -18,16 +19,24 @@ import { WebLayoutModule } from "./web-layout.module";
|
|||||||
selector: "app-user-layout",
|
selector: "app-user-layout",
|
||||||
templateUrl: "user-layout.component.html",
|
templateUrl: "user-layout.component.html",
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, RouterModule, JslibModule, WebLayoutModule, IconModule],
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
RouterModule,
|
||||||
|
JslibModule,
|
||||||
|
WebLayoutModule,
|
||||||
|
IconModule,
|
||||||
|
BillingFreeFamiliesNavItemComponent,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class UserLayoutComponent implements OnInit {
|
export class UserLayoutComponent implements OnInit {
|
||||||
protected readonly logo = PasswordManagerLogo;
|
protected readonly logo = PasswordManagerLogo;
|
||||||
|
isFreeFamilyFlagEnabled: boolean;
|
||||||
protected hasFamilySponsorshipAvailable$: Observable<boolean>;
|
protected hasFamilySponsorshipAvailable$: Observable<boolean>;
|
||||||
|
protected showSponsoredFamilies$: Observable<boolean>;
|
||||||
protected showSubscription$: Observable<boolean>;
|
protected showSubscription$: Observable<boolean>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
private organizationService: OrganizationService,
|
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private syncService: SyncService,
|
private syncService: SyncService,
|
||||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
@ -38,8 +47,6 @@ export class UserLayoutComponent implements OnInit {
|
|||||||
|
|
||||||
await this.syncService.fullSync(false);
|
await this.syncService.fullSync(false);
|
||||||
|
|
||||||
this.hasFamilySponsorshipAvailable$ = this.organizationService.canManageSponsorships$;
|
|
||||||
|
|
||||||
// We want to hide the subscription menu for organizations that provide premium.
|
// We want to hide the subscription menu for organizations that provide premium.
|
||||||
// Except if the user has premium personally or has a billing history.
|
// Except if the user has premium personally or has a billing history.
|
||||||
this.showSubscription$ = combineLatest([
|
this.showSubscription$ = combineLatest([
|
||||||
|
Loading…
Reference in New Issue
Block a user