diff --git a/CHANGELOG.md b/CHANGELOG.md index ea4370113..4bfd2dd3d 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 - Refactored the active menu item state by parsing the current url +- Used a desaturated background color for unknown types in pie charts ### Fixed diff --git a/apps/api/src/models/portfolio.spec.ts b/apps/api/src/models/portfolio.spec.ts index 874ea0817..5831373a3 100644 --- a/apps/api/src/models/portfolio.spec.ts +++ b/apps/api/src/models/portfolio.spec.ts @@ -1,4 +1,9 @@ -import { baseCurrency, getUtc, getYesterday } from '@ghostfolio/helper'; +import { + UNKNOWN_KEY, + baseCurrency, + getUtc, + getYesterday +} from '@ghostfolio/helper'; import { Test } from '@nestjs/testing'; import { AccountType, Currency, DataSource, Role, Type } from '@prisma/client'; @@ -170,7 +175,7 @@ describe('Portfolio', () => { expect(details).toMatchObject({ BTCUSD: { accounts: { - Other: { + [UNKNOWN_KEY]: { /*current: exchangeRateDataService.toCurrency( 1 * 49631.24, Currency.USD, @@ -184,7 +189,7 @@ describe('Portfolio', () => { } }, currency: Currency.USD, - exchange: 'Other', + exchange: UNKNOWN_KEY, grossPerformance: 0, grossPerformancePercent: 0, investment: exchangeRateDataService.toCurrency( @@ -271,7 +276,7 @@ describe('Portfolio', () => { expect(details).toMatchObject({ ETHUSD: { accounts: { - Other: { + [UNKNOWN_KEY]: { /*current: exchangeRateDataService.toCurrency( 0.2 * 991.49, Currency.USD, @@ -285,7 +290,7 @@ describe('Portfolio', () => { } }, currency: Currency.USD, - exchange: 'Other', + exchange: UNKNOWN_KEY, // grossPerformance: 0, // grossPerformancePercent: 0, investment: exchangeRateDataService.toCurrency( diff --git a/apps/api/src/models/portfolio.ts b/apps/api/src/models/portfolio.ts index f867363a4..c82072bec 100644 --- a/apps/api/src/models/portfolio.ts +++ b/apps/api/src/models/portfolio.ts @@ -2,7 +2,12 @@ import { PortfolioItem, Position } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-item.interface'; -import { getToday, getYesterday, resetHours } from '@ghostfolio/helper'; +import { + UNKNOWN_KEY, + getToday, + getYesterday, + resetHours +} from '@ghostfolio/helper'; import { add, format, @@ -227,15 +232,17 @@ export class Portfolio implements PortfolioInterface { originalValueOfSymbol *= -1; } - if (accounts[orderOfSymbol.getAccount()?.name || 'Other']?.current) { + if ( + accounts[orderOfSymbol.getAccount()?.name || UNKNOWN_KEY]?.current + ) { accounts[ - orderOfSymbol.getAccount()?.name || 'Other' + orderOfSymbol.getAccount()?.name || UNKNOWN_KEY ].current += currentValueOfSymbol; accounts[ - orderOfSymbol.getAccount()?.name || 'Other' + orderOfSymbol.getAccount()?.name || UNKNOWN_KEY ].original += originalValueOfSymbol; } else { - accounts[orderOfSymbol.getAccount()?.name || 'Other'] = { + accounts[orderOfSymbol.getAccount()?.name || UNKNOWN_KEY] = { current: currentValueOfSymbol, original: originalValueOfSymbol }; diff --git a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts index 8d53a6bfe..1976a0522 100644 --- a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts @@ -1,4 +1,9 @@ -import { isCrypto, isCurrency, parseCurrency } from '@ghostfolio/helper'; +import { + UNKNOWN_KEY, + isCrypto, + isCurrency, + parseCurrency +} from '@ghostfolio/helper'; import { Injectable } from '@nestjs/common'; import { DataSource } from '@prisma/client'; import { format } from 'date-fns'; @@ -170,7 +175,7 @@ export class YahooFinanceService implements DataProviderInterface { private parseExchange(aString: string): string { if (aString?.toLowerCase() === 'ccc') { - return 'Other'; + return UNKNOWN_KEY; } return aString; @@ -200,7 +205,7 @@ export class YahooFinanceService implements DataProviderInterface { return Industry.Software; } - return Industry.Other; + return Industry.Unknown; } private parseSector(aString: string): Sector { @@ -222,7 +227,7 @@ export class YahooFinanceService implements DataProviderInterface { return Sector.Technology; } - return Sector.Other; + return Sector.Unknown; } private parseType(aString: string): Type { @@ -234,7 +239,7 @@ export class YahooFinanceService implements DataProviderInterface { return Type.Stock; } - return Type.Other; + return Type.Unknown; } } diff --git a/apps/api/src/services/interfaces/interfaces.ts b/apps/api/src/services/interfaces/interfaces.ts index 3200b5290..904eaae79 100644 --- a/apps/api/src/services/interfaces/interfaces.ts +++ b/apps/api/src/services/interfaces/interfaces.ts @@ -1,4 +1,5 @@ -import { Account, Currency, DataSource, Platform } from '@prisma/client'; +import { UNKNOWN_KEY } from '@ghostfolio/helper'; +import { Account, Currency, DataSource } from '@prisma/client'; import { OrderType } from '../../models/order-type'; @@ -7,9 +8,9 @@ export const Industry = { Biotechnology: 'Biotechnology', Food: 'Food', Internet: 'Internet', - Other: 'Other', Pharmaceutical: 'Pharmaceutical', - Software: 'Software' + Software: 'Software', + Unknown: UNKNOWN_KEY }; export const MarketState = { @@ -21,15 +22,15 @@ export const MarketState = { export const Sector = { Consumer: 'Consumer', Healthcare: 'Healthcare', - Other: 'Other', - Technology: 'Technology' + Technology: 'Technology', + Unknown: UNKNOWN_KEY }; export const Type = { Cryptocurrency: 'Cryptocurrency', ETF: 'ETF', - Other: 'Other', - Stock: 'Stock' + Stock: 'Stock', + Unknown: UNKNOWN_KEY }; export interface IOrder { diff --git a/apps/client/src/app/components/line-chart/line-chart.component.ts b/apps/client/src/app/components/line-chart/line-chart.component.ts index 5c6b68a5d..5614ed25d 100644 --- a/apps/client/src/app/components/line-chart/line-chart.component.ts +++ b/apps/client/src/app/components/line-chart/line-chart.component.ts @@ -9,7 +9,11 @@ import { OnInit, ViewChild } from '@angular/core'; -import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/helper'; +import { + getBackgroundColor, + primaryColorRgb, + secondaryColorRgb +} from '@ghostfolio/helper'; import { Chart, Filler, @@ -62,6 +66,10 @@ export class LineChartComponent implements OnChanges, OnDestroy, OnInit { } } + public ngOnDestroy() { + this.chart?.destroy(); + } + private initialize() { this.isLoading = true; const benchmarkPrices = []; @@ -76,7 +84,7 @@ export class LineChartComponent implements OnChanges, OnDestroy, OnInit { const canvas = document.getElementById('chartCanvas'); - var gradient = this.chartCanvas?.nativeElement + const gradient = this.chartCanvas?.nativeElement ?.getContext('2d') .createLinearGradient( 0, @@ -88,14 +96,7 @@ export class LineChartComponent implements OnChanges, OnDestroy, OnInit { 0, `rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.01)` ); - gradient.addColorStop( - 1, - getComputedStyle(document.documentElement).getPropertyValue( - window.matchMedia('(prefers-color-scheme: dark)').matches - ? '--dark-background' - : '--light-background' - ) - ); + gradient.addColorStop(1, getBackgroundColor()); const data = { labels, @@ -181,8 +182,4 @@ export class LineChartComponent implements OnChanges, OnDestroy, OnInit { this.isLoading = false; } - - public ngOnDestroy() { - this.chart?.destroy(); - } } diff --git a/apps/client/src/app/components/portfolio-proportion-chart/portfolio-proportion-chart.component.ts b/apps/client/src/app/components/portfolio-proportion-chart/portfolio-proportion-chart.component.ts index 6ab5b3459..b970ffd5c 100644 --- a/apps/client/src/app/components/portfolio-proportion-chart/portfolio-proportion-chart.component.ts +++ b/apps/client/src/app/components/portfolio-proportion-chart/portfolio-proportion-chart.component.ts @@ -8,6 +8,7 @@ import { ViewChild } from '@angular/core'; import { PortfolioPosition } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-position.interface'; +import { UNKNOWN_KEY, getCssVariable, getTextColor } from '@ghostfolio/helper'; import { Currency } from '@prisma/client'; import { Tooltip } from 'chart.js'; import { LinearScale } from 'chart.js'; @@ -38,7 +39,11 @@ export class PortfolioProportionChartComponent private colorMap: { [symbol: string]: string; - } = {}; + } = { + [UNKNOWN_KEY]: `rgba(${getTextColor()}, ${getCssVariable( + '--palette-foreground-divider-alpha' + )})` + }; public constructor() { Chart.register(ArcElement, DoughnutController, LinearScale, Tooltip); @@ -74,10 +79,10 @@ export class PortfolioProportionChartComponent }; } } else { - if (chartData['Other']) { - chartData['Other'].value += this.positions[symbol].value; + if (chartData[UNKNOWN_KEY]) { + chartData[UNKNOWN_KEY].value += this.positions[symbol].value; } else { - chartData['Other'] = { + chartData[UNKNOWN_KEY] = { value: this.positions[symbol].value }; } @@ -134,7 +139,8 @@ export class PortfolioProportionChartComponent tooltip: { callbacks: { label: (context) => { - const label = context.label; + const label = + context.label === UNKNOWN_KEY ? 'Other' : context.label; if (this.isInPercent) { const value = 100 * context.raw; diff --git a/apps/client/src/app/pages/analysis/analysis-page.html b/apps/client/src/app/pages/analysis/analysis-page.html index b5336589e..e282c522c 100644 --- a/apps/client/src/app/pages/analysis/analysis-page.html +++ b/apps/client/src/app/pages/analysis/analysis-page.html @@ -2,12 +2,15 @@

Analysis

- +
+

Positions

+ +
@@ -157,7 +160,7 @@
You can find more charts on your desktop: - www.ghostfol.io + Ghostfol.io
diff --git a/libs/helper/src/lib/config.ts b/libs/helper/src/lib/config.ts index 2684c6e1f..3c724127c 100644 --- a/libs/helper/src/lib/config.ts +++ b/libs/helper/src/lib/config.ts @@ -30,3 +30,5 @@ export const secondaryColorRgb = { export const DEFAULT_DATE_FORMAT = 'dd.MM.yyyy'; export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy'; + +export const UNKNOWN_KEY = 'UNKNOWN'; diff --git a/libs/helper/src/lib/helper.ts b/libs/helper/src/lib/helper.ts index 0e8123fc6..208c68d5f 100644 --- a/libs/helper/src/lib/helper.ts +++ b/libs/helper/src/lib/helper.ts @@ -11,6 +11,28 @@ export function capitalize(aString: string) { return aString.charAt(0).toUpperCase() + aString.slice(1).toLowerCase(); } +export function getBackgroundColor() { + return getCssVariable( + window.matchMedia('(prefers-color-scheme: dark)').matches + ? '--dark-background' + : '--light-background' + ); +} + +export function getCssVariable(aCssVariable: string) { + return getComputedStyle(document.documentElement).getPropertyValue( + aCssVariable + ); +} + +export function getTextColor() { + return getCssVariable( + window.matchMedia('(prefers-color-scheme: dark)').matches + ? '--light-primary-text' + : '--dark-primary-text' + ); +} + export function getToday() { const year = getYear(new Date()); const month = getMonth(new Date());