PM-2165 Migrate delete account dialog (#8503)

* PM-2165 Migrate delete account dialog

* PM-2165 Addressed Review comments

* PM-2165 Removed legacy user verfication component and used new one

* PM-2165 Added invalidSecret to form input
This commit is contained in:
KiruthigaManivannan 2024-05-24 12:25:43 +05:30 committed by GitHub
parent f2fcf5ce2e
commit 36c6dc27e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 48 additions and 61 deletions

View File

@ -15,13 +15,12 @@
<button type="button" bitButton buttonType="danger" [bitAction]="purgeVault"> <button type="button" bitButton buttonType="danger" [bitAction]="purgeVault">
{{ "purgeVault" | i18n }} {{ "purgeVault" | i18n }}
</button> </button>
<button type="button" bitButton buttonType="danger" (click)="deleteAccount()"> <button type="button" bitButton buttonType="danger" [bitAction]="deleteAccount">
{{ "deleteAccount" | i18n }} {{ "deleteAccount" | i18n }}
</button> </button>
</app-danger-zone> </app-danger-zone>
<ng-template #deauthorizeSessionsTemplate></ng-template> <ng-template #deauthorizeSessionsTemplate></ng-template>
<ng-template #deleteAccountTemplate></ng-template>
<ng-template #viewUserApiKeyTemplate></ng-template> <ng-template #viewUserApiKeyTemplate></ng-template>
<ng-template #rotateUserApiKeyTemplate></ng-template> <ng-template #rotateUserApiKeyTemplate></ng-template>
</bit-container> </bit-container>

View File

@ -8,7 +8,7 @@ import { DialogService } from "@bitwarden/components";
import { PurgeVaultComponent } from "../../../vault/settings/purge-vault.component"; import { PurgeVaultComponent } from "../../../vault/settings/purge-vault.component";
import { DeauthorizeSessionsComponent } from "./deauthorize-sessions.component"; import { DeauthorizeSessionsComponent } from "./deauthorize-sessions.component";
import { DeleteAccountComponent } from "./delete-account.component"; import { DeleteAccountDialogComponent } from "./delete-account-dialog.component";
@Component({ @Component({
selector: "app-account", selector: "app-account",
@ -17,8 +17,6 @@ import { DeleteAccountComponent } from "./delete-account.component";
export class AccountComponent { export class AccountComponent {
@ViewChild("deauthorizeSessionsTemplate", { read: ViewContainerRef, static: true }) @ViewChild("deauthorizeSessionsTemplate", { read: ViewContainerRef, static: true })
deauthModalRef: ViewContainerRef; deauthModalRef: ViewContainerRef;
@ViewChild("deleteAccountTemplate", { read: ViewContainerRef, static: true })
deleteModalRef: ViewContainerRef;
showChangeEmail = true; showChangeEmail = true;
@ -41,7 +39,8 @@ export class AccountComponent {
await lastValueFrom(dialogRef.closed); await lastValueFrom(dialogRef.closed);
}; };
async deleteAccount() { deleteAccount = async () => {
await this.modalService.openViewRef(DeleteAccountComponent, this.deleteModalRef); const dialogRef = DeleteAccountDialogComponent.open(this.dialogService);
} await lastValueFrom(dialogRef.closed);
};
} }

View File

@ -0,0 +1,21 @@
<form [formGroup]="deleteForm" [bitSubmit]="submit">
<bit-dialog dialogSize="default" [title]="'deleteAccount' | i18n">
<ng-container bitDialogContent>
<p bitTypography="body1">{{ "deleteAccountDesc" | i18n }}</p>
<app-callout type="warning">{{ "deleteAccountWarning" | i18n }}</app-callout>
<app-user-verification-form-input
formControlName="verification"
name="verification"
[(invalidSecret)]="invalidSecret"
></app-user-verification-form-input>
</ng-container>
<ng-container bitDialogFooter>
<button bitButton bitFormButton type="submit" buttonType="danger">
{{ "deleteAccount" | i18n }}
</button>
<button bitButton bitFormButton type="button" buttonType="secondary" bitDialogClose>
{{ "close" | i18n }}
</button>
</ng-container>
</bit-dialog>
</form>

View File

@ -1,43 +1,50 @@
import { DialogRef } from "@angular/cdk/dialog";
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { FormBuilder } from "@angular/forms"; import { FormBuilder } from "@angular/forms";
import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-api.service"; import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-api.service";
import { Verification } from "@bitwarden/common/auth/types/verification"; import { Verification } from "@bitwarden/common/auth/types/verification";
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogService } from "@bitwarden/components";
@Component({ @Component({
selector: "app-delete-account", templateUrl: "delete-account-dialog.component.html",
templateUrl: "delete-account.component.html",
}) })
export class DeleteAccountComponent { export class DeleteAccountDialogComponent {
formPromise: Promise<void>;
deleteForm = this.formBuilder.group({ deleteForm = this.formBuilder.group({
verification: undefined as Verification | undefined, verification: undefined as Verification | undefined,
}); });
invalidSecret: boolean = false;
constructor( constructor(
private i18nService: I18nService, private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private accountApiService: AccountApiService, private accountApiService: AccountApiService,
private logService: LogService, private dialogRef: DialogRef,
) {} ) {}
async submit() { submit = async () => {
try { try {
const verification = this.deleteForm.get("verification").value; const verification = this.deleteForm.get("verification").value;
this.formPromise = this.accountApiService.deleteAccount(verification); await this.accountApiService.deleteAccount(verification);
await this.formPromise; this.dialogRef.close();
this.platformUtilsService.showToast( this.platformUtilsService.showToast(
"success", "success",
this.i18nService.t("accountDeleted"), this.i18nService.t("accountDeleted"),
this.i18nService.t("accountDeletedDesc"), this.i18nService.t("accountDeletedDesc"),
); );
} catch (e) { } catch (e) {
this.logService.error(e); if (e instanceof ErrorResponse && e.statusCode === 400) {
this.invalidSecret = true;
} }
throw e;
}
};
static open(dialogService: DialogService) {
return dialogService.open(DeleteAccountDialogComponent);
} }
} }

View File

@ -1,39 +0,0 @@
<div class="modal fade" role="dialog" aria-modal="true" aria-labelledby="deleteAccountTitle">
<div class="modal-dialog modal-dialog-scrollable" role="document">
<form
class="modal-content"
#form
(ngSubmit)="submit()"
[appApiAction]="formPromise"
ngNativeValidate
[formGroup]="deleteForm"
>
<div class="modal-header">
<h1 class="modal-title" id="deleteAccountTitle">{{ "deleteAccount" | i18n }}</h1>
<button
type="button"
class="close"
data-dismiss="modal"
appA11yTitle="{{ 'close' | i18n }}"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>{{ "deleteAccountDesc" | i18n }}</p>
<app-callout type="warning">{{ "deleteAccountWarning" | i18n }}</app-callout>
<app-user-verification ngDefaultControl formControlName="verification" name="verification">
</app-user-verification>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-danger btn-submit" [disabled]="form.loading">
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
<span>{{ "deleteAccount" | i18n }}</span>
</button>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
{{ "close" | i18n }}
</button>
</div>
</form>
</div>
</div>

View File

@ -33,7 +33,7 @@ import { ChangeAvatarComponent } from "../auth/settings/account/change-avatar.co
import { ChangeEmailComponent } from "../auth/settings/account/change-email.component"; import { ChangeEmailComponent } from "../auth/settings/account/change-email.component";
import { DangerZoneComponent } from "../auth/settings/account/danger-zone.component"; import { DangerZoneComponent } from "../auth/settings/account/danger-zone.component";
import { DeauthorizeSessionsComponent } from "../auth/settings/account/deauthorize-sessions.component"; import { DeauthorizeSessionsComponent } from "../auth/settings/account/deauthorize-sessions.component";
import { DeleteAccountComponent } from "../auth/settings/account/delete-account.component"; import { DeleteAccountDialogComponent } from "../auth/settings/account/delete-account-dialog.component";
import { ProfileComponent } from "../auth/settings/account/profile.component"; import { ProfileComponent } from "../auth/settings/account/profile.component";
import { EmergencyAccessAttachmentsComponent } from "../auth/settings/emergency-access/attachments/emergency-access-attachments.component"; import { EmergencyAccessAttachmentsComponent } from "../auth/settings/emergency-access/attachments/emergency-access-attachments.component";
import { EmergencyAccessConfirmComponent } from "../auth/settings/emergency-access/confirm/emergency-access-confirm.component"; import { EmergencyAccessConfirmComponent } from "../auth/settings/emergency-access/confirm/emergency-access-confirm.component";
@ -130,7 +130,7 @@ import { SharedModule } from "./shared.module";
ChangeEmailComponent, ChangeEmailComponent,
CollectionsComponent, CollectionsComponent,
DeauthorizeSessionsComponent, DeauthorizeSessionsComponent,
DeleteAccountComponent, DeleteAccountDialogComponent,
DomainRulesComponent, DomainRulesComponent,
EmergencyAccessAddEditComponent, EmergencyAccessAddEditComponent,
EmergencyAccessAttachmentsComponent, EmergencyAccessAttachmentsComponent,
@ -203,7 +203,7 @@ import { SharedModule } from "./shared.module";
ChangeEmailComponent, ChangeEmailComponent,
CollectionsComponent, CollectionsComponent,
DeauthorizeSessionsComponent, DeauthorizeSessionsComponent,
DeleteAccountComponent, DeleteAccountDialogComponent,
DomainRulesComponent, DomainRulesComponent,
DynamicAvatarComponent, DynamicAvatarComponent,
EmergencyAccessAddEditComponent, EmergencyAccessAddEditComponent,