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" },