diff --git a/apps/browser/src/platform/ipc/background-communication-backend.ts b/apps/browser/src/platform/ipc/background-communication-backend.ts index 6c5b374dd56..1ebb835fa3b 100644 --- a/apps/browser/src/platform/ipc/background-communication-backend.ts +++ b/apps/browser/src/platform/ipc/background-communication-backend.ts @@ -18,7 +18,11 @@ export class BackgroundCommunicationBackend implements CommunicationBackend { return; } - void this.queue.enqueue({ ...message.message, source: { Web: { id: sender.tab.id } } }); + void this.queue.enqueue( + new IncomingMessage(message.message.payload, message.message.destination, { + Web: { id: sender.tab.id }, + }), + ); }); } diff --git a/apps/web/src/app/admin-console/organizations/members/members-routing.module.ts b/apps/web/src/app/admin-console/organizations/members/members-routing.module.ts index 9666630fc08..153a2f3a956 100644 --- a/apps/web/src/app/admin-console/organizations/members/members-routing.module.ts +++ b/apps/web/src/app/admin-console/organizations/members/members-routing.module.ts @@ -3,9 +3,10 @@ import { RouterModule, Routes } from "@angular/router"; import { canAccessMembersTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { SponsoredFamiliesComponent } from "../../../billing/settings/sponsored-families.component"; +import { FreeBitwardenFamiliesComponent } from "../../../billing/members/free-bitwarden-families.component"; import { organizationPermissionsGuard } from "../guards/org-permissions.guard"; +import { canAccessSponsoredFamilies } from "./../../../billing/guards/can-access-sponsored-families.guard"; import { MembersComponent } from "./members.component"; const routes: Routes = [ @@ -19,8 +20,8 @@ const routes: Routes = [ }, { path: "sponsored-families", - component: SponsoredFamiliesComponent, - canActivate: [organizationPermissionsGuard(canAccessMembersTab)], + component: FreeBitwardenFamiliesComponent, + canActivate: [organizationPermissionsGuard(canAccessMembersTab), canAccessSponsoredFamilies], data: { titleId: "sponsoredFamilies", }, diff --git a/apps/web/src/app/admin-console/organizations/sponsorships/families-for-enterprise-setup.component.ts b/apps/web/src/app/admin-console/organizations/sponsorships/families-for-enterprise-setup.component.ts index fdad689d982..57fe212fa65 100644 --- a/apps/web/src/app/admin-console/organizations/sponsorships/families-for-enterprise-setup.component.ts +++ b/apps/web/src/app/admin-console/organizations/sponsorships/families-for-enterprise-setup.component.ts @@ -43,6 +43,8 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit, OnDestroy { value.plan = PlanType.FamiliesAnnually; value.productTier = ProductTierType.Families; value.acceptingSponsorship = true; + value.planSponsorshipType = PlanSponsorshipType.FamiliesForEnterprise; + // eslint-disable-next-line rxjs-angular/prefer-takeuntil value.onSuccess.subscribe(this.onOrganizationCreateSuccess.bind(this)); } diff --git a/apps/web/src/app/billing/guards/can-access-sponsored-families.guard.ts b/apps/web/src/app/billing/guards/can-access-sponsored-families.guard.ts new file mode 100644 index 00000000000..9bc6778f0b0 --- /dev/null +++ b/apps/web/src/app/billing/guards/can-access-sponsored-families.guard.ts @@ -0,0 +1,26 @@ +import { inject } from "@angular/core"; +import { ActivatedRouteSnapshot, CanActivateFn } from "@angular/router"; +import { firstValueFrom, switchMap, filter } from "rxjs"; + +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { getUserId } from "@bitwarden/common/auth/services/account.service"; +import { getById } from "@bitwarden/common/platform/misc"; + +import { FreeFamiliesPolicyService } from "../services/free-families-policy.service"; + +export const canAccessSponsoredFamilies: CanActivateFn = async (route: ActivatedRouteSnapshot) => { + const freeFamiliesPolicyService = inject(FreeFamiliesPolicyService); + const organizationService = inject(OrganizationService); + const accountService = inject(AccountService); + + const org = accountService.activeAccount$.pipe( + getUserId, + switchMap((userId) => organizationService.organizations$(userId)), + getById(route.params.organizationId), + filter((org): org is Organization => org !== undefined), + ); + + return await firstValueFrom(freeFamiliesPolicyService.showSponsoredFamiliesDropdown$(org)); +}; diff --git a/apps/web/src/app/billing/members/add-sponsorship-dialog.component.html b/apps/web/src/app/billing/members/add-sponsorship-dialog.component.html new file mode 100644 index 00000000000..2dbcc577e54 --- /dev/null +++ b/apps/web/src/app/billing/members/add-sponsorship-dialog.component.html @@ -0,0 +1,45 @@ +
diff --git a/apps/web/src/app/billing/members/add-sponsorship-dialog.component.ts b/apps/web/src/app/billing/members/add-sponsorship-dialog.component.ts new file mode 100644 index 00000000000..54d9ae90009 --- /dev/null +++ b/apps/web/src/app/billing/members/add-sponsorship-dialog.component.ts @@ -0,0 +1,135 @@ +import { DialogRef } from "@angular/cdk/dialog"; +import { Component } from "@angular/core"; +import { + AbstractControl, + FormBuilder, + FormControl, + FormGroup, + FormsModule, + ReactiveFormsModule, + ValidationErrors, + Validators, +} from "@angular/forms"; +import { firstValueFrom, map } from "rxjs"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { ButtonModule, DialogModule, DialogService, FormFieldModule } from "@bitwarden/components"; + +interface RequestSponsorshipForm { + sponsorshipEmail: FormControl{{ "sponsoredFamiliesRemoveActiveSponsorship" | i18n }}
diff --git a/apps/web/src/app/billing/members/free-bitwarden-families.component.ts b/apps/web/src/app/billing/members/free-bitwarden-families.component.ts new file mode 100644 index 00000000000..af43e5a4bc1 --- /dev/null +++ b/apps/web/src/app/billing/members/free-bitwarden-families.component.ts @@ -0,0 +1,62 @@ +import { DialogRef } from "@angular/cdk/dialog"; +import { Component, OnInit } from "@angular/core"; +import { Router } from "@angular/router"; +import { firstValueFrom } from "rxjs"; + +import { DialogService } from "@bitwarden/components"; + +import { FreeFamiliesPolicyService } from "../services/free-families-policy.service"; + +import { + AddSponsorshipDialogComponent, + AddSponsorshipDialogResult, +} from "./add-sponsorship-dialog.component"; +import { SponsoredFamily } from "./types/sponsored-family"; + +@Component({ + selector: "app-free-bitwarden-families", + templateUrl: "free-bitwarden-families.component.html", +}) +export class FreeBitwardenFamiliesComponent implements OnInit { + tabIndex = 0; + sponsoredFamilies: SponsoredFamily[] = []; + + constructor( + private router: Router, + private dialogService: DialogService, + private freeFamiliesPolicyService: FreeFamiliesPolicyService, + ) {} + + async ngOnInit() { + await this.preventAccessToFreeFamiliesPage(); + } + + async addSponsorship() { + const addSponsorshipDialogRef: DialogRef+ {{ "membersWithSponsoredFamilies" | i18n }} +
+ +{{ "noMemberFamiliesDescription" | i18n }}
++ {{ "sponsorFreeBitwardenFamilies" | i18n }} +
+{{ "noSponsoredFamiliesDescription" | i18n }}
+{{ "compromisedData" | i18n }}:
-{{ "compromisedData" | i18n }}:
+