From 7d5a95f9eaa2f36a88c0522ede48c9d57cc7c7b1 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 15 Sep 2026 21:20:33 +0200 Subject: [PATCH] Add support for country codes to entity logo component --- .../currency-selector.component.html | 13 ++++-- .../currency-selector.component.ts | 15 +++--- .../entity-logo/entity-logo.component.html | 17 ++++++- .../entity-logo/entity-logo.component.scss | 12 +++-- .../entity-logo.component.stories.ts | 8 ++++ .../lib/entity-logo/entity-logo.component.ts | 5 ++ .../holdings-table.component.html | 1 + .../holdings-table.component.stories.ts | 2 +- .../holdings-table.component.ts | 12 ++++- libs/ui/src/lib/mocks/holdings.ts | 46 ++++++++++++++++--- 10 files changed, 107 insertions(+), 24 deletions(-) diff --git a/libs/ui/src/lib/currency-selector/currency-selector.component.html b/libs/ui/src/lib/currency-selector/currency-selector.component.html index 2100b01de3..c3e622dadb 100644 --- a/libs/ui/src/lib/currency-selector/currency-selector.component.html +++ b/libs/ui/src/lib/currency-selector/currency-selector.component.html @@ -1,5 +1,8 @@ -@if (emojiFlagOfSelectedCurrency) { - {{ emojiFlagOfSelectedCurrency }} +@if (countryCodeOfSelectedCurrency) { + } - {{ getEmojiFlagFromCurrency(currency) }} + {{ currency }} diff --git a/libs/ui/src/lib/currency-selector/currency-selector.component.ts b/libs/ui/src/lib/currency-selector/currency-selector.component.ts index 27bd3ad792..de0cd6ff30 100644 --- a/libs/ui/src/lib/currency-selector/currency-selector.component.ts +++ b/libs/ui/src/lib/currency-selector/currency-selector.component.ts @@ -1,7 +1,4 @@ -import { - getCountryCodeFromCurrency, - getEmojiFlag -} from '@ghostfolio/common/helper'; +import { getCountryCodeFromCurrency } from '@ghostfolio/common/helper'; import { FocusMonitor } from '@angular/cdk/a11y'; import { @@ -40,6 +37,7 @@ import { import { MatInput, MatInputModule } from '@angular/material/input'; import { map, startWith } from 'rxjs/operators'; +import { GfEntityLogoComponent } from '../entity-logo/entity-logo.component'; import { AbstractMatFormField } from '../shared/abstract-mat-form-field'; @Component({ @@ -51,6 +49,7 @@ import { AbstractMatFormField } from '../shared/abstract-mat-form-field'; }, imports: [ FormsModule, + GfEntityLogoComponent, MatAutocompleteModule, MatFormFieldModule, MatInputModule, @@ -99,12 +98,12 @@ export class GfCurrencySelectorComponent return { elementRef: this.formField.getConnectedOverlayOrigin() }; } - public get emojiFlagOfSelectedCurrency() { + public get countryCodeOfSelectedCurrency() { const selectedCurrency = this.currencies().find((currency) => { return currency === this.control.value; }); - return this.getEmojiFlagFromCurrency(selectedCurrency); + return getCountryCodeFromCurrency(selectedCurrency); } public override get empty() { @@ -126,8 +125,8 @@ export class GfCurrencySelectorComponent this.input().focus(); } - public getEmojiFlagFromCurrency(aCurrency = '') { - return getEmojiFlag(getCountryCodeFromCurrency(aCurrency)); + public getCountryCodeFromCurrency(aCurrency = '') { + return getCountryCodeFromCurrency(aCurrency); } public ngOnInit() { diff --git a/libs/ui/src/lib/entity-logo/entity-logo.component.html b/libs/ui/src/lib/entity-logo/entity-logo.component.html index fe58f8226c..0aadaa8e8b 100644 --- a/libs/ui/src/lib/entity-logo/entity-logo.component.html +++ b/libs/ui/src/lib/entity-logo/entity-logo.component.html @@ -1,4 +1,19 @@ -@if (src && !hasError) { +@if (countryCode) { + +} @else if (src && !hasError) { ; +export const FlagByCountryCode: Story = { + args: { + countryCode: 'US', + size: 'large', + tooltip: 'United States' + } +}; + export const LogoByAssetProfileIdentifier: Story = { args: { dataSource: 'YAHOO', diff --git a/libs/ui/src/lib/entity-logo/entity-logo.component.ts b/libs/ui/src/lib/entity-logo/entity-logo.component.ts index ef8e721056..c78e12489f 100644 --- a/libs/ui/src/lib/entity-logo/entity-logo.component.ts +++ b/libs/ui/src/lib/entity-logo/entity-logo.component.ts @@ -1,3 +1,4 @@ +import { getEmojiFlag } from '@ghostfolio/common/helper'; import { EntityLogoImageSourceService } from '@ghostfolio/ui/entity-logo/entity-logo-image-source.service'; import { @@ -11,12 +12,14 @@ import { DataSource } from '@prisma/client'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, + host: { class: 'align-items-center d-flex' }, schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-entity-logo', styleUrls: ['./entity-logo.component.scss'], templateUrl: './entity-logo.component.html' }) export class GfEntityLogoComponent implements OnChanges { + @Input() countryCode: string; @Input() dataSource: DataSource; @Input() hasPlaceholder = false; @Input() size: 'large'; @@ -27,6 +30,8 @@ export class GfEntityLogoComponent implements OnChanges { public hasError = false; public src?: string; + public readonly getEmojiFlag = getEmojiFlag; + public constructor( private readonly imageSourceService: EntityLogoImageSourceService ) {} 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 69be6f8961..2001a1b990 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.html +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -17,6 +17,7 @@ [class.text-nowrap]="mode() === 'simple'" > ; export const Loading: Story = { args: { - holdings: undefined, hasPermissionToOpenDetails: false, hasPermissionToShowQuantities: true, hasPermissionToShowValues: true, + holdings: undefined, locale: 'en-US', pageSize: Number.MAX_SAFE_INTEGER } 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 ddf6a2f224..eac1c9d918 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -1,7 +1,9 @@ import { canOpenHoldingDetail, + getCountryCodeFromCurrency, getLocale, - getLowercase + getLowercase, + isCashPosition } from '@ghostfolio/common/helper'; import { AssetProfileIdentifier, @@ -120,6 +122,14 @@ export class GfHoldingsTableComponent { return this.hasPermissionToOpenDetails() && canOpenHoldingDetail(holding); } + protected getCountryCodeForCashPosition({ + assetProfile + }: PortfolioPosition): string { + return isCashPosition(assetProfile) + ? getCountryCodeFromCurrency(assetProfile.currency) + : ''; + } + protected onOpenHoldingDialog({ dataSource, symbol diff --git a/libs/ui/src/lib/mocks/holdings.ts b/libs/ui/src/lib/mocks/holdings.ts index 11f3bec0e8..0acb52e5f9 100644 --- a/libs/ui/src/lib/mocks/holdings.ts +++ b/libs/ui/src/lib/mocks/holdings.ts @@ -3,7 +3,7 @@ import { PortfolioPosition } from '@ghostfolio/common/interfaces'; export const holdings: PortfolioPosition[] = [ { activitiesCount: 1, - allocationInPercentage: 0.042990776363386086, + allocationInPercentage: 0.06447799495516787, assetProfile: { assetClass: 'EQUITY', assetClassLabel: 'Equity', @@ -48,7 +48,7 @@ export const holdings: PortfolioPosition[] = [ }, { activitiesCount: 2, - allocationInPercentage: 0.02377401948293552, + allocationInPercentage: 0.03565651141834935, assetProfile: { assetClass: 'EQUITY', assetClassLabel: 'Equity', @@ -93,7 +93,7 @@ export const holdings: PortfolioPosition[] = [ }, { activitiesCount: 1, - allocationInPercentage: 0.08038536990007467, + allocationInPercentage: 0.12056277911976934, assetProfile: { assetClass: 'EQUITY', assetClassLabel: 'Equity', @@ -138,7 +138,7 @@ export const holdings: PortfolioPosition[] = [ }, { activitiesCount: 1, - allocationInPercentage: 0.19216416482928922, + allocationInPercentage: 0.28820973005222217, assetProfile: { assetClass: 'LIQUIDITY', assetClassLabel: 'Liquidity', @@ -171,7 +171,7 @@ export const holdings: PortfolioPosition[] = [ }, { activitiesCount: 1, - allocationInPercentage: 0.04307127421937313, + allocationInPercentage: 0.06459872644204223, assetProfile: { assetClass: 'EQUITY', assetClassLabel: 'Equity', @@ -216,7 +216,7 @@ export const holdings: PortfolioPosition[] = [ }, { activitiesCount: 1, - allocationInPercentage: 0.18762679306394897, + allocationInPercentage: 0.28140453464652826, assetProfile: { assetClass: 'EQUITY', assetClassLabel: 'Equity', @@ -261,7 +261,7 @@ export const holdings: PortfolioPosition[] = [ }, { activitiesCount: 5, - allocationInPercentage: 0.053051250766657634, + allocationInPercentage: 0.0795667947557967, assetProfile: { assetClass: 'EQUITY', assetClassLabel: 'Equity', @@ -303,5 +303,37 @@ export const holdings: PortfolioPosition[] = [ quantity: 50, tags: [], valueInBaseCurrency: 15092 + }, + { + activitiesCount: 3, + allocationInPercentage: 0.06552292861012407, + assetProfile: { + assetClass: 'LIQUIDITY', + assetClassLabel: 'Liquidity', + assetSubClass: 'CASH', + assetSubClassLabel: 'Cash', + countries: [], + currency: 'USD', + dataSource: 'YAHOO', + holdings: [], + name: 'USD', + sectors: [], + symbol: 'USD' + }, + dateOfFirstActivity: new Date('2024-01-01T00:00:00.000Z'), + dividend: 0, + grossPerformance: 0, + grossPerformancePercent: 0, + grossPerformancePercentWithCurrencyEffect: 0, + grossPerformanceWithCurrencyEffect: 0, + investment: 12428.2, + marketPrice: 1, + netPerformance: 0, + netPerformancePercent: 0, + netPerformancePercentWithCurrencyEffect: 0, + netPerformanceWithCurrencyEffect: 0, + quantity: 12428.2, + tags: [], + valueInBaseCurrency: 12428.2 } ];