Browse Source

Fix user settings and calculations in impersonation mode

pull/7592/head
Thomas Kaul 1 week ago
parent
commit
c46fc5264d
  1. 5
      apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html
  2. 1
      apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
  3. 32
      apps/client/src/app/components/user-account-settings/user-account-settings.component.ts
  4. 6
      apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts
  5. 3
      apps/client/src/app/pages/portfolio/analysis/analysis-page.html
  6. 2
      apps/client/src/app/pages/portfolio/fire/fire-page.html

5
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html

@ -18,7 +18,10 @@
<mat-label i18n>Compare with...</mat-label> <mat-label i18n>Compare with...</mat-label>
<mat-select <mat-select
name="benchmark" name="benchmark"
[disabled]="user()?.subscription?.type === 'Basic'" [disabled]="
!hasPermissionToUpdateUserSettings() ||
user()?.subscription?.type === 'Basic'
"
[value]="benchmark()?.id" [value]="benchmark()?.id"
(selectionChange)="onChangeBenchmark($event.value)" (selectionChange)="onChangeBenchmark($event.value)"
> >

1
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts

@ -69,6 +69,7 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy {
public readonly benchmarkDataItems = input<LineChartItem[]>([]); public readonly benchmarkDataItems = input<LineChartItem[]>([]);
public readonly benchmarks = input<Partial<SymbolProfile>[]>(); public readonly benchmarks = input<Partial<SymbolProfile>[]>();
public readonly colorScheme = input.required<ColorScheme>(); public readonly colorScheme = input.required<ColorScheme>();
public readonly hasPermissionToUpdateUserSettings = input<boolean>();
public readonly isLoading = input<boolean>(); public readonly isLoading = input<boolean>();
public readonly locale = input(getLocale()); public readonly locale = input(getLocale());
public readonly performanceDataItems = input.required<LineChartItem[]>(); public readonly performanceDataItems = input.required<LineChartItem[]>();

32
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,
@ -90,6 +91,7 @@ export class GfUserAccountSettingsComponent implements OnInit {
protected readonly deleteOwnUserForm = inject(NonNullableFormBuilder).group({ protected readonly deleteOwnUserForm = inject(NonNullableFormBuilder).group({
accessToken: ['', Validators.required] accessToken: ['', Validators.required]
}); });
protected hasImpersonationId: boolean;
protected hasPermissionToDeleteOwnUser: boolean; protected hasPermissionToDeleteOwnUser: boolean;
protected hasPermissionToRequestOwnUserDeletion: boolean; protected hasPermissionToRequestOwnUserDeletion: boolean;
protected hasPermissionToUpdateViewMode: boolean; protected hasPermissionToUpdateViewMode: boolean;
@ -129,6 +131,9 @@ export class GfUserAccountSettingsComponent implements OnInit {
private readonly dataService = inject(DataService); private readonly dataService = inject(DataService);
private readonly deviceDetectorService = inject(DeviceDetectorService); private readonly deviceDetectorService = inject(DeviceDetectorService);
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
private readonly impersonationStorageService = inject(
ImpersonationStorageService
);
private readonly notificationService = inject(NotificationService); private readonly notificationService = inject(NotificationService);
private readonly settingsStorageService = inject(SettingsStorageService); private readonly settingsStorageService = inject(SettingsStorageService);
private readonly snackBar = inject(MatSnackBar); private readonly snackBar = inject(MatSnackBar);
@ -140,6 +145,17 @@ export class GfUserAccountSettingsComponent implements OnInit {
this.currencies = currencies; this.currencies = currencies;
this.impersonationStorageService
.onChangeHasImpersonation()
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((impersonationId) => {
this.hasImpersonationId = !!impersonationId;
this.updateBaseCurrencyFormState();
this.changeDetectorRef.markForCheck();
});
this.userService.stateChanged this.userService.stateChanged
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((state) => { .subscribe((state) => {
@ -192,11 +208,7 @@ export class GfUserAccountSettingsComponent implements OnInit {
baseCurrency: this.user.settings.baseCurrency ?? null baseCurrency: this.user.settings.baseCurrency ?? null
}); });
if (this.hasPermissionToUpdateUserSettings) { this.updateBaseCurrencyFormState();
this.baseCurrencyForm.enable({ emitEvent: false });
} else {
this.baseCurrencyForm.disable({ emitEvent: false });
}
if (this.user.settings.locale) { if (this.user.settings.locale) {
this.locales.push(this.user.settings.locale); this.locales.push(this.user.settings.locale);
@ -431,4 +443,14 @@ export class GfUserAccountSettingsComponent implements OnInit {
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
} }
private updateBaseCurrencyFormState() {
// The base currency belongs to the impersonated user while a change would be
// applied to the authenticated user
if (!this.hasImpersonationId && this.hasPermissionToUpdateUserSettings) {
this.baseCurrencyForm.enable({ emitEvent: false });
} else {
this.baseCurrencyForm.disable({ emitEvent: false });
}
}
} }

6
apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts

@ -88,6 +88,7 @@ export class GfAnalysisPageComponent implements OnInit {
protected dividendsByGroup: InvestmentItem[]; protected dividendsByGroup: InvestmentItem[];
protected readonly dividendTimelineDataLabel = $localize`Dividend`; protected readonly dividendTimelineDataLabel = $localize`Dividend`;
protected hasPermissionToReadAiPrompt: boolean; protected hasPermissionToReadAiPrompt: boolean;
protected hasPermissionToUpdateUserSettings: boolean;
protected impersonationId: string | null; protected impersonationId: string | null;
protected investments: InvestmentItem[]; protected investments: InvestmentItem[];
protected readonly investmentTimelineDataLabel = $localize`Invested Capital`; protected readonly investmentTimelineDataLabel = $localize`Invested Capital`;
@ -174,6 +175,11 @@ export class GfAnalysisPageComponent implements OnInit {
permissions.readAiPrompt permissions.readAiPrompt
); );
this.hasPermissionToUpdateUserSettings = hasPermission(
this.user.permissions,
permissions.updateUserSettings
);
this.update(); this.update();
} }

3
apps/client/src/app/pages/portfolio/analysis/analysis-page.html

@ -137,6 +137,9 @@
[benchmarkDataItems]="benchmarkDataItems" [benchmarkDataItems]="benchmarkDataItems"
[benchmarks]="benchmarks" [benchmarks]="benchmarks"
[colorScheme]="user?.settings?.colorScheme" [colorScheme]="user?.settings?.colorScheme"
[hasPermissionToUpdateUserSettings]="
hasPermissionToUpdateUserSettings && !impersonationId
"
[isLoading]="isLoadingBenchmarkComparator || isLoadingInvestmentChart" [isLoading]="isLoadingBenchmarkComparator || isLoadingInvestmentChart"
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[performanceDataItems]="performanceDataItemsInPercentage" [performanceDataItems]="performanceDataItemsInPercentage"

2
apps/client/src/app/pages/portfolio/fire/fire-page.html

@ -21,7 +21,7 @@
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[projectedTotalAmount]="user?.settings?.projectedTotalAmount" [projectedTotalAmount]="user?.settings?.projectedTotalAmount"
[retirementDate]="user?.settings?.retirementDate" [retirementDate]="user?.settings?.retirementDate"
[savingsRate]="hasImpersonationId ? 0 : user?.settings?.savingsRate" [savingsRate]="user?.settings?.savingsRate"
[style.opacity]=" [style.opacity]="
user?.subscription?.type === 'Basic' ? '0.67' : 'initial' user?.subscription?.type === 'Basic' ? '0.67' : 'initial'
" "

Loading…
Cancel
Save