diff --git a/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts b/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts
index 70e16ad3037..e0c1a12a80f 100644
--- a/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts
+++ b/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts
@@ -344,6 +344,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
data: {
type: "Organization",
id: this.organizationId,
+ plan: this.sub.plan.type,
},
});
diff --git a/apps/web/src/app/billing/shared/offboarding-survey.component.html b/apps/web/src/app/billing/shared/offboarding-survey.component.html
index b69565d95fa..50cf71a03d5 100644
--- a/apps/web/src/app/billing/shared/offboarding-survey.component.html
+++ b/apps/web/src/app/billing/shared/offboarding-survey.component.html
@@ -21,7 +21,8 @@
{{
- "charactersCurrentAndMaximum" | i18n: formGroup.value.feedback.length : MaxFeedbackLength
+ "charactersCurrentAndMaximum"
+ | i18n: formGroup.value.feedback?.length ?? 0 : MaxFeedbackLength
}}
diff --git a/apps/web/src/app/billing/shared/offboarding-survey.component.ts b/apps/web/src/app/billing/shared/offboarding-survey.component.ts
index fe7d724a079..40e1572a3bb 100644
--- a/apps/web/src/app/billing/shared/offboarding-survey.component.ts
+++ b/apps/web/src/app/billing/shared/offboarding-survey.component.ts
@@ -1,9 +1,10 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
-import { Component, Inject } from "@angular/core";
+import { ChangeDetectionStrategy, Component, Inject } from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms";
import { BillingApiServiceAbstraction as BillingApiService } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
+import { PlanType } from "@bitwarden/common/billing/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import {
@@ -21,6 +22,7 @@ type UserOffboardingParams = {
type OrganizationOffboardingParams = {
type: "Organization";
id: string;
+ plan: PlanType;
};
export type OffboardingSurveyDialogParams = UserOffboardingParams | OrganizationOffboardingParams;
@@ -46,50 +48,20 @@ export const openOffboardingSurvey = (
dialogConfig,
);
-// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
-// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "app-cancel-subscription-form",
templateUrl: "offboarding-survey.component.html",
+ changeDetection: ChangeDetectionStrategy.OnPush,
standalone: false,
})
export class OffboardingSurveyComponent {
protected ResultType = OffboardingSurveyDialogResultType;
protected readonly MaxFeedbackLength = 400;
- protected readonly reasons: Reason[] = [
- {
- value: null,
- text: this.i18nService.t("selectPlaceholder"),
- },
- {
- value: "missing_features",
- text: this.i18nService.t("missingFeatures"),
- },
- {
- value: "switched_service",
- text: this.i18nService.t("movingToAnotherTool"),
- },
- {
- value: "too_complex",
- text: this.i18nService.t("tooDifficultToUse"),
- },
- {
- value: "unused",
- text: this.i18nService.t("notUsingEnough"),
- },
- {
- value: "too_expensive",
- text: this.i18nService.t("tooExpensive"),
- },
- {
- value: "other",
- text: this.i18nService.t("other"),
- },
- ];
+ protected readonly reasons: Reason[] = [];
protected formGroup = this.formBuilder.group({
- reason: [this.reasons[0].value, [Validators.required]],
+ reason: [null, [Validators.required]],
feedback: ["", [Validators.maxLength(this.MaxFeedbackLength)]],
});
@@ -101,7 +73,35 @@ export class OffboardingSurveyComponent {
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
private toastService: ToastService,
- ) {}
+ ) {
+ this.reasons = [
+ {
+ value: null,
+ text: this.i18nService.t("selectPlaceholder"),
+ },
+ {
+ value: "missing_features",
+ text: this.i18nService.t("missingFeatures"),
+ },
+ {
+ value: "switched_service",
+ text: this.i18nService.t("movingToAnotherTool"),
+ },
+ {
+ value: "too_complex",
+ text: this.i18nService.t("tooDifficultToUse"),
+ },
+ {
+ value: "unused",
+ text: this.i18nService.t("notUsingEnough"),
+ },
+ this.getSwitchingReason(),
+ {
+ value: "other",
+ text: this.i18nService.t("other"),
+ },
+ ];
+ }
submit = async () => {
this.formGroup.markAllAsTouched();
@@ -127,4 +127,24 @@ export class OffboardingSurveyComponent {
this.dialogRef.close(this.ResultType.Submitted);
};
+
+ private getSwitchingReason(): Reason {
+ if (this.dialogParams.type === "User") {
+ return {
+ value: "too_expensive",
+ text: this.i18nService.t("switchToFreePlan"),
+ };
+ }
+
+ const isFamilyPlan = [
+ PlanType.FamiliesAnnually,
+ PlanType.FamiliesAnnually2019,
+ PlanType.FamiliesAnnually2025,
+ ].includes(this.dialogParams.plan);
+
+ return {
+ value: "too_expensive",
+ text: this.i18nService.t(isFamilyPlan ? "switchToFreeOrg" : "tooExpensive"),
+ };
+ }
}
diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json
index 0c87e00b26c..5cf1bea6fd8 100644
--- a/apps/web/src/locales/en/messages.json
+++ b/apps/web/src/locales/en/messages.json
@@ -9824,6 +9824,14 @@
"message": "Too expensive",
"description": "An option for the offboarding survey shown when a user cancels their subscription."
},
+ "switchToFreePlan": {
+ "message": "Switching to free plan",
+ "description": "An option for the offboarding survey shown when a user cancels their subscription."
+ },
+ "switchToFreeOrg": {
+ "message": "Switching to free organization",
+ "description": "An option for the offboarding survey shown when a user cancels their subscription."
+ },
"freeForOneYear": {
"message": "Free for 1 year"
},