1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-22 11:45:59 +01:00

Remove FF 'AC-1607_present-user-offboarding-survey' and old cancel functionality (#8322)

This commit is contained in:
Alex Morask 2024-03-21 15:04:29 -04:00 committed by GitHub
parent 9a70e63e73
commit c4c275604b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 22 additions and 140 deletions

View File

@ -145,7 +145,7 @@
type="button" type="button"
buttonType="danger" buttonType="danger"
class="btn-submit tw-ml-auto" class="btn-submit tw-ml-auto"
(click)="cancel()" (click)="cancelSubscription()"
[appApiAction]="cancelPromise" [appApiAction]="cancelPromise"
[disabled]="$any(cancelBtn).loading" [disabled]="$any(cancelBtn).loading"
*ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel" *ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel"

View File

@ -1,12 +1,10 @@
import { Component, OnInit } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { firstValueFrom, lastValueFrom, Observable } from "rxjs"; import { firstValueFrom, lastValueFrom } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { SubscriptionResponse } from "@bitwarden/common/billing/models/response/subscription.response"; import { SubscriptionResponse } from "@bitwarden/common/billing/models/response/subscription.response";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigServiceAbstraction as ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -34,7 +32,6 @@ export class UserSubscriptionComponent implements OnInit {
cancelPromise: Promise<any>; cancelPromise: Promise<any>;
reinstatePromise: Promise<any>; reinstatePromise: Promise<any>;
presentUserWithOffboardingSurvey$: Observable<boolean>;
constructor( constructor(
private apiService: ApiService, private apiService: ApiService,
@ -45,7 +42,6 @@ export class UserSubscriptionComponent implements OnInit {
private fileDownloadService: FileDownloadService, private fileDownloadService: FileDownloadService,
private dialogService: DialogService, private dialogService: DialogService,
private environmentService: EnvironmentService, private environmentService: EnvironmentService,
private configService: ConfigService,
private billingAccountProfileStateService: BillingAccountProfileStateService, private billingAccountProfileStateService: BillingAccountProfileStateService,
) { ) {
this.selfHosted = platformUtilsService.isSelfHost(); this.selfHosted = platformUtilsService.isSelfHost();
@ -53,9 +49,6 @@ export class UserSubscriptionComponent implements OnInit {
async ngOnInit() { async ngOnInit() {
this.cloudWebVaultUrl = await firstValueFrom(this.environmentService.cloudWebVaultUrl$); this.cloudWebVaultUrl = await firstValueFrom(this.environmentService.cloudWebVaultUrl$);
this.presentUserWithOffboardingSurvey$ = this.configService.getFeatureFlag$<boolean>(
FeatureFlag.AC1607_PresentUserOffboardingSurvey,
);
await this.load(); await this.load();
this.firstLoaded = true; this.firstLoaded = true;
} }
@ -105,16 +98,22 @@ export class UserSubscriptionComponent implements OnInit {
} }
} }
cancel = async () => { cancelSubscription = async () => {
const presentUserWithOffboardingSurvey = await this.configService.getFeatureFlag<boolean>( const reference = openOffboardingSurvey(this.dialogService, {
FeatureFlag.AC1607_PresentUserOffboardingSurvey, data: {
); type: "User",
},
});
if (presentUserWithOffboardingSurvey) { this.cancelPromise = lastValueFrom(reference.closed);
await this.cancelWithOffboardingSurvey();
} else { const result = await this.cancelPromise;
await this.cancelWithWarning();
if (result === OffboardingSurveyDialogResultType.Closed) {
return;
} }
await this.load();
}; };
downloadLicense() { downloadLicense() {
@ -159,55 +158,6 @@ export class UserSubscriptionComponent implements OnInit {
} }
} }
private cancelWithOffboardingSurvey = async () => {
const reference = openOffboardingSurvey(this.dialogService, {
data: {
type: "User",
},
});
this.cancelPromise = lastValueFrom(reference.closed);
const result = await this.cancelPromise;
if (result === OffboardingSurveyDialogResultType.Closed) {
return;
}
await this.load();
};
private async cancelWithWarning() {
if (this.loading) {
return;
}
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "cancelSubscription" },
content: { key: "cancelConfirmation" },
type: "warning",
});
if (!confirmed) {
return;
}
try {
this.cancelPromise = this.apiService.postCancelPremium();
await this.cancelPromise;
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("canceledSubscription"),
);
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.load();
} catch (e) {
this.logService.error(e);
}
}
get subscriptionMarkedForCancel() { get subscriptionMarkedForCancel() {
return ( return (
this.subscription != null && !this.subscription.cancelled && this.subscription.cancelAtEndDate this.subscription != null && !this.subscription.cancelled && this.subscription.cancelAtEndDate

View File

@ -232,28 +232,9 @@
<button <button
bitButton bitButton
buttonType="danger" buttonType="danger"
[bitAction]="cancelWithWarning" (click)="cancelSubscription()"
type="button" type="button"
*ngIf=" *ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel"
subscription &&
!subscription.cancelled &&
!subscriptionMarkedForCancel &&
!(presentUserWithOffboardingSurvey$ | async)
"
>
{{ "cancelSubscription" | i18n }}
</button>
<button
bitButton
buttonType="danger"
(click)="cancelWithOffboardingSurvey()"
type="button"
*ngIf="
subscription &&
!subscription.cancelled &&
!subscriptionMarkedForCancel &&
(presentUserWithOffboardingSurvey$ | async)
"
> >
{{ "cancelSubscription" | i18n }} {{ "cancelSubscription" | i18n }}
</button> </button>

View File

@ -1,6 +1,6 @@
import { Component, OnDestroy, OnInit } from "@angular/core"; import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router"; import { ActivatedRoute } from "@angular/router";
import { concatMap, firstValueFrom, lastValueFrom, Observable, Subject, takeUntil } from "rxjs"; import { concatMap, firstValueFrom, lastValueFrom, Subject, takeUntil } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
@ -11,8 +11,6 @@ import { PlanType } from "@bitwarden/common/billing/enums";
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response"; import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
import { BillingSubscriptionItemResponse } from "@bitwarden/common/billing/models/response/subscription.response"; import { BillingSubscriptionItemResponse } from "@bitwarden/common/billing/models/response/subscription.response";
import { ProductType } from "@bitwarden/common/enums"; import { ProductType } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigServiceAbstraction as ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@ -43,7 +41,6 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
showSecretsManagerSubscribe = false; showSecretsManagerSubscribe = false;
firstLoaded = false; firstLoaded = false;
loading: boolean; loading: boolean;
presentUserWithOffboardingSurvey$: Observable<boolean>;
protected readonly teamsStarter = ProductType.TeamsStarter; protected readonly teamsStarter = ProductType.TeamsStarter;
@ -58,7 +55,6 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
private organizationApiService: OrganizationApiServiceAbstraction, private organizationApiService: OrganizationApiServiceAbstraction,
private route: ActivatedRoute, private route: ActivatedRoute,
private dialogService: DialogService, private dialogService: DialogService,
private configService: ConfigService,
) {} ) {}
async ngOnInit() { async ngOnInit() {
@ -78,10 +74,6 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
takeUntil(this.destroy$), takeUntil(this.destroy$),
) )
.subscribe(); .subscribe();
this.presentUserWithOffboardingSurvey$ = this.configService.getFeatureFlag$<boolean>(
FeatureFlag.AC1607_PresentUserOffboardingSurvey,
);
} }
ngOnDestroy() { ngOnDestroy() {
@ -278,7 +270,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
); );
} }
cancelWithOffboardingSurvey = async () => { cancelSubscription = async () => {
const reference = openOffboardingSurvey(this.dialogService, { const reference = openOffboardingSurvey(this.dialogService, {
data: { data: {
type: "Organization", type: "Organization",
@ -295,36 +287,6 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
await this.load(); await this.load();
}; };
cancelWithWarning = async () => {
if (this.loading) {
return;
}
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "cancelSubscription" },
content: { key: "cancelConfirmation" },
type: "warning",
});
if (!confirmed) {
return;
}
try {
await this.organizationApiService.cancel(this.organizationId);
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("canceledSubscription"),
);
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.load();
} catch (e) {
this.logService.error(e);
}
};
reinstate = async () => { reinstate = async () => {
if (this.loading) { if (this.loading) {
return; return;

View File

@ -170,7 +170,6 @@ export abstract class ApiService {
postRegister: (request: RegisterRequest) => Promise<RegisterResponse>; postRegister: (request: RegisterRequest) => Promise<RegisterResponse>;
postPremium: (data: FormData) => Promise<PaymentResponse>; postPremium: (data: FormData) => Promise<PaymentResponse>;
postReinstatePremium: () => Promise<any>; postReinstatePremium: () => Promise<any>;
postCancelPremium: () => Promise<any>;
postAccountStorage: (request: StorageRequest) => Promise<PaymentResponse>; postAccountStorage: (request: StorageRequest) => Promise<PaymentResponse>;
postAccountPayment: (request: PaymentRequest) => Promise<void>; postAccountPayment: (request: PaymentRequest) => Promise<void>;
postAccountLicense: (data: FormData) => Promise<any>; postAccountLicense: (data: FormData) => Promise<any>;

View File

@ -51,7 +51,6 @@ export class OrganizationApiServiceAbstraction {
updateSeats: (id: string, request: SeatRequest) => Promise<PaymentResponse>; updateSeats: (id: string, request: SeatRequest) => Promise<PaymentResponse>;
updateStorage: (id: string, request: StorageRequest) => Promise<PaymentResponse>; updateStorage: (id: string, request: StorageRequest) => Promise<PaymentResponse>;
verifyBank: (id: string, request: VerifyBankRequest) => Promise<void>; verifyBank: (id: string, request: VerifyBankRequest) => Promise<void>;
cancel: (id: string) => Promise<void>;
reinstate: (id: string) => Promise<void>; reinstate: (id: string) => Promise<void>;
leave: (id: string) => Promise<void>; leave: (id: string) => Promise<void>;
delete: (id: string, request: SecretVerificationRequest) => Promise<void>; delete: (id: string, request: SecretVerificationRequest) => Promise<void>;

View File

@ -184,10 +184,6 @@ export class OrganizationApiService implements OrganizationApiServiceAbstraction
); );
} }
async cancel(id: string): Promise<void> {
return this.apiService.send("POST", "/organizations/" + id + "/cancel", null, true, false);
}
async reinstate(id: string): Promise<void> { async reinstate(id: string): Promise<void> {
return this.apiService.send("POST", "/organizations/" + id + "/reinstate", null, true, false); return this.apiService.send("POST", "/organizations/" + id + "/reinstate", null, true, false);
} }

View File

@ -12,7 +12,7 @@ export class BillingApiService implements BillingApiServiceAbstraction {
): Promise<void> { ): Promise<void> {
return this.apiService.send( return this.apiService.send(
"POST", "POST",
"/organizations/" + organizationId + "/churn", "/organizations/" + organizationId + "/cancel",
request, request,
true, true,
false, false,
@ -20,7 +20,7 @@ export class BillingApiService implements BillingApiServiceAbstraction {
} }
cancelPremiumUserSubscription(request: SubscriptionCancellationRequest): Promise<void> { cancelPremiumUserSubscription(request: SubscriptionCancellationRequest): Promise<void> {
return this.apiService.send("POST", "/accounts/churn-premium", request, true, false); return this.apiService.send("POST", "/accounts/cancel", request, true, false);
} }
async getBillingStatus(id: string): Promise<OrganizationBillingStatusResponse> { async getBillingStatus(id: string): Promise<OrganizationBillingStatusResponse> {

View File

@ -7,7 +7,6 @@ export enum FeatureFlag {
GeneratorToolsModernization = "generator-tools-modernization", GeneratorToolsModernization = "generator-tools-modernization",
KeyRotationImprovements = "key-rotation-improvements", KeyRotationImprovements = "key-rotation-improvements",
FlexibleCollectionsMigration = "flexible-collections-migration", FlexibleCollectionsMigration = "flexible-collections-migration",
AC1607_PresentUserOffboardingSurvey = "AC-1607_present-user-offboarding-survey",
ShowPaymentMethodWarningBanners = "show-payment-method-warning-banners", ShowPaymentMethodWarningBanners = "show-payment-method-warning-banners",
} }

View File

@ -394,10 +394,6 @@ export class ApiService implements ApiServiceAbstraction {
return this.send("POST", "/accounts/reinstate-premium", null, true, false); return this.send("POST", "/accounts/reinstate-premium", null, true, false);
} }
postCancelPremium(): Promise<any> {
return this.send("POST", "/accounts/cancel-premium", null, true, false);
}
async postAccountStorage(request: StorageRequest): Promise<PaymentResponse> { async postAccountStorage(request: StorageRequest): Promise<PaymentResponse> {
const r = await this.send("POST", "/accounts/storage", request, true, true); const r = await this.send("POST", "/accounts/storage", request, true, true);
return new PaymentResponse(r); return new PaymentResponse(r);