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) {
+
+
+ {{ getEmojiFlag(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
}
];