From 7fac744d8ac7cd3e25357f18ec223e338484a2ff Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 6 Sep 2025 17:11:57 +0200 Subject: [PATCH] Refactoring --- .../src/app/portfolio/portfolio.service.ts | 161 +++++++++--------- .../src/app/components/rule/rule.component.ts | 2 +- .../portfolio/x-ray/x-ray-page.component.ts | 14 +- 3 files changed, 89 insertions(+), 88 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 716b55bd2..f5b4ab1c6 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -33,7 +33,6 @@ import { } from '@ghostfolio/common/calculation-helper'; import { DEFAULT_CURRENCY, - DEFAULT_LANGUAGE_CODE, TAG_ID_EMERGENCY_FUND, TAG_ID_EXCLUDE_FROM_ANALYSIS, UNKNOWN_KEY @@ -1235,26 +1234,66 @@ export class PortfolioService { const categories: PortfolioReportResponse['xRay']['categories'] = [ { - key: 'accountClusterRisk', + key: 'liquidity', name: this.i18nService.getTranslation({ - id: 'rule.accountClusterRisk.category', - languageCode: userSettings.language || DEFAULT_LANGUAGE_CODE + id: 'rule.liquidity.category', + languageCode: userSettings.language + }), + rules: await this.rulesService.evaluate( + [ + new BuyingPower( + this.exchangeRateDataService, + this.i18nService, + summary.cash, + userSettings.language + ) + ], + userSettings + ) + }, + { + key: 'emergencyFund', + name: this.i18nService.getTranslation({ + id: 'rule.emergencyFund.category', + languageCode: userSettings.language + }), + rules: await this.rulesService.evaluate( + [ + new EmergencyFundSetup( + this.exchangeRateDataService, + this.i18nService, + userSettings.language, + this.getTotalEmergencyFund({ + userSettings, + emergencyFundHoldingsValueInBaseCurrency: + this.getEmergencyFundHoldingsValueInBaseCurrency({ holdings }) + }).toNumber() + ) + ], + userSettings + ) + }, + { + key: 'currencyClusterRisk', + name: this.i18nService.getTranslation({ + id: 'rule.currencyClusterRisk.category', + languageCode: userSettings.language }), rules: summary.activityCount > 0 ? await this.rulesService.evaluate( [ - new AccountClusterRiskCurrentInvestment( + new CurrencyClusterRiskBaseCurrencyCurrentInvestment( this.exchangeRateDataService, this.i18nService, - userSettings.language, - accounts + Object.values(holdings), + userSettings.language ), - new AccountClusterRiskSingleAccount( + new CurrencyClusterRiskCurrentInvestment( this.exchangeRateDataService, this.i18nService, - userSettings.language, - accounts + Object.values(holdings), + userSettings.language ) ], userSettings @@ -1265,7 +1304,7 @@ export class PortfolioService { key: 'assetClassClusterRisk', name: this.i18nService.getTranslation({ id: 'rule.assetClassClusterRisk.category', - languageCode: userSettings.language || DEFAULT_LANGUAGE_CODE + languageCode: userSettings.language }), rules: summary.activityCount > 0 @@ -1289,26 +1328,26 @@ export class PortfolioService { : undefined }, { - key: 'currencyClusterRisk', + key: 'accountClusterRisk', name: this.i18nService.getTranslation({ - id: 'rule.currencyClusterRisk.category', - languageCode: userSettings.language || DEFAULT_LANGUAGE_CODE + id: 'rule.accountClusterRisk.category', + languageCode: userSettings.language }), rules: summary.activityCount > 0 ? await this.rulesService.evaluate( [ - new CurrencyClusterRiskBaseCurrencyCurrentInvestment( + new AccountClusterRiskCurrentInvestment( this.exchangeRateDataService, this.i18nService, - Object.values(holdings), - userSettings.language + userSettings.language, + accounts ), - new CurrencyClusterRiskCurrentInvestment( + new AccountClusterRiskSingleAccount( this.exchangeRateDataService, this.i18nService, - Object.values(holdings), - userSettings.language + userSettings.language, + accounts ) ], userSettings @@ -1319,7 +1358,7 @@ export class PortfolioService { key: 'economicMarketClusterRisk', name: this.i18nService.getTranslation({ id: 'rule.economicMarketClusterRisk.category', - languageCode: userSettings.language || DEFAULT_LANGUAGE_CODE + languageCode: userSettings.language }), rules: summary.activityCount > 0 @@ -1344,70 +1383,11 @@ export class PortfolioService { ) : undefined }, - { - key: 'emergencyFund', - name: this.i18nService.getTranslation({ - id: 'rule.emergencyFund.category', - languageCode: userSettings.language || DEFAULT_LANGUAGE_CODE - }), - rules: await this.rulesService.evaluate( - [ - new EmergencyFundSetup( - this.exchangeRateDataService, - this.i18nService, - userSettings.language, - this.getTotalEmergencyFund({ - userSettings, - emergencyFundHoldingsValueInBaseCurrency: - this.getEmergencyFundHoldingsValueInBaseCurrency({ holdings }) - }).toNumber() - ) - ], - userSettings - ) - }, - { - key: 'fees', - name: this.i18nService.getTranslation({ - id: 'rule.fees.category', - languageCode: userSettings.language || DEFAULT_LANGUAGE_CODE - }), - rules: await this.rulesService.evaluate( - [ - new FeeRatioInitialInvestment( - this.exchangeRateDataService, - this.i18nService, - userSettings.language, - summary.committedFunds, - summary.fees - ) - ], - userSettings - ) - }, - { - key: 'liquidity', - name: this.i18nService.getTranslation({ - id: 'rule.liquidity.category', - languageCode: userSettings.language || DEFAULT_LANGUAGE_CODE - }), - rules: await this.rulesService.evaluate( - [ - new BuyingPower( - this.exchangeRateDataService, - this.i18nService, - summary.cash, - userSettings.language - ) - ], - userSettings - ) - }, { key: 'regionalMarketClusterRisk', name: this.i18nService.getTranslation({ id: 'rule.regionalMarketClusterRisk.category', - languageCode: userSettings.language || DEFAULT_LANGUAGE_CODE + languageCode: userSettings.language }), rules: summary.activityCount > 0 @@ -1452,6 +1432,25 @@ export class PortfolioService { userSettings ) : undefined + }, + { + key: 'fees', + name: this.i18nService.getTranslation({ + id: 'rule.fees.category', + languageCode: userSettings.language + }), + rules: await this.rulesService.evaluate( + [ + new FeeRatioInitialInvestment( + this.exchangeRateDataService, + this.i18nService, + userSettings.language, + summary.committedFunds, + summary.fees + ) + ], + userSettings + ) } ]; diff --git a/apps/client/src/app/components/rule/rule.component.ts b/apps/client/src/app/components/rule/rule.component.ts index f93bd7658..f9d7c8664 100644 --- a/apps/client/src/app/components/rule/rule.component.ts +++ b/apps/client/src/app/components/rule/rule.component.ts @@ -69,8 +69,8 @@ export class RuleComponent implements OnInit { public onCustomizeRule(rule: PortfolioReportRule) { const dialogRef = this.dialog.open(GfRuleSettingsDialogComponent, { data: { - categoryName: this.categoryName, rule, + categoryName: this.categoryName, settings: this.settings } as IRuleSettingsDialogParams, width: this.deviceType === 'mobile' ? '100vw' : '50rem' diff --git a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts index 39e116507..c0578b5d7 100644 --- a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts +++ b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts @@ -114,9 +114,9 @@ export class GfXRayPageComponent { .fetchPortfolioReport() .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(({ xRay: { categories, statistics } }) => { + this.categories = categories; this.inactiveRules = this.mergeInactiveRules(categories); this.statistics = statistics; - this.categories = categories; this.isLoading = false; @@ -127,10 +127,12 @@ export class GfXRayPageComponent { private mergeInactiveRules( categories: PortfolioReportResponse['xRay']['categories'] ): PortfolioReportRule[] { - const inactiveRules = categories.flatMap( - (category) => category.rules?.filter(({ isActive }) => !isActive) ?? [] - ); - - return inactiveRules; + return categories.flatMap(({ rules }) => { + return ( + rules?.filter(({ isActive }) => { + return !isActive; + }) ?? [] + ); + }); } }