Browse Source

Migrate date range to user settings

pull/1239/head
Thomas 3 years ago
parent
commit
b5f90bba81
  1. 4
      apps/api/src/app/user/update-user-setting.dto.ts
  2. 22
      apps/api/src/app/user/user.service.ts
  3. 34
      apps/client/src/app/components/home-holdings/home-holdings.component.ts
  4. 4
      apps/client/src/app/components/home-holdings/home-holdings.html
  5. 37
      apps/client/src/app/components/home-overview/home-overview.component.ts
  6. 2
      apps/client/src/app/components/home-overview/home-overview.html
  7. 4
      libs/common/src/lib/interfaces/user-settings.interface.ts

4
apps/api/src/app/user/update-user-setting.dto.ts

@ -1,6 +1,10 @@
import { IsBoolean, IsNumber, IsOptional, IsString } from 'class-validator'; import { IsBoolean, IsNumber, IsOptional, IsString } from 'class-validator';
export class UpdateUserSettingDto { export class UpdateUserSettingDto {
@IsOptional()
@IsString() // TODO: DateRange
dateRange?: string;
@IsNumber() @IsNumber()
@IsOptional() @IsOptional()
emergencyFund?: number; emergencyFund?: number;

22
apps/api/src/app/user/user.service.ts

@ -4,7 +4,11 @@ import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { TagService } from '@ghostfolio/api/services/tag/tag.service'; import { TagService } from '@ghostfolio/api/services/tag/tag.service';
import { PROPERTY_IS_READ_ONLY_MODE, locale } from '@ghostfolio/common/config'; import { PROPERTY_IS_READ_ONLY_MODE, locale } from '@ghostfolio/common/config';
import { User as IUser, UserWithSettings } from '@ghostfolio/common/interfaces'; import {
User as IUser,
UserSettings,
UserWithSettings
} from '@ghostfolio/common/interfaces';
import { import {
getPermissions, getPermissions,
hasRole, hasRole,
@ -15,7 +19,6 @@ import { Prisma, Role, User, ViewMode } from '@prisma/client';
import { sortBy } from 'lodash'; import { sortBy } from 'lodash';
import { UserSettingsParams } from './interfaces/user-settings-params.interface'; import { UserSettingsParams } from './interfaces/user-settings-params.interface';
import { UserSettings } from './interfaces/user-settings.interface';
const crypto = require('crypto'); const crypto = require('crypto');
@ -68,9 +71,13 @@ export class UserService {
}), }),
accounts: Account, accounts: Account,
settings: { settings: {
...(<UserSettings>Settings.settings), ...(<UserSettings>(<unknown>Settings.settings)),
baseCurrency: Settings?.currency ?? UserService.DEFAULT_CURRENCY, baseCurrency: Settings?.currency ?? UserService.DEFAULT_CURRENCY,
locale: (<UserSettings>Settings.settings)?.locale ?? aLocale, dateRange:
Settings?.viewMode === 'ZEN'
? 'max'
: (<UserSettings>(<unknown>Settings.settings))?.dateRange ?? 'max',
locale: (<UserSettings>(<unknown>Settings.settings))?.locale ?? aLocale,
viewMode: Settings?.viewMode ?? ViewMode.DEFAULT viewMode: Settings?.viewMode ?? ViewMode.DEFAULT
} }
}; };
@ -89,7 +96,10 @@ export class UserService {
} }
public isRestrictedView(aUser: UserWithSettings) { public isRestrictedView(aUser: UserWithSettings) {
return (aUser.Settings.settings as UserSettings)?.isRestrictedView ?? false; return (
(aUser.Settings.settings as unknown as UserSettings)?.isRestrictedView ??
false
);
} }
public async user( public async user(
@ -295,7 +305,7 @@ export class UserService {
userId: string; userId: string;
userSettings: UserSettings; userSettings: UserSettings;
}) { }) {
const settings = userSettings as Prisma.JsonObject; const settings = userSettings as unknown as Prisma.JsonObject;
await this.prismaService.settings.upsert({ await this.prismaService.settings.upsert({
create: { create: {

34
apps/client/src/app/components/home-holdings/home-holdings.component.ts

@ -5,10 +5,6 @@ import { PositionDetailDialog } from '@ghostfolio/client/components/position/pos
import { ToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component'; import { ToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component';
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import {
RANGE,
SettingsStorageService
} from '@ghostfolio/client/services/settings-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
import { Position, User } from '@ghostfolio/common/interfaces'; import { Position, User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
@ -26,7 +22,6 @@ import { PositionDetailDialogParams } from '../position/position-detail-dialog/i
templateUrl: './home-holdings.html' templateUrl: './home-holdings.html'
}) })
export class HomeHoldingsComponent implements OnDestroy, OnInit { export class HomeHoldingsComponent implements OnDestroy, OnInit {
public dateRange: DateRange;
public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS; public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS;
public deviceType: string; public deviceType: string;
public hasImpersonationId: boolean; public hasImpersonationId: boolean;
@ -44,7 +39,6 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
private impersonationStorageService: ImpersonationStorageService, private impersonationStorageService: ImpersonationStorageService,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
private settingsStorageService: SettingsStorageService,
private userService: UserService private userService: UserService
) { ) {
this.route.queryParams this.route.queryParams
@ -73,7 +67,7 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
permissions.createOrder permissions.createOrder
); );
this.changeDetectorRef.markForCheck(); this.update();
} }
}); });
} }
@ -88,18 +82,24 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
this.hasImpersonationId = !!aId; this.hasImpersonationId = !!aId;
}); });
this.dateRange =
this.user.settings.viewMode === 'ZEN'
? 'max'
: <DateRange>this.settingsStorageService.getSetting(RANGE) ?? 'max';
this.update(); this.update();
} }
public onChangeDateRange(aDateRange: DateRange) { public onChangeDateRange(dateRange: DateRange) {
this.dateRange = aDateRange; this.dataService
this.settingsStorageService.setSetting(RANGE, this.dateRange); .putUserSetting({ dateRange })
this.update(); .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;
this.changeDetectorRef.markForCheck();
});
});
} }
public ngOnDestroy() { public ngOnDestroy() {
@ -151,7 +151,7 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
this.positions = undefined; this.positions = undefined;
this.dataService this.dataService
.fetchPositions({ range: this.dateRange }) .fetchPositions({ range: this.user?.settings?.dateRange })
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe((response) => { .subscribe((response) => {
this.positions = response.positions; this.positions = response.positions;

4
apps/client/src/app/components/home-holdings/home-holdings.html

@ -1,7 +1,7 @@
<div class="container justify-content-center p-3"> <div class="container justify-content-center p-3">
<div *ngIf="user.settings.viewMode !== 'ZEN'" class="mb-3 text-center"> <div *ngIf="user.settings.viewMode !== 'ZEN'" class="mb-3 text-center">
<gf-toggle <gf-toggle
[defaultValue]="dateRange" [defaultValue]="user?.settings?.dateRange"
[isLoading]="positions === undefined" [isLoading]="positions === undefined"
[options]="dateRangeOptions" [options]="dateRangeOptions"
(change)="onChangeDateRange($event.value)" (change)="onChangeDateRange($event.value)"
@ -17,7 +17,7 @@
[hasPermissionToCreateOrder]="hasPermissionToCreateOrder" [hasPermissionToCreateOrder]="hasPermissionToCreateOrder"
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[positions]="positions" [positions]="positions"
[range]="dateRange" [range]="user?.settings?.dateRange"
></gf-positions> ></gf-positions>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

37
apps/client/src/app/components/home-overview/home-overview.component.ts

@ -2,10 +2,6 @@ import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { ToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component'; import { ToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component';
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import {
RANGE,
SettingsStorageService
} from '@ghostfolio/client/services/settings-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
import { import {
LineChartItem, LineChartItem,
@ -25,7 +21,6 @@ import { takeUntil } from 'rxjs/operators';
templateUrl: './home-overview.html' templateUrl: './home-overview.html'
}) })
export class HomeOverviewComponent implements OnDestroy, OnInit { export class HomeOverviewComponent implements OnDestroy, OnInit {
public dateRange: DateRange;
public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS; public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS;
public deviceType: string; public deviceType: string;
public errors: UniqueAsset[]; public errors: UniqueAsset[];
@ -47,7 +42,6 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
private dataService: DataService, private dataService: DataService,
private deviceService: DeviceDetectorService, private deviceService: DeviceDetectorService,
private impersonationStorageService: ImpersonationStorageService, private impersonationStorageService: ImpersonationStorageService,
private settingsStorageService: SettingsStorageService,
private userService: UserService private userService: UserService
) { ) {
this.userService.stateChanged this.userService.stateChanged
@ -61,7 +55,7 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
permissions.createOrder permissions.createOrder
); );
this.changeDetectorRef.markForCheck(); this.update();
} }
}); });
} }
@ -78,11 +72,6 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
}); });
this.dateRange =
this.user.settings.viewMode === 'ZEN'
? 'max'
: <DateRange>this.settingsStorageService.getSetting(RANGE) ?? 'max';
this.showDetails = this.showDetails =
!this.hasImpersonationId && !this.hasImpersonationId &&
!this.user.settings.isRestrictedView && !this.user.settings.isRestrictedView &&
@ -91,10 +80,22 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
this.update(); this.update();
} }
public onChangeDateRange(aDateRange: DateRange) { public onChangeDateRange(dateRange: DateRange) {
this.dateRange = aDateRange; this.dataService
this.settingsStorageService.setSetting(RANGE, this.dateRange); .putUserSetting({ dateRange })
this.update(); .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;
this.changeDetectorRef.markForCheck();
});
});
} }
public ngOnDestroy() { public ngOnDestroy() {
@ -107,7 +108,7 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
this.dataService this.dataService
.fetchChart({ .fetchChart({
range: this.dateRange, range: this.user?.settings?.dateRange,
version: this.user?.settings?.isExperimentalFeatures ? 2 : 1 version: this.user?.settings?.isExperimentalFeatures ? 2 : 1
}) })
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
@ -125,7 +126,7 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
}); });
this.dataService this.dataService
.fetchPortfolioPerformance({ range: this.dateRange }) .fetchPortfolioPerformance({ range: this.user?.settings?.dateRange })
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe((response) => { .subscribe((response) => {
this.errors = response.errors; this.errors = response.errors;

2
apps/client/src/app/components/home-overview/home-overview.html

@ -46,7 +46,7 @@
></gf-portfolio-performance> ></gf-portfolio-performance>
<div *ngIf="showDetails" class="text-center"> <div *ngIf="showDetails" class="text-center">
<gf-toggle <gf-toggle
[defaultValue]="dateRange" [defaultValue]="user?.settings?.dateRange"
[isLoading]="isLoadingPerformance" [isLoading]="isLoadingPerformance"
[options]="dateRangeOptions" [options]="dateRangeOptions"
(change)="onChangeDateRange($event.value)" (change)="onChangeDateRange($event.value)"

4
libs/common/src/lib/interfaces/user-settings.interface.ts

@ -1,10 +1,12 @@
import { DateRange } from '@ghostfolio/common/types';
import { ViewMode } from '@prisma/client'; import { ViewMode } from '@prisma/client';
export interface UserSettings { export interface UserSettings {
baseCurrency?: string; baseCurrency?: string;
dateRange?: DateRange;
isExperimentalFeatures?: boolean; isExperimentalFeatures?: boolean;
isRestrictedView?: boolean; isRestrictedView?: boolean;
language?: string; language?: string;
locale: string; locale?: string;
viewMode?: ViewMode; viewMode?: ViewMode;
} }

Loading…
Cancel
Save