diff --git a/apps/web/src/app/billing/individual/premium/setup-premium.component.html b/apps/web/src/app/billing/individual/premium/setup-premium.component.html
new file mode 100644
index 00000000000..e59219ca13e
--- /dev/null
+++ b/apps/web/src/app/billing/individual/premium/setup-premium.component.html
@@ -0,0 +1,8 @@
+
Setup Premium
+
+
+
+
+
diff --git a/apps/web/src/app/billing/individual/premium/setup-premium.component.ts b/apps/web/src/app/billing/individual/premium/setup-premium.component.ts
new file mode 100644
index 00000000000..75e9df2d7e6
--- /dev/null
+++ b/apps/web/src/app/billing/individual/premium/setup-premium.component.ts
@@ -0,0 +1,41 @@
+import { Component, OnInit } from "@angular/core";
+import { Router } from "@angular/router";
+import { firstValueFrom } from "rxjs";
+
+import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
+import { ButtonModule } from "@bitwarden/components";
+import { UserId } from "@bitwarden/user-core";
+
+import { SetupPremiumService } from "./setup-premium.service";
+
+@Component({
+ templateUrl: "./setup-premium.component.html",
+ standalone: true,
+ imports: [ButtonModule],
+})
+export class SetupPremiumComponent implements OnInit {
+ userId: UserId;
+
+ constructor(
+ private accountService: AccountService,
+ private router: Router,
+ private setupPremiumService: SetupPremiumService,
+ ) {}
+
+ async ngOnInit(): Promise {
+ const currentAcct = await firstValueFrom(this.accountService.activeAccount$);
+ this.userId = currentAcct.id;
+ }
+
+ async clickSetup() {
+ // Insert logic for setting up premium...
+
+ await this.setupPremiumService.clearIntentToSetupPremium(this.userId);
+ await this.router.navigate(["/vault"]);
+ }
+
+ async clickMaybeLater() {
+ await this.setupPremiumService.clearIntentToSetupPremium(this.userId);
+ await this.router.navigate(["/vault"]);
+ }
+}
diff --git a/apps/web/src/app/billing/individual/premium/setup-premium.service.ts b/apps/web/src/app/billing/individual/premium/setup-premium.service.ts
index ea3fdc6d080..ea9360f59e0 100644
--- a/apps/web/src/app/billing/individual/premium/setup-premium.service.ts
+++ b/apps/web/src/app/billing/individual/premium/setup-premium.service.ts
@@ -24,7 +24,9 @@ export class SetupPremiumService {
}
async getIntentToSetupPremium(userId: UserId) {
- await firstValueFrom(this.stateProvider.getUserState$(INTENT_TO_SETUP_PREMIUM_KEY, userId));
+ return await firstValueFrom(
+ this.stateProvider.getUserState$(INTENT_TO_SETUP_PREMIUM_KEY, userId),
+ );
}
async clearIntentToSetupPremium(userId: UserId) {
diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts
index 45ed6dc8eb9..e60f0f1814a 100644
--- a/apps/web/src/app/oss-routing.module.ts
+++ b/apps/web/src/app/oss-routing.module.ts
@@ -65,6 +65,7 @@ import { EmergencyAccessViewComponent } from "./auth/settings/emergency-access/v
import { SecurityRoutingModule } from "./auth/settings/security/security-routing.module";
import { VerifyEmailTokenComponent } from "./auth/verify-email-token.component";
import { VerifyRecoverDeleteComponent } from "./auth/verify-recover-delete.component";
+import { SetupPremiumComponent } from "./billing/individual/premium/setup-premium.component";
import { SponsoredFamiliesComponent } from "./billing/settings/sponsored-families.component";
import { CompleteTrialInitiationComponent } from "./billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component";
import { freeTrialTextResolver } from "./billing/trial-initiation/complete-trial-initiation/resolver/free-trial-text.resolver";
@@ -86,6 +87,7 @@ import { BrowserExtensionPromptInstallComponent } from "./vault/components/brows
import { BrowserExtensionPromptComponent } from "./vault/components/browser-extension-prompt/browser-extension-prompt.component";
import { SetupExtensionComponent } from "./vault/components/setup-extension/setup-extension.component";
import { setupExtensionRedirectGuard } from "./vault/guards/setup-extension-redirect.guard";
+import { setupPremiumRedirectGuard } from "./vault/guards/setup-premium-redirect.guard";
import { VaultModule } from "./vault/individual-vault/vault.module";
const routes: Routes = [
@@ -617,6 +619,10 @@ const routes: Routes = [
},
],
},
+ {
+ path: "setup-premium",
+ component: SetupPremiumComponent,
+ },
],
},
{
@@ -626,7 +632,7 @@ const routes: Routes = [
children: [
{
path: "vault",
- canActivate: [setupExtensionRedirectGuard],
+ canActivate: [setupPremiumRedirectGuard, setupExtensionRedirectGuard],
loadChildren: () => VaultModule,
},
{
diff --git a/apps/web/src/app/vault/guards/setup-premium-redirect.guard.ts b/apps/web/src/app/vault/guards/setup-premium-redirect.guard.ts
new file mode 100644
index 00000000000..0094c725ad3
--- /dev/null
+++ b/apps/web/src/app/vault/guards/setup-premium-redirect.guard.ts
@@ -0,0 +1,23 @@
+import { inject } from "@angular/core";
+import { CanActivateFn, Router } from "@angular/router";
+import { firstValueFrom } from "rxjs";
+
+import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
+
+import { SetupPremiumService } from "../../billing/individual/premium/setup-premium.service";
+
+export const setupPremiumRedirectGuard: CanActivateFn = async () => {
+ const router = inject(Router);
+ const accountService = inject(AccountService);
+ const setupPremiumService = inject(SetupPremiumService);
+
+ const currentAcct = await firstValueFrom(accountService.activeAccount$);
+
+ const intentToSetupPremium = await setupPremiumService.getIntentToSetupPremium(currentAcct.id);
+
+ if (intentToSetupPremium) {
+ return router.createUrlTree(["/setup-premium"]);
+ }
+
+ return true;
+};
diff --git a/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts b/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts
index 18623ea692e..8f4bae3bc85 100644
--- a/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts
+++ b/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts
@@ -142,8 +142,7 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy {
// ```
// export const MarketingInitiative = Object.freeze({
// Premium: "premium",
- // Families: "families",
- // // Other variants in the future
+ // // Families: "families", // easy to add if asked to in the future
// } as const);
// -- Proof of Concept (end) --
@@ -211,11 +210,13 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy {
await this.loginSuccessHandlerService.run(authenticationResult.userId);
+ // -- Proof of Concept (start) --
if (this.intendsToSetupPremium) {
await this.registrationFinishService.establishIntentToSetupPremium(
authenticationResult.userId,
);
}
+ // -- Proof of Concept (end) --
await this.router.navigate(["/vault"]);
} catch (e) {