mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-18 15:47:57 +01:00
[PM-15545][Defect] Update trial initiation UI for new flow via trial/send-verification-email endpoint (#12256)
* Add the on trial payment option on new UI * Rename variables correctly * Resolve the isTrialPaymentOptional and use observable * use firstValueFrom and remove subscribe * Resolve the selected plantype * Changes for free Org
This commit is contained in:
parent
30c151f44a
commit
bfa9cf3623
@ -23,12 +23,17 @@
|
||||
bitButton
|
||||
buttonType="primary"
|
||||
[disabled]="orgInfoFormGroup.controls.name.invalid"
|
||||
(click)="conditionallyCreateOrganization()"
|
||||
[loading]="loading && (trialPaymentOptional$ | async)"
|
||||
(click)="orgNameEntrySubmit()"
|
||||
>
|
||||
{{ "next" | i18n }}
|
||||
{{ (trialPaymentOptional$ | async) ? ("startTrial" | i18n) : ("next" | i18n) }}
|
||||
</button>
|
||||
</app-vertical-step>
|
||||
<app-vertical-step label="Billing" [subLabel]="billingSubLabel" *ngIf="!isSecretsManagerFree">
|
||||
<app-vertical-step
|
||||
label="Billing"
|
||||
[subLabel]="billingSubLabel"
|
||||
*ngIf="!(trialPaymentOptional$ | async) && !isSecretsManagerFree"
|
||||
>
|
||||
<app-trial-billing-step
|
||||
*ngIf="stepper.selectedIndex === 2"
|
||||
[organizationInfo]="{
|
||||
|
@ -4,7 +4,7 @@ import { StepperSelectionEvent } from "@angular/cdk/stepper";
|
||||
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import { firstValueFrom, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { PasswordInputResult, RegistrationFinishService } from "@bitwarden/auth/angular";
|
||||
import { LoginStrategyServiceAbstraction, PasswordLoginCredentials } from "@bitwarden/auth/common";
|
||||
@ -12,8 +12,14 @@ import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abs
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { OrganizationBillingServiceAbstraction as OrganizationBillingService } from "@bitwarden/common/billing/abstractions/organization-billing.service";
|
||||
import { ProductTierType, ProductType } from "@bitwarden/common/billing/enums";
|
||||
import {
|
||||
OrganizationBillingServiceAbstraction as OrganizationBillingService,
|
||||
OrganizationInformation,
|
||||
PlanInformation,
|
||||
} from "@bitwarden/common/billing/abstractions/organization-billing.service";
|
||||
import { PlanType, ProductTierType, ProductType } 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 { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||
@ -28,6 +34,10 @@ import { RouterService } from "../../../core/router.service";
|
||||
import { AcceptOrganizationInviteService } from "../../organization-invite/accept-organization.service";
|
||||
import { VerticalStepperComponent } from "../vertical-stepper/vertical-stepper.component";
|
||||
|
||||
export type InitiationPath =
|
||||
| "Password Manager trial from marketing website"
|
||||
| "Secrets Manager trial from marketing website";
|
||||
|
||||
@Component({
|
||||
selector: "app-complete-trial-initiation",
|
||||
templateUrl: "complete-trial-initiation.component.html",
|
||||
@ -65,6 +75,8 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy {
|
||||
email = "";
|
||||
/** Token from the backend associated with the email verification */
|
||||
emailVerificationToken: string;
|
||||
loading = false;
|
||||
productTierValue: number;
|
||||
|
||||
orgInfoFormGroup = this.formBuilder.group({
|
||||
name: ["", { validators: [Validators.required, Validators.maxLength(50)], updateOn: "change" }],
|
||||
@ -74,6 +86,9 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy {
|
||||
private destroy$ = new Subject<void>();
|
||||
protected readonly SubscriptionProduct = SubscriptionProduct;
|
||||
protected readonly ProductType = ProductType;
|
||||
protected trialPaymentOptional$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.TrialPaymentOptional,
|
||||
);
|
||||
|
||||
constructor(
|
||||
protected router: Router,
|
||||
@ -90,6 +105,7 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy {
|
||||
private registrationFinishService: RegistrationFinishService,
|
||||
private validationService: ValidationService,
|
||||
private loginStrategyService: LoginStrategyServiceAbstraction,
|
||||
private configService: ConfigService,
|
||||
) {}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
@ -119,6 +135,7 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy {
|
||||
this.product = this.validProducts.includes(product) ? product : ProductType.PasswordManager;
|
||||
|
||||
const productTierParam = parseInt(qParams.productTier) as ProductTierType;
|
||||
this.productTierValue = productTierParam;
|
||||
|
||||
/** Only show the trial stepper for a subset of types */
|
||||
const showPasswordManagerStepper = this.stepperProductTypes.includes(productTierParam);
|
||||
@ -185,6 +202,16 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
async orgNameEntrySubmit(): Promise<void> {
|
||||
const isTrialPaymentOptional = await firstValueFrom(this.trialPaymentOptional$);
|
||||
|
||||
if (isTrialPaymentOptional) {
|
||||
await this.createOrganizationOnTrial();
|
||||
} else {
|
||||
await this.conditionallyCreateOrganization();
|
||||
}
|
||||
}
|
||||
|
||||
/** Update local details from organization created event */
|
||||
createdOrganization(event: OrganizationCreatedEvent) {
|
||||
this.orgId = event.organizationId;
|
||||
@ -192,11 +219,62 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy {
|
||||
this.verticalStepper.next();
|
||||
}
|
||||
|
||||
/** create an organization on trial without payment method */
|
||||
async createOrganizationOnTrial() {
|
||||
this.loading = true;
|
||||
let trialInitiationPath: InitiationPath = "Password Manager trial from marketing website";
|
||||
let plan: PlanInformation = {
|
||||
type: this.getPlanType(),
|
||||
passwordManagerSeats: 1,
|
||||
};
|
||||
|
||||
if (this.product === ProductType.SecretsManager) {
|
||||
trialInitiationPath = "Secrets Manager trial from marketing website";
|
||||
plan = {
|
||||
...plan,
|
||||
subscribeToSecretsManager: true,
|
||||
isFromSecretsManagerTrial: true,
|
||||
secretsManagerSeats: 1,
|
||||
};
|
||||
}
|
||||
|
||||
const organization: OrganizationInformation = {
|
||||
name: this.orgInfoFormGroup.value.name,
|
||||
billingEmail: this.orgInfoFormGroup.value.billingEmail,
|
||||
initiationPath: trialInitiationPath,
|
||||
};
|
||||
|
||||
const response = await this.organizationBillingService.purchaseSubscriptionNoPaymentMethod({
|
||||
organization,
|
||||
plan,
|
||||
});
|
||||
|
||||
this.orgId = response?.id;
|
||||
this.billingSubLabel = response.name.toString();
|
||||
this.loading = false;
|
||||
this.verticalStepper.next();
|
||||
}
|
||||
|
||||
/** Move the user to the previous step */
|
||||
previousStep() {
|
||||
this.verticalStepper.previous();
|
||||
}
|
||||
|
||||
getPlanType() {
|
||||
switch (this.productTier) {
|
||||
case ProductTierType.Teams:
|
||||
return PlanType.TeamsAnnually;
|
||||
case ProductTierType.Enterprise:
|
||||
return PlanType.EnterpriseAnnually;
|
||||
case ProductTierType.Families:
|
||||
return PlanType.FamiliesAnnually;
|
||||
case ProductTierType.Free:
|
||||
return PlanType.Free;
|
||||
default:
|
||||
return PlanType.EnterpriseAnnually;
|
||||
}
|
||||
}
|
||||
|
||||
get isSecretsManagerFree() {
|
||||
return this.product === ProductType.SecretsManager && this.productTier === ProductTierType.Free;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user