diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts index cbdacaa3f1..915c6833ab 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts @@ -11,6 +11,7 @@ import { convertValuesToPercentagesOfTotal, getAssetProfileIdentifier, getCountryName, + getHoldingName, isCashPosition } from '@ghostfolio/common/helper'; import { @@ -533,7 +534,7 @@ export class GfAllocationsPageComponent implements OnInit { value, dataSource: position.assetProfile.dataSource, isClickable: canOpenHoldingDetail(position), - name: position.assetProfile.name ?? '' + name: getHoldingName(position.assetProfile) }; } } diff --git a/apps/client/src/app/pages/public/public-page.component.ts b/apps/client/src/app/pages/public/public-page.component.ts index 46606753e4..8fa8abde18 100644 --- a/apps/client/src/app/pages/public/public-page.component.ts +++ b/apps/client/src/app/pages/public/public-page.component.ts @@ -3,6 +3,7 @@ import { convertValuesToPercentagesOfTotal, getAssetProfileIdentifier, getCountryName, + getHoldingName, isCashPosition } from '@ghostfolio/common/helper'; import { @@ -260,7 +261,7 @@ export class GfPublicPageComponent implements OnInit { this.symbols[symbol] = { symbol, value, - name: position.assetProfile.name ?? symbol + name: getHoldingName(position.assetProfile) }; } } diff --git a/libs/common/src/lib/helper.spec.ts b/libs/common/src/lib/helper.spec.ts index b7e7635670..4e2ddf8401 100644 --- a/libs/common/src/lib/helper.spec.ts +++ b/libs/common/src/lib/helper.spec.ts @@ -7,6 +7,7 @@ import { extractNumberFromString, getCountryCodeFromCurrency, getEmojiFlag, + getHoldingName, getNumberFormatGroup, getStringOrNull, getStringOrUndefined, @@ -143,6 +144,41 @@ describe('Helper', () => { }); }); + describe('Get holding name', () => { + it('Cash position', () => { + expect( + getHoldingName({ + assetSubClass: 'CASH', + assetSubClassLabel: 'Cash', + name: 'CHF', + symbol: 'CHF' + }) + ).toEqual('Cash (CHF)'); + }); + + it('Holding with name', () => { + expect( + getHoldingName({ + assetSubClass: 'STOCK', + assetSubClassLabel: 'Stock', + name: 'Apple Inc.', + symbol: 'AAPL' + }) + ).toEqual('Apple Inc.'); + }); + + it('Holding without name', () => { + expect( + getHoldingName({ + assetSubClass: 'STOCK', + assetSubClassLabel: 'Stock', + name: undefined, + symbol: 'AAPL' + }) + ).toEqual('AAPL'); + }); + }); + describe('Get number format group', () => { let languageGetter: jest.SpyInstance; diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 2a76261dae..4c82a08116 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -453,6 +453,22 @@ export function getEmojiFlag(aCountryCode: string) { }); } +export function getHoldingName({ + assetSubClass, + assetSubClassLabel, + name, + symbol +}: Pick< + PortfolioPosition['assetProfile'], + 'assetSubClass' | 'assetSubClassLabel' | 'name' | 'symbol' +>) { + if (isCashPosition({ assetSubClass })) { + return `${assetSubClassLabel} (${symbol})`; + } + + return name ?? symbol; +} + export function getLocale() { return navigator.language ?? DEFAULT_LOCALE; } diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.html b/libs/ui/src/lib/holdings-table/holdings-table.component.html index 2001a1b990..688aac75e8 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.html +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -20,7 +20,7 @@ [countryCode]="getCountryCodeForCashPosition(element)" [dataSource]="element.assetProfile.dataSource" [symbol]="element.assetProfile.symbol" - [tooltip]="element.assetProfile.name" + [tooltip]="getHoldingName(element.assetProfile)" /> @@ -40,11 +40,11 @@ mat-cell [class.w-100]="mode() === 'simple'" > -
- {{ element.assetProfile.name }} - @if (element.assetProfile.name === element.assetProfile.symbol) { - ({{ element.assetProfile.assetSubClassLabel }}) - } +
+ {{ getHoldingName(element.assetProfile) }}
@if (mode() === 'default') {
diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.ts b/libs/ui/src/lib/holdings-table/holdings-table.component.ts index eac1c9d918..5eed45950f 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -1,6 +1,7 @@ import { canOpenHoldingDetail, getCountryCodeFromCurrency, + getHoldingName, getLocale, getLowercase, isCashPosition @@ -89,6 +90,8 @@ export class GfHoldingsTableComponent { return columns; }); + protected readonly getHoldingName = getHoldingName; + protected readonly isLoading = computed(() => { return !this.holdings(); }); diff --git a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts index 83b9916c6e..01037f77f4 100644 --- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts +++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts @@ -3,7 +3,11 @@ import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; import { getTooltipOptions } from '@ghostfolio/common/chart-helper'; -import { canOpenHoldingDetail, getLocale } from '@ghostfolio/common/helper'; +import { + canOpenHoldingDetail, + getHoldingName, + getLocale +} from '@ghostfolio/common/helper'; import { AssetProfileIdentifier, PortfolioPosition @@ -399,20 +403,18 @@ export class GfTreemapChartComponent const raw = context.raw as GfTreemapDataPoint; const allocationInPercentage = `${(raw._data.allocationInPercentage * 100).toFixed(2)}%`; - const name = raw._data.assetProfile.name; + const name = getHoldingName(raw._data.assetProfile); const sign = raw._data.netPerformancePercentWithCurrencyEffect > 0 ? '+' : ''; - const symbol = raw._data.assetProfile.symbol; - const netPerformanceInPercentageWithSign = `${sign}${(raw._data.netPerformancePercentWithCurrencyEffect * 100).toFixed(2)}%`; if (raw._data.valueInBaseCurrency !== null) { const value = raw._data.valueInBaseCurrency; return [ - `${name ?? symbol} (${allocationInPercentage})`, + `${name} (${allocationInPercentage})`, `${value?.toLocaleString(this.locale(), { maximumFractionDigits: 2, minimumFractionDigits: 2 @@ -429,7 +431,7 @@ export class GfTreemapChartComponent ]; } else { return [ - `${name ?? symbol} (${allocationInPercentage})`, + `${name} (${allocationInPercentage})`, '', $localize`Performance`, netPerformanceInPercentageWithSign