From 02db0db733183931a8836f9a5d4f8bbeb8aa9750 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 2 Aug 2024 20:27:58 +0200 Subject: [PATCH] Feature/persist view mode of holdings tab on home page (#3624) * Persist view mode of holdings in user settings * Update changelog --- CHANGELOG.md | 1 + .../src/app/user/update-user-setting.dto.ts | 5 +++ apps/api/src/app/user/user.service.ts | 5 ++- .../home-holdings/home-holdings.component.ts | 40 ++++++++++++++++--- .../lib/interfaces/user-settings.interface.ts | 8 +++- .../src/lib/types/holding-view-mode.type.ts | 1 - .../src/lib/types/holdings-view-mode.type.ts | 1 + libs/common/src/lib/types/index.ts | 4 +- 8 files changed, 55 insertions(+), 10 deletions(-) delete mode 100644 libs/common/src/lib/types/holding-view-mode.type.ts create mode 100644 libs/common/src/lib/types/holdings-view-mode.type.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 30dd1f3a5..805821d7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Improved the color assignment in the chart of the holdings tab on the home page (experimental) +- Persisted the view mode of the holdings tab on the home page (experimental) - Improved the language localization for Catalan (`ca`) - Improved the language localization for Spanish (`es`) diff --git a/apps/api/src/app/user/update-user-setting.dto.ts b/apps/api/src/app/user/update-user-setting.dto.ts index 1fc02ff4d..78e6c27a9 100644 --- a/apps/api/src/app/user/update-user-setting.dto.ts +++ b/apps/api/src/app/user/update-user-setting.dto.ts @@ -2,6 +2,7 @@ import { IsCurrencyCode } from '@ghostfolio/api/validators/is-currency-code'; import type { ColorScheme, DateRange, + HoldingsViewMode, ViewMode } from '@ghostfolio/common/types'; @@ -66,6 +67,10 @@ export class UpdateUserSettingDto { @IsOptional() 'filters.tags'?: string[]; + @IsIn(['CHART', 'TABLE']) + @IsOptional() + holdingsViewMode?: HoldingsViewMode; + @IsBoolean() @IsOptional() isExperimentalFeatures?: boolean; diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 02a65b6a0..7aa1dbbe8 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -190,7 +190,7 @@ export class UserService { (user.Settings.settings as UserSettings).dateRange = (user.Settings.settings as UserSettings).viewMode === 'ZEN' ? 'max' - : (user.Settings.settings as UserSettings)?.dateRange ?? 'max'; + : ((user.Settings.settings as UserSettings)?.dateRange ?? 'max'); // Set default value for view mode if (!(user.Settings.settings as UserSettings).viewMode) { @@ -243,6 +243,9 @@ export class UserService { // Reset benchmark user.Settings.settings.benchmark = undefined; + + // Reset holdings view mode + user.Settings.settings.holdingsViewMode = undefined; } else if (user.subscription?.type === 'Premium') { currentPermissions.push(permissions.reportDataGlitch); diff --git a/apps/client/src/app/components/home-holdings/home-holdings.component.ts b/apps/client/src/app/components/home-holdings/home-holdings.component.ts index 3b99adb06..dca8bbe55 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.component.ts +++ b/apps/client/src/app/components/home-holdings/home-holdings.component.ts @@ -9,7 +9,7 @@ import { import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { HoldingType, - HoldingViewMode, + HoldingsViewMode, ToggleOption } from '@ghostfolio/common/types'; @@ -18,7 +18,7 @@ import { FormControl } from '@angular/forms'; import { Router } from '@angular/router'; import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { skip, takeUntil } from 'rxjs/operators'; @Component({ selector: 'gf-home-holdings', @@ -26,6 +26,8 @@ import { takeUntil } from 'rxjs/operators'; templateUrl: './home-holdings.html' }) export class HomeHoldingsComponent implements OnDestroy, OnInit { + public static DEFAULT_HOLDINGS_VIEW_MODE: HoldingsViewMode = 'TABLE'; + public deviceType: string; public hasImpersonationId: boolean; public hasPermissionToAccessHoldingsChart: boolean; @@ -37,7 +39,9 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit { { label: $localize`Closed`, value: 'CLOSED' } ]; public user: User; - public viewModeFormControl = new FormControl('TABLE'); + public viewModeFormControl = new FormControl( + HomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE + ); private unsubscribeSubject = new Subject(); @@ -81,6 +85,21 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit { this.changeDetectorRef.markForCheck(); } }); + + this.viewModeFormControl.valueChanges + .pipe( + // Skip inizialization: "new FormControl" + skip(1), + takeUntil(this.unsubscribeSubject) + ) + .subscribe((holdingsViewMode) => { + this.dataService + .putUserSetting({ holdingsViewMode }) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(() => { + this.userService.remove(); + }); + }); } public onChangeHoldingType(aHoldingType: HoldingType) { @@ -122,9 +141,20 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit { this.hasPermissionToAccessHoldingsChart && this.holdingType === 'ACTIVE' ) { - this.viewModeFormControl.enable(); + this.viewModeFormControl.enable({ emitEvent: false }); + + this.viewModeFormControl.setValue( + this.deviceType === 'mobile' + ? HomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE + : this.user?.settings?.holdingsViewMode || + HomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE, + { emitEvent: false } + ); } else if (this.holdingType === 'CLOSED') { - this.viewModeFormControl.setValue('TABLE'); + this.viewModeFormControl.setValue( + HomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE, + { emitEvent: false } + ); } this.holdings = undefined; diff --git a/libs/common/src/lib/interfaces/user-settings.interface.ts b/libs/common/src/lib/interfaces/user-settings.interface.ts index a0599d132..5c88e3f4b 100644 --- a/libs/common/src/lib/interfaces/user-settings.interface.ts +++ b/libs/common/src/lib/interfaces/user-settings.interface.ts @@ -1,4 +1,9 @@ -import { ColorScheme, DateRange, ViewMode } from '@ghostfolio/common/types'; +import { + ColorScheme, + DateRange, + HoldingsViewMode, + ViewMode +} from '@ghostfolio/common/types'; export interface UserSettings { annualInterestRate?: number; @@ -9,6 +14,7 @@ export interface UserSettings { emergencyFund?: number; 'filters.accounts'?: string[]; 'filters.tags'?: string[]; + holdingsViewMode?: HoldingsViewMode; isExperimentalFeatures?: boolean; isRestrictedView?: boolean; language?: string; diff --git a/libs/common/src/lib/types/holding-view-mode.type.ts b/libs/common/src/lib/types/holding-view-mode.type.ts deleted file mode 100644 index 50a4e2b29..000000000 --- a/libs/common/src/lib/types/holding-view-mode.type.ts +++ /dev/null @@ -1 +0,0 @@ -export type HoldingViewMode = 'CHART' | 'TABLE'; diff --git a/libs/common/src/lib/types/holdings-view-mode.type.ts b/libs/common/src/lib/types/holdings-view-mode.type.ts new file mode 100644 index 000000000..7b5d0a09c --- /dev/null +++ b/libs/common/src/lib/types/holdings-view-mode.type.ts @@ -0,0 +1 @@ +export type HoldingsViewMode = 'CHART' | 'TABLE'; diff --git a/libs/common/src/lib/types/index.ts b/libs/common/src/lib/types/index.ts index 65fdfe5f0..68d4a2ec4 100644 --- a/libs/common/src/lib/types/index.ts +++ b/libs/common/src/lib/types/index.ts @@ -8,7 +8,7 @@ import type { DateRange } from './date-range.type'; import type { Granularity } from './granularity.type'; import type { GroupBy } from './group-by.type'; import type { HoldingType } from './holding-type.type'; -import type { HoldingViewMode } from './holding-view-mode.type'; +import type { HoldingsViewMode } from './holdings-view-mode.type'; import type { MarketAdvanced } from './market-advanced.type'; import type { MarketDataPreset } from './market-data-preset.type'; import type { MarketState } from './market-state.type'; @@ -31,7 +31,7 @@ export type { Granularity, GroupBy, HoldingType, - HoldingViewMode, + HoldingsViewMode, Market, MarketAdvanced, MarketDataPreset,