Browse Source

Improve user account deletion flow

pull/7269/head
Thomas Kaul 1 week ago
parent
commit
70ebf23d9e
  1. 21
      apps/client/src/app/components/user-account-settings/user-account-settings.component.ts
  2. 118
      apps/client/src/app/components/user-account-settings/user-account-settings.html

21
apps/client/src/app/components/user-account-settings/user-account-settings.component.ts

@ -1,3 +1,4 @@
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { import {
KEY_STAY_SIGNED_IN, KEY_STAY_SIGNED_IN,
KEY_TOKEN, KEY_TOKEN,
@ -76,6 +77,8 @@ export class GfUserAccountSettingsComponent implements OnInit {
public deleteOwnUserForm = this.formBuilder.group({ public deleteOwnUserForm = this.formBuilder.group({
accessToken: ['', Validators.required] accessToken: ['', Validators.required]
}); });
public hasImpersonationId: boolean;
public hasPermissionForSubscription: boolean;
public hasPermissionToDeleteOwnUser: boolean; public hasPermissionToDeleteOwnUser: boolean;
public hasPermissionToUpdateViewMode: boolean; public hasPermissionToUpdateViewMode: boolean;
public hasPermissionToUpdateUserSettings: boolean; public hasPermissionToUpdateUserSettings: boolean;
@ -108,17 +111,33 @@ export class GfUserAccountSettingsComponent implements OnInit {
private dataService: DataService, private dataService: DataService,
private destroyRef: DestroyRef, private destroyRef: DestroyRef,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private impersonationStorageService: ImpersonationStorageService,
private notificationService: NotificationService, private notificationService: NotificationService,
private settingsStorageService: SettingsStorageService, private settingsStorageService: SettingsStorageService,
private snackBar: MatSnackBar, private snackBar: MatSnackBar,
private userService: UserService, private userService: UserService,
public webAuthnService: WebAuthnService public webAuthnService: WebAuthnService
) { ) {
const { baseCurrency, currencies } = this.dataService.fetchInfo(); const { baseCurrency, currencies, globalPermissions } =
this.dataService.fetchInfo();
this.baseCurrency = baseCurrency; this.baseCurrency = baseCurrency;
this.currencies = currencies; this.currencies = currencies;
this.hasPermissionForSubscription = hasPermission(
globalPermissions,
permissions.enableSubscription
);
this.impersonationStorageService
.onChangeHasImpersonation()
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((impersonationId) => {
this.hasImpersonationId = !!impersonationId;
this.changeDetectorRef.markForCheck();
});
this.userService.stateChanged this.userService.stateChanged
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((state) => { .subscribe((state) => {

118
apps/client/src/app/components/user-account-settings/user-account-settings.html

@ -285,67 +285,75 @@
</button> </button>
</div> </div>
</div> </div>
<hr class="mt-5" /> @if (
<div class="d-flex py-1"> !hasImpersonationId &&
<div class="pr-1 text-danger w-50" i18n>Danger Zone</div> (hasPermissionToDeleteOwnUser || hasPermissionForSubscription)
<div class="pl-1 w-50"> ) {
@if (hasPermissionToDeleteOwnUser) { <hr class="mt-5" />
<form <div class="d-flex py-1">
class="w-100" <div class="pr-1 text-danger w-50" i18n>Danger Zone</div>
[formGroup]="deleteOwnUserForm" <div class="pl-1 w-50">
(ngSubmit)="onCloseAccount()" @if (hasPermissionToDeleteOwnUser) {
> <form
<mat-form-field class="w-100"
appearance="outline" [formGroup]="deleteOwnUserForm"
class="without-hint w-100" (ngSubmit)="onCloseAccount()"
[hideRequiredMarker]="true"
> >
<mat-label i18n>Security Token</mat-label> <mat-form-field
<input appearance="outline"
formControlName="accessToken" class="without-hint w-100"
matInput [hideRequiredMarker]="true"
[type]="isAccessTokenHidden ? 'password' : 'text'"
/>
<button
class="mx-2"
mat-icon-button
matSuffix
type="button"
(click)="isAccessTokenHidden = !isAccessTokenHidden"
> >
<ion-icon <mat-label i18n>Security Token</mat-label>
class="mat-icon" <input
[name]=" formControlName="accessToken"
isAccessTokenHidden ? 'eye-outline' : 'eye-off-outline' matInput
" [type]="isAccessTokenHidden ? 'password' : 'text'"
/> />
<button
class="mx-2"
mat-icon-button
matSuffix
type="button"
(click)="isAccessTokenHidden = !isAccessTokenHidden"
>
<ion-icon
class="mat-icon"
[name]="
isAccessTokenHidden ? 'eye-outline' : 'eye-off-outline'
"
/>
</button>
</mat-form-field>
<button
class="mt-2"
color="warn"
i18n
mat-flat-button
type="submit"
[disabled]="
!(deleteOwnUserForm.dirty && deleteOwnUserForm.valid)
"
>
Close Account
</button> </button>
</mat-form-field> </form>
<button } @else if (
class="mt-2" hasPermissionForSubscription &&
color="warn" (user?.accounts?.length > 0 || user?.activitiesCount > 0)
i18n ) {
mat-flat-button <div class="hint-text text-muted" i18n>
type="submit" For security reasons, please delete all activities and accounts
[disabled]=" first before your Ghostfolio account can be closed.
!(deleteOwnUserForm.dirty && deleteOwnUserForm.valid) </div>
" } @else if (hasPermissionForSubscription) {
<a color="warn" i18n mat-flat-button [href]="closeUserAccountMail"
>Close Account</a
> >
Close Account }
</button> </div>
</form>
} @else if (user?.accounts?.length > 0 || user?.activitiesCount > 0) {
<div class="hint-text text-muted" i18n>
For security reasons, please delete all activities and accounts
first before your Ghostfolio account can be closed.
</div>
} @else {
<a color="warn" i18n mat-flat-button [href]="closeUserAccountMail"
>Close Account</a
>
}
</div> </div>
</div> }
</div> </div>
</div> </div>
</div> </div>

Loading…
Cancel
Save