Feature/migrate date range setting to user settings (#1239)
* Migrate date range to user settings * Refactor currency and view mode in the user user settings * Update changelog
This commit is contained in:
parent
20bc7ef99c
commit
fc4bb71184
@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Changed
|
||||
|
||||
- Improved the mobile layout of the benchmark comparator
|
||||
- Migrated the date range setting from the locale storage to the user settings
|
||||
- Refactored the `currency` and `view mode` in the user settings
|
||||
|
||||
## 1.189.0 - 08.09.2022
|
||||
|
||||
|
@ -5,7 +5,6 @@ import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.s
|
||||
import { PortfolioOrder } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-order.interface';
|
||||
import { TimelineSpecification } from '@ghostfolio/api/app/portfolio/interfaces/timeline-specification.interface';
|
||||
import { TransactionPoint } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point.interface';
|
||||
import { UserSettings } from '@ghostfolio/api/app/user/interfaces/user-settings.interface';
|
||||
import { UserService } from '@ghostfolio/api/app/user/user.service';
|
||||
import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment';
|
||||
import { AccountClusterRiskInitialInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/initial-investment';
|
||||
@ -35,7 +34,8 @@ import {
|
||||
PortfolioReport,
|
||||
PortfolioSummary,
|
||||
Position,
|
||||
TimelinePosition
|
||||
TimelinePosition,
|
||||
UserSettings
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
|
||||
import type {
|
||||
@ -1045,7 +1045,7 @@ export class PortfolioService {
|
||||
accounts
|
||||
)
|
||||
],
|
||||
{ baseCurrency: currency }
|
||||
<UserSettings>this.request.user.Settings.settings
|
||||
),
|
||||
currencyClusterRisk: await this.rulesService.evaluate(
|
||||
[
|
||||
@ -1066,7 +1066,7 @@ export class PortfolioService {
|
||||
currentPositions
|
||||
)
|
||||
],
|
||||
{ baseCurrency: currency }
|
||||
<UserSettings>this.request.user.Settings.settings
|
||||
),
|
||||
fees: await this.rulesService.evaluate(
|
||||
[
|
||||
@ -1076,7 +1076,7 @@ export class PortfolioService {
|
||||
this.getFees(orders).toNumber()
|
||||
)
|
||||
],
|
||||
{ baseCurrency: currency }
|
||||
<UserSettings>this.request.user.Settings.settings
|
||||
)
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
import { Rule } from '@ghostfolio/api/models/rule';
|
||||
import { UserSettings } from '@ghostfolio/common/interfaces';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
@ -8,7 +9,7 @@ export class RulesService {
|
||||
|
||||
public async evaluate<T extends RuleSettings>(
|
||||
aRules: Rule<T>[],
|
||||
aUserSettings: { baseCurrency: string }
|
||||
aUserSettings: UserSettings
|
||||
) {
|
||||
return aRules
|
||||
.filter((rule) => {
|
||||
|
@ -1,7 +0,0 @@
|
||||
import { ViewMode } from '@prisma/client';
|
||||
|
||||
export interface UserSettingsParams {
|
||||
currency?: string;
|
||||
userId: string;
|
||||
viewMode?: ViewMode;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
export interface UserSettings {
|
||||
emergencyFund?: number;
|
||||
locale?: string;
|
||||
isRestrictedView?: boolean;
|
||||
}
|
@ -1,6 +1,22 @@
|
||||
import { IsBoolean, IsNumber, IsOptional, IsString } from 'class-validator';
|
||||
import type { DateRange } from '@ghostfolio/common/types';
|
||||
import { ViewMode } from '@prisma/client';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsIn,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString
|
||||
} from 'class-validator';
|
||||
|
||||
export class UpdateUserSettingDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
baseCurrency?: string;
|
||||
|
||||
@IsIn(<DateRange[]>['1d', '1y', '5y', 'max', 'ytd'])
|
||||
@IsOptional()
|
||||
dateRange?: DateRange;
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
emergencyFund?: number;
|
||||
@ -24,4 +40,8 @@ export class UpdateUserSettingDto {
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
savingsRate?: number;
|
||||
|
||||
@IsIn(<ViewMode[]>['DEFAULT', 'ZEN'])
|
||||
@IsOptional()
|
||||
viewMode?: ViewMode;
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { ViewMode } from '@prisma/client';
|
||||
import { IsString } from 'class-validator';
|
||||
|
||||
export class UpdateUserSettingsDto {
|
||||
@IsString()
|
||||
baseCurrency: string;
|
||||
|
||||
@IsString()
|
||||
viewMode: ViewMode;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
||||
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
||||
import { PROPERTY_IS_READ_ONLY_MODE } from '@ghostfolio/common/config';
|
||||
import { User } from '@ghostfolio/common/interfaces';
|
||||
import { User, UserSettings } from '@ghostfolio/common/interfaces';
|
||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||
import type { RequestWithUser } from '@ghostfolio/common/types';
|
||||
import {
|
||||
@ -24,10 +24,7 @@ import { User as UserModel } from '@prisma/client';
|
||||
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
|
||||
|
||||
import { UserItem } from './interfaces/user-item.interface';
|
||||
import { UserSettingsParams } from './interfaces/user-settings-params.interface';
|
||||
import { UserSettings } from './interfaces/user-settings.interface';
|
||||
import { UpdateUserSettingDto } from './update-user-setting.dto';
|
||||
import { UpdateUserSettingsDto } from './update-user-settings.dto';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
@Controller('user')
|
||||
@ -130,33 +127,4 @@ export class UserController {
|
||||
userId: this.request.user.id
|
||||
});
|
||||
}
|
||||
|
||||
@Put('settings')
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
public async updateUserSettings(@Body() data: UpdateUserSettingsDto) {
|
||||
if (
|
||||
!hasPermission(
|
||||
this.request.user.permissions,
|
||||
permissions.updateUserSettings
|
||||
)
|
||||
) {
|
||||
throw new HttpException(
|
||||
getReasonPhrase(StatusCodes.FORBIDDEN),
|
||||
StatusCodes.FORBIDDEN
|
||||
);
|
||||
}
|
||||
|
||||
const userSettings: UserSettingsParams = {
|
||||
currency: data.baseCurrency,
|
||||
userId: this.request.user.id
|
||||
};
|
||||
|
||||
if (
|
||||
hasPermission(this.request.user.permissions, permissions.updateViewMode)
|
||||
) {
|
||||
userSettings.viewMode = data.viewMode;
|
||||
}
|
||||
|
||||
return await this.userService.updateUserSettings(userSettings);
|
||||
}
|
||||
}
|
||||
|
@ -4,19 +4,20 @@ import { PrismaService } from '@ghostfolio/api/services/prisma.service';
|
||||
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
||||
import { TagService } from '@ghostfolio/api/services/tag/tag.service';
|
||||
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 {
|
||||
getPermissions,
|
||||
hasRole,
|
||||
permissions
|
||||
} from '@ghostfolio/common/permissions';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Prisma, Role, User, ViewMode } from '@prisma/client';
|
||||
import { Prisma, Role, User } from '@prisma/client';
|
||||
import { sortBy } from 'lodash';
|
||||
|
||||
import { UserSettingsParams } from './interfaces/user-settings-params.interface';
|
||||
import { UserSettings } from './interfaces/user-settings.interface';
|
||||
|
||||
const crypto = require('crypto');
|
||||
|
||||
@Injectable()
|
||||
@ -68,10 +69,8 @@ export class UserService {
|
||||
}),
|
||||
accounts: Account,
|
||||
settings: {
|
||||
...(<UserSettings>Settings.settings),
|
||||
baseCurrency: Settings?.currency ?? UserService.DEFAULT_CURRENCY,
|
||||
locale: (<UserSettings>Settings.settings)?.locale ?? aLocale,
|
||||
viewMode: Settings?.viewMode ?? ViewMode.DEFAULT
|
||||
...(<UserSettings>(<unknown>Settings.settings)),
|
||||
locale: (<UserSettings>(<unknown>Settings.settings))?.locale ?? aLocale
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -89,7 +88,10 @@ export class UserService {
|
||||
}
|
||||
|
||||
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(
|
||||
@ -126,21 +128,37 @@ export class UserService {
|
||||
};
|
||||
|
||||
if (user?.Settings) {
|
||||
if (!user.Settings.currency) {
|
||||
// Set default currency if needed
|
||||
user.Settings.currency = UserService.DEFAULT_CURRENCY;
|
||||
if (!user.Settings.settings) {
|
||||
user.Settings.settings = {};
|
||||
}
|
||||
} else if (user) {
|
||||
// Set default settings if needed
|
||||
user.Settings = {
|
||||
currency: UserService.DEFAULT_CURRENCY,
|
||||
settings: null,
|
||||
currency: null,
|
||||
settings: {},
|
||||
updatedAt: new Date(),
|
||||
userId: user?.id,
|
||||
viewMode: ViewMode.DEFAULT
|
||||
viewMode: 'DEFAULT'
|
||||
};
|
||||
}
|
||||
|
||||
// Set default value for base currency
|
||||
if (!(user.Settings.settings as UserSettings)?.baseCurrency) {
|
||||
(user.Settings.settings as UserSettings).baseCurrency =
|
||||
UserService.DEFAULT_CURRENCY;
|
||||
}
|
||||
|
||||
// Set default value for date range
|
||||
(user.Settings.settings as UserSettings).dateRange =
|
||||
(user.Settings.settings as UserSettings).viewMode === 'ZEN'
|
||||
? 'max'
|
||||
: (user.Settings.settings as UserSettings)?.dateRange ?? 'max';
|
||||
|
||||
// Set default value for view mode
|
||||
if (!(user.Settings.settings as UserSettings).viewMode) {
|
||||
(user.Settings.settings as UserSettings).viewMode = 'DEFAULT';
|
||||
}
|
||||
|
||||
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
|
||||
user.subscription =
|
||||
this.subscriptionService.getSubscription(Subscription);
|
||||
@ -295,7 +313,7 @@ export class UserService {
|
||||
userId: string;
|
||||
userSettings: UserSettings;
|
||||
}) {
|
||||
const settings = userSettings as Prisma.JsonObject;
|
||||
const settings = userSettings as unknown as Prisma.JsonObject;
|
||||
|
||||
await this.prismaService.settings.upsert({
|
||||
create: {
|
||||
@ -317,33 +335,6 @@ export class UserService {
|
||||
return;
|
||||
}
|
||||
|
||||
public async updateUserSettings({
|
||||
currency,
|
||||
userId,
|
||||
viewMode
|
||||
}: UserSettingsParams) {
|
||||
await this.prismaService.settings.upsert({
|
||||
create: {
|
||||
currency,
|
||||
User: {
|
||||
connect: {
|
||||
id: userId
|
||||
}
|
||||
},
|
||||
viewMode
|
||||
},
|
||||
update: {
|
||||
currency,
|
||||
viewMode
|
||||
},
|
||||
where: {
|
||||
userId: userId
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private getRandomString(length: number) {
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
const result = [];
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||
import { UserSettings } from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { EvaluationResult } from './evaluation-result.interface';
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
export interface UserSettings {
|
||||
baseCurrency: string;
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||
import { groupBy } from '@ghostfolio/common/helper';
|
||||
import { TimelinePosition } from '@ghostfolio/common/interfaces';
|
||||
import { TimelinePosition, UserSettings } from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { EvaluationResult } from './interfaces/evaluation-result.interface';
|
||||
import { RuleInterface } from './interfaces/rule.interface';
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||
import {
|
||||
PortfolioDetails,
|
||||
PortfolioPosition
|
||||
PortfolioPosition,
|
||||
UserSettings
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { Rule } from '../../rule';
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||
import {
|
||||
PortfolioDetails,
|
||||
PortfolioPosition
|
||||
PortfolioPosition,
|
||||
UserSettings
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { Rule } from '../../rule';
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||
import { PortfolioDetails } from '@ghostfolio/common/interfaces';
|
||||
import { PortfolioDetails, UserSettings } from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { Rule } from '../../rule';
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||
import { UserSettings } from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { Rule } from '../../rule';
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||
import { UserSettings } from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { Rule } from '../../rule';
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||
import { UserSettings } from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { Rule } from '../../rule';
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||
import { UserSettings } from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { Rule } from '../../rule';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||
import { UserSettings } from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { Rule } from '../../rule';
|
||||
|
||||
|
@ -5,10 +5,6 @@ import { PositionDetailDialog } from '@ghostfolio/client/components/position/pos
|
||||
import { ToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component';
|
||||
import { DataService } from '@ghostfolio/client/services/data.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 { Position, User } from '@ghostfolio/common/interfaces';
|
||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||
@ -26,7 +22,6 @@ import { PositionDetailDialogParams } from '../position/position-detail-dialog/i
|
||||
templateUrl: './home-holdings.html'
|
||||
})
|
||||
export class HomeHoldingsComponent implements OnDestroy, OnInit {
|
||||
public dateRange: DateRange;
|
||||
public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS;
|
||||
public deviceType: string;
|
||||
public hasImpersonationId: boolean;
|
||||
@ -44,7 +39,6 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
|
||||
private impersonationStorageService: ImpersonationStorageService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private settingsStorageService: SettingsStorageService,
|
||||
private userService: UserService
|
||||
) {
|
||||
this.route.queryParams
|
||||
@ -73,7 +67,7 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
|
||||
permissions.createOrder
|
||||
);
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
this.update();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -88,18 +82,24 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
|
||||
this.hasImpersonationId = !!aId;
|
||||
});
|
||||
|
||||
this.dateRange =
|
||||
this.user.settings.viewMode === 'ZEN'
|
||||
? 'max'
|
||||
: <DateRange>this.settingsStorageService.getSetting(RANGE) ?? 'max';
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
public onChangeDateRange(aDateRange: DateRange) {
|
||||
this.dateRange = aDateRange;
|
||||
this.settingsStorageService.setSetting(RANGE, this.dateRange);
|
||||
this.update();
|
||||
public onChangeDateRange(dateRange: DateRange) {
|
||||
this.dataService
|
||||
.putUserSetting({ dateRange })
|
||||
.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() {
|
||||
@ -151,7 +151,7 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
|
||||
this.positions = undefined;
|
||||
|
||||
this.dataService
|
||||
.fetchPositions({ range: this.dateRange })
|
||||
.fetchPositions({ range: this.user?.settings?.dateRange })
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((response) => {
|
||||
this.positions = response.positions;
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div class="container justify-content-center p-3">
|
||||
<div *ngIf="user.settings.viewMode !== 'ZEN'" class="mb-3 text-center">
|
||||
<gf-toggle
|
||||
[defaultValue]="dateRange"
|
||||
[defaultValue]="user?.settings?.dateRange"
|
||||
[isLoading]="positions === undefined"
|
||||
[options]="dateRangeOptions"
|
||||
(change)="onChangeDateRange($event.value)"
|
||||
@ -17,7 +17,7 @@
|
||||
[hasPermissionToCreateOrder]="hasPermissionToCreateOrder"
|
||||
[locale]="user?.settings?.locale"
|
||||
[positions]="positions"
|
||||
[range]="dateRange"
|
||||
[range]="user?.settings?.dateRange"
|
||||
></gf-positions>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
@ -2,10 +2,6 @@ import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component';
|
||||
import { DataService } from '@ghostfolio/client/services/data.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 {
|
||||
LineChartItem,
|
||||
@ -25,7 +21,6 @@ import { takeUntil } from 'rxjs/operators';
|
||||
templateUrl: './home-overview.html'
|
||||
})
|
||||
export class HomeOverviewComponent implements OnDestroy, OnInit {
|
||||
public dateRange: DateRange;
|
||||
public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS;
|
||||
public deviceType: string;
|
||||
public errors: UniqueAsset[];
|
||||
@ -47,7 +42,6 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
|
||||
private dataService: DataService,
|
||||
private deviceService: DeviceDetectorService,
|
||||
private impersonationStorageService: ImpersonationStorageService,
|
||||
private settingsStorageService: SettingsStorageService,
|
||||
private userService: UserService
|
||||
) {
|
||||
this.userService.stateChanged
|
||||
@ -61,7 +55,7 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
|
||||
permissions.createOrder
|
||||
);
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
this.update();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -78,11 +72,6 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
|
||||
this.dateRange =
|
||||
this.user.settings.viewMode === 'ZEN'
|
||||
? 'max'
|
||||
: <DateRange>this.settingsStorageService.getSetting(RANGE) ?? 'max';
|
||||
|
||||
this.showDetails =
|
||||
!this.hasImpersonationId &&
|
||||
!this.user.settings.isRestrictedView &&
|
||||
@ -91,10 +80,22 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
|
||||
this.update();
|
||||
}
|
||||
|
||||
public onChangeDateRange(aDateRange: DateRange) {
|
||||
this.dateRange = aDateRange;
|
||||
this.settingsStorageService.setSetting(RANGE, this.dateRange);
|
||||
this.update();
|
||||
public onChangeDateRange(dateRange: DateRange) {
|
||||
this.dataService
|
||||
.putUserSetting({ dateRange })
|
||||
.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() {
|
||||
@ -107,7 +108,7 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
|
||||
|
||||
this.dataService
|
||||
.fetchChart({
|
||||
range: this.dateRange,
|
||||
range: this.user?.settings?.dateRange,
|
||||
version: this.user?.settings?.isExperimentalFeatures ? 2 : 1
|
||||
})
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
@ -125,7 +126,7 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
|
||||
});
|
||||
|
||||
this.dataService
|
||||
.fetchPortfolioPerformance({ range: this.dateRange })
|
||||
.fetchPortfolioPerformance({ range: this.user?.settings?.dateRange })
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((response) => {
|
||||
this.errors = response.errors;
|
||||
|
@ -46,7 +46,7 @@
|
||||
></gf-portfolio-performance>
|
||||
<div *ngIf="showDetails" class="text-center">
|
||||
<gf-toggle
|
||||
[defaultValue]="dateRange"
|
||||
[defaultValue]="user?.settings?.dateRange"
|
||||
[isLoading]="isLoadingPerformance"
|
||||
[options]="dateRangeOptions"
|
||||
(change)="onChangeDateRange($event.value)"
|
||||
|
@ -38,7 +38,7 @@ export class HomeSummaryComponent implements OnDestroy, OnInit {
|
||||
permissions.updateUserSettings
|
||||
);
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
this.update();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -59,7 +59,16 @@ export class HomeSummaryComponent implements OnDestroy, OnInit {
|
||||
.putUserSetting({ emergencyFund })
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(() => {
|
||||
this.update();
|
||||
this.userService.remove();
|
||||
|
||||
this.userService
|
||||
.get()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((user) => {
|
||||
this.user = user;
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -175,29 +175,6 @@ export class AccountPageComponent implements OnDestroy, OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
public onChangeUserSettings(aKey: string, aValue: string) {
|
||||
const settings = { ...this.user.settings, [aKey]: aValue };
|
||||
|
||||
this.dataService
|
||||
.putUserSettings({
|
||||
baseCurrency: settings?.baseCurrency,
|
||||
viewMode: settings?.viewMode
|
||||
})
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(() => {
|
||||
this.userService.remove();
|
||||
|
||||
this.userService
|
||||
.get()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((user) => {
|
||||
this.user = user;
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public onCheckout() {
|
||||
this.dataService
|
||||
.createCheckoutSession({ couponId: this.couponId, priceId: this.priceId })
|
||||
|
@ -99,7 +99,7 @@
|
||||
name="baseCurrency"
|
||||
[disabled]="!hasPermissionToUpdateUserSettings"
|
||||
[value]="user.settings.baseCurrency"
|
||||
(selectionChange)="onChangeUserSettings('baseCurrency', $event.value)"
|
||||
(selectionChange)="onChangeUserSetting('baseCurrency', $event.value)"
|
||||
>
|
||||
<mat-option
|
||||
*ngFor="let currency of currencies"
|
||||
@ -166,7 +166,7 @@
|
||||
name="viewMode"
|
||||
[disabled]="!hasPermissionToUpdateViewMode"
|
||||
[value]="user.settings.viewMode"
|
||||
(selectionChange)="onChangeUserSettings('viewMode', $event.value)"
|
||||
(selectionChange)="onChangeUserSetting('viewMode', $event.value)"
|
||||
>
|
||||
<mat-option value="DEFAULT">Default</mat-option>
|
||||
<mat-option value="ZEN">Zen</mat-option>
|
||||
|
@ -73,7 +73,18 @@ export class FirePageComponent implements OnDestroy, OnInit {
|
||||
this.dataService
|
||||
.putUserSetting({ savingsRate })
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(() => {});
|
||||
.subscribe(() => {
|
||||
this.userService.remove();
|
||||
|
||||
this.userService
|
||||
.get()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((user) => {
|
||||
this.user = user;
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy() {
|
||||
|
@ -12,7 +12,6 @@ import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.in
|
||||
import { SymbolItem } from '@ghostfolio/api/app/symbol/interfaces/symbol-item.interface';
|
||||
import { UserItem } from '@ghostfolio/api/app/user/interfaces/user-item.interface';
|
||||
import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto';
|
||||
import { UpdateUserSettingsDto } from '@ghostfolio/api/app/user/update-user-settings.dto';
|
||||
import { PropertyDto } from '@ghostfolio/api/services/property/property.dto';
|
||||
import { DATE_FORMAT } from '@ghostfolio/common/helper';
|
||||
import {
|
||||
@ -448,10 +447,6 @@ export class DataService {
|
||||
return this.http.put<User>(`/api/v1/user/setting`, aData);
|
||||
}
|
||||
|
||||
public putUserSettings(aData: UpdateUserSettingsDto) {
|
||||
return this.http.put<User>(`/api/v1/user/settings`, aData);
|
||||
}
|
||||
|
||||
public redeemCoupon(couponCode: string) {
|
||||
return this.http.post('/api/v1/subscription/redeem-coupon', {
|
||||
couponCode
|
||||
|
@ -1,10 +1,13 @@
|
||||
import { DateRange } from '@ghostfolio/common/types';
|
||||
import { ViewMode } from '@prisma/client';
|
||||
|
||||
export interface UserSettings {
|
||||
baseCurrency?: string;
|
||||
dateRange?: DateRange;
|
||||
emergencyFund?: number;
|
||||
isExperimentalFeatures?: boolean;
|
||||
isRestrictedView?: boolean;
|
||||
language?: string;
|
||||
locale: string;
|
||||
locale?: string;
|
||||
viewMode?: ViewMode;
|
||||
}
|
||||
|
@ -102,10 +102,10 @@ model Property {
|
||||
}
|
||||
|
||||
model Settings {
|
||||
currency String?
|
||||
currency String? /// @deprecated
|
||||
settings Json?
|
||||
updatedAt DateTime @updatedAt
|
||||
viewMode ViewMode?
|
||||
viewMode ViewMode? /// @deprecated
|
||||
userId String @id
|
||||
User User @relation(fields: [userId], references: [id])
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user