Browse Source

Feature/improve precision of values in holding detail dialog on mobile (#5337)

* Improve dynamic numerical precision

* Shorten date on mobile

* Extend Storybook story of value component

* Update changelog
pull/5192/merge
Thomas Kaul 2 days ago
committed by GitHub
parent
commit
fcaa4f7996
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 59
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
  3. 6
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html
  4. 4
      apps/client/src/app/components/home-overview/home-overview.component.ts
  5. 4
      libs/common/src/lib/config.ts
  6. 7
      libs/ui/src/lib/activities-table/activities-table.component.html
  7. 5
      libs/ui/src/lib/activities-table/activities-table.component.ts
  8. 18
      libs/ui/src/lib/value/value.component.stories.ts
  9. 3
      libs/ui/src/lib/value/value.component.ts

2
CHANGELOG.md

@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Extended the import functionality by tags
- Improved the dynamic numerical precision for various values in the holding detail dialog
- Shortened the date in the activities table on mobile
- Introduced the fuzzy search for the accounts endpoint
- Refactored the fuzzy search for the holdings of the assistant
- Improved the language localization for Polish (`pl`)

59
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts

@ -3,7 +3,11 @@ import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-foote
import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module';
import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { NUMERICAL_PRECISION_THRESHOLD } from '@ghostfolio/common/config';
import {
NUMERICAL_PRECISION_THRESHOLD_3_FIGURES,
NUMERICAL_PRECISION_THRESHOLD_5_FIGURES,
NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
} from '@ghostfolio/common/config';
import { DATE_FORMAT, downloadAsFile } from '@ghostfolio/common/helper';
import {
DataProviderInfo,
@ -101,6 +105,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
public assetClass: string;
public assetSubClass: string;
public averagePrice: number;
public averagePricePrecision = 2;
public benchmarkDataItems: LineChartItem[];
public benchmarkLabel = $localize`Average Unit Price`;
public countries: {
@ -122,11 +127,15 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
public marketDataItems: MarketData[] = [];
public marketPrice: number;
public marketPriceMax: number;
public marketPriceMaxPrecision = 2;
public marketPriceMin: number;
public marketPriceMinPrecision = 2;
public marketPricePrecision = 2;
public netPerformance: number;
public netPerformancePrecision = 2;
public netPerformancePercent: number;
public netPerformancePercentWithCurrencyEffect: number;
public netPerformancePercentWithCurrencyEffectPrecision = 2;
public netPerformanceWithCurrencyEffect: number;
public netPerformanceWithCurrencyEffectPrecision = 2;
public quantity: number;
@ -274,6 +283,14 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
value
}) => {
this.averagePrice = averagePrice;
if (
this.data.deviceType === 'mobile' &&
this.averagePrice >= NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
) {
this.averagePricePrecision = 0;
}
this.benchmarkDataItems = [];
this.countries = {};
this.dataProviderInfo = dataProviderInfo;
@ -281,7 +298,8 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
if (
this.data.deviceType === 'mobile' &&
this.dividendInBaseCurrency >= NUMERICAL_PRECISION_THRESHOLD
this.dividendInBaseCurrency >=
NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
) {
this.dividendInBaseCurrencyPrecision = 0;
}
@ -320,19 +338,42 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
if (
this.data.deviceType === 'mobile' &&
this.investmentInBaseCurrencyWithCurrencyEffect >=
NUMERICAL_PRECISION_THRESHOLD
NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
) {
this.investmentInBaseCurrencyWithCurrencyEffectPrecision = 0;
}
this.marketPrice = marketPrice;
this.marketPriceMax = marketPriceMax;
if (
this.data.deviceType === 'mobile' &&
this.marketPriceMax >= NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
) {
this.marketPriceMaxPrecision = 0;
}
this.marketPriceMin = marketPriceMin;
if (
this.data.deviceType === 'mobile' &&
this.marketPriceMin >= NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
) {
this.marketPriceMinPrecision = 0;
}
if (
this.data.deviceType === 'mobile' &&
this.marketPrice >= NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
) {
this.marketPricePrecision = 0;
}
this.netPerformance = netPerformance;
if (
this.data.deviceType === 'mobile' &&
this.netPerformance >= NUMERICAL_PRECISION_THRESHOLD
this.netPerformance >= NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
) {
this.netPerformancePrecision = 0;
}
@ -342,13 +383,21 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
this.netPerformancePercentWithCurrencyEffect =
netPerformancePercentWithCurrencyEffect;
if (
this.data.deviceType === 'mobile' &&
this.netPerformancePercentWithCurrencyEffect >=
NUMERICAL_PRECISION_THRESHOLD_3_FIGURES
) {
this.netPerformancePercentWithCurrencyEffectPrecision = 0;
}
this.netPerformanceWithCurrencyEffect =
netPerformanceWithCurrencyEffect;
if (
this.data.deviceType === 'mobile' &&
this.netPerformanceWithCurrencyEffect >=
NUMERICAL_PRECISION_THRESHOLD
NUMERICAL_PRECISION_THRESHOLD_5_FIGURES
) {
this.netPerformanceWithCurrencyEffectPrecision = 0;
}

6
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html

@ -77,6 +77,7 @@
[colorizeSign]="true"
[isPercent]="true"
[locale]="data.locale"
[precision]="netPerformancePercentWithCurrencyEffectPrecision"
[value]="netPerformancePercentWithCurrencyEffect"
>
@if (
@ -95,6 +96,7 @@
size="medium"
[isCurrency]="true"
[locale]="data.locale"
[precision]="averagePricePrecision"
[unit]="SymbolProfile?.currency"
[value]="averagePrice"
>Average Unit Price</gf-value
@ -106,6 +108,7 @@
size="medium"
[isCurrency]="true"
[locale]="data.locale"
[precision]="marketPricePrecision"
[unit]="SymbolProfile?.currency"
[value]="marketPrice"
>Market Price</gf-value
@ -122,6 +125,7 @@
marketPriceMin?.toFixed(2) === marketPrice?.toFixed(2) &&
marketPriceMax?.toFixed(2) !== marketPriceMin?.toFixed(2)
}"
[precision]="marketPriceMinPrecision"
[unit]="SymbolProfile?.currency"
[value]="marketPriceMin"
>Minimum Price</gf-value
@ -138,6 +142,7 @@
marketPriceMax?.toFixed(2) === marketPrice?.toFixed(2) &&
marketPriceMax?.toFixed(2) !== marketPriceMin?.toFixed(2)
}"
[precision]="marketPriceMaxPrecision"
[unit]="SymbolProfile?.currency"
[value]="marketPriceMax"
>Maximum Price</gf-value
@ -208,6 +213,7 @@
<gf-value
i18n
size="medium"
[deviceType]="data.deviceType"
[isDate]="true"
[locale]="data.locale"
[value]="firstBuyDate"

4
apps/client/src/app/components/home-overview/home-overview.component.ts

@ -3,7 +3,7 @@ import { LayoutService } from '@ghostfolio/client/core/layout.service';
import { DataService } from '@ghostfolio/client/services/data.service';
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { NUMERICAL_PRECISION_THRESHOLD } from '@ghostfolio/common/config';
import { NUMERICAL_PRECISION_THRESHOLD_6_FIGURES } from '@ghostfolio/common/config';
import {
AssetProfileIdentifier,
LineChartItem,
@ -143,7 +143,7 @@ export class GfHomeOverviewComponent implements OnDestroy, OnInit {
if (
this.deviceType === 'mobile' &&
this.performance.currentValueInBaseCurrency >=
NUMERICAL_PRECISION_THRESHOLD
NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
) {
this.precision = 0;
}

4
libs/common/src/lib/config.ts

@ -136,7 +136,9 @@ export const HEADER_KEY_SKIP_INTERCEPTOR = 'X-Skip-Interceptor';
export const MAX_TOP_HOLDINGS = 50;
export const NUMERICAL_PRECISION_THRESHOLD = 100000;
export const NUMERICAL_PRECISION_THRESHOLD_3_FIGURES = 100;
export const NUMERICAL_PRECISION_THRESHOLD_5_FIGURES = 10000;
export const NUMERICAL_PRECISION_THRESHOLD_6_FIGURES = 100000;
export const PROPERTY_API_KEY_GHOSTFOLIO = 'API_KEY_GHOSTFOLIO';
export const PROPERTY_API_KEY_OPENROUTER = 'API_KEY_OPENROUTER';

7
libs/ui/src/lib/activities-table/activities-table.component.html

@ -171,7 +171,12 @@
</th>
<td *matCellDef="let element" class="px-1" mat-cell>
<div class="d-flex">
{{ element.date | date: defaultDateFormat }}
<gf-value
[deviceType]="deviceType"
[isDate]="true"
[locale]="locale"
[value]="isLoading ? undefined : element.date"
/>
</div>
</td>
</ng-container>

5
libs/ui/src/lib/activities-table/activities-table.component.ts

@ -6,7 +6,7 @@ import {
DEFAULT_PAGE_SIZE,
TAG_ID_EXCLUDE_FROM_ANALYSIS
} from '@ghostfolio/common/config';
import { getDateFormatString, getLocale } from '@ghostfolio/common/helper';
import { getLocale } from '@ghostfolio/common/helper';
import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces';
import { OrderWithAccount } from '@ghostfolio/common/types';
@ -128,7 +128,6 @@ export class GfActivitiesTableComponent
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
public defaultDateFormat: string;
public displayedColumns = [];
public endOfToday = endOfToday();
public hasDrafts = false;
@ -175,8 +174,6 @@ export class GfActivitiesTableComponent
}
public ngOnChanges() {
this.defaultDateFormat = getDateFormatString(this.locale);
this.displayedColumns = [
'select',
'importStatus',

18
libs/ui/src/lib/value/value.component.stories.ts

@ -11,7 +11,13 @@ export default {
moduleMetadata({
imports: [NgxSkeletonLoaderModule]
})
]
],
argTypes: {
deviceType: {
control: 'select',
options: ['desktop', 'mobile']
}
}
} as Meta<GfValueComponent>;
type Story = StoryObj<GfValueComponent>;
@ -31,6 +37,16 @@ export const Currency: Story = {
}
};
export const DateValue: Story = {
args: {
deviceType: 'desktop',
isDate: true,
locale: 'en-US',
value: new Date().toISOString()
},
name: 'Date'
};
export const Label: Story = {
args: {
locale: 'en-US',

3
libs/ui/src/lib/value/value.component.ts

@ -22,6 +22,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
})
export class GfValueComponent implements OnChanges {
@Input() colorizeSign = false;
@Input() deviceType: string;
@Input() icon = '';
@Input() isAbsolute = false;
@Input() isCurrency = false;
@ -118,7 +119,7 @@ export class GfValueComponent implements OnChanges {
{
day: '2-digit',
month: '2-digit',
year: 'numeric'
year: this.deviceType === 'mobile' ? '2-digit' : 'numeric'
}
);
} else {

Loading…
Cancel
Save