diff --git a/apps/client/src/app/components/home-holdings/home-holdings.component.ts b/apps/client/src/app/components/home-holdings/home-holdings.component.ts index cf7e52833..bae154607 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.component.ts +++ b/apps/client/src/app/components/home-holdings/home-holdings.component.ts @@ -58,7 +58,7 @@ export class GfHomeHoldingsComponent implements OnInit { protected hasImpersonationId: boolean; protected hasPermissionToAccessHoldingsChart: boolean; protected hasPermissionToCreateActivity: boolean; - protected holdings: PortfolioPosition[]; + protected holdings: PortfolioPosition[] | undefined; protected holdingType: HoldingType = 'ACTIVE'; protected readonly holdingTypeOptions: ToggleOption[] = [ { label: $localize`Active`, value: 'ACTIVE' }, @@ -181,8 +181,8 @@ export class GfHomeHoldingsComponent implements OnInit { this.viewModeFormControl.setValue( this.deviceType === 'mobile' ? GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE - : this.user?.settings?.holdingsViewMode || - GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE, + : (this.user?.settings?.holdingsViewMode ?? + GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE), { emitEvent: false } ); } else if (this.holdingType === 'CLOSED') { @@ -192,7 +192,7 @@ export class GfHomeHoldingsComponent implements OnInit { ); } - this.holdings = []; + this.holdings = undefined; this.fetchHoldings() .pipe(takeUntilDestroyed(this.destroyRef)) 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 fd4e63f29..eb0265af3 100644 --- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts +++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts @@ -15,18 +15,16 @@ import { ChangeDetectionStrategy, Component, ElementRef, - EventEmitter, - Input, + input, OnChanges, OnDestroy, - Output, - ViewChild + output, + viewChild } from '@angular/core'; import { DataSource } from '@prisma/client'; import { Big } from 'big.js'; import type { ChartData, TooltipOptions } from 'chart.js'; -import { LinearScale } from 'chart.js'; -import { Chart, Tooltip } from 'chart.js'; +import { Chart, LinearScale, Tooltip } from 'chart.js'; import { TreemapController, TreemapElement } from 'chartjs-chart-treemap'; import { isUUID } from 'class-validator'; import { differenceInDays, max } from 'date-fns'; @@ -52,33 +50,31 @@ const { gray, green, red } = OpenColor; export class GfTreemapChartComponent implements AfterViewInit, OnChanges, OnDestroy { - @Input() baseCurrency: string; - @Input() colorScheme: ColorScheme; - @Input() cursor: string; - @Input() dateRange: DateRange; - @Input() holdings: PortfolioPosition[]; - @Input() locale = getLocale(); + public readonly baseCurrency = input.required(); + public readonly colorScheme = input.required(); + public readonly cursor = input.required(); + public readonly dateRange = input.required(); + public readonly holdings = input(); + public readonly locale = input(getLocale()); - @Output() treemapChartClicked = new EventEmitter(); + public readonly treemapChartClicked = output(); - @ViewChild('chartCanvas') chartCanvas: ElementRef; + protected isLoading = true; - public chart: Chart<'treemap'>; - public isLoading = true; + private chart: Chart<'treemap'>; + private readonly chartCanvas = + viewChild.required>('chartCanvas'); public constructor() { Chart.register(LinearScale, Tooltip, TreemapController, TreemapElement); } + public ngAfterViewInit() { - if (this.holdings) { - this.initialize(); - } + this.initialize(); } public ngOnChanges() { - if (this.holdings) { - this.initialize(); - } + this.initialize(); } public ngOnDestroy() { @@ -159,13 +155,19 @@ export class GfTreemapChartComponent } private initialize() { + const holdings = this.holdings(); + + if (!holdings) { + return; + } + this.isLoading = true; const { endDate, startDate } = getIntervalFromDateRange({ - dateRange: this.dateRange + dateRange: this.dateRange() }); - const netPerformancePercentsWithCurrencyEffect = this.holdings.map( + const netPerformancePercentsWithCurrencyEffect = holdings.map( ({ dateOfFirstActivity, netPerformancePercentWithCurrencyEffect }) => { return getAnnualizedPerformancePercent({ daysInMarket: differenceInDays( @@ -301,12 +303,12 @@ export class GfTreemapChartComponent }, spacing: 1, // @ts-expect-error: should be PortfolioPosition[] - tree: this.holdings + tree: this.holdings() } ] }; - if (this.chartCanvas) { + if (this.chartCanvas()) { if (this.chart) { this.chart.data = data; this.chart.options.plugins ??= {}; @@ -315,7 +317,7 @@ export class GfTreemapChartComponent this.chart.update(); } else { - this.chart = new Chart<'treemap'>(this.chartCanvas.nativeElement, { + this.chart = new Chart<'treemap'>(this.chartCanvas().nativeElement, { data, options: { animation: false, @@ -339,9 +341,9 @@ export class GfTreemapChartComponent } catch {} }, onHover: (event, chartElement) => { - if (this.cursor) { + if (this.cursor()) { (event.native?.target as HTMLElement).style.cursor = - chartElement[0] ? this.cursor : 'default'; + chartElement[0] ? this.cursor() : 'default'; } }, plugins: { @@ -359,9 +361,9 @@ export class GfTreemapChartComponent private getTooltipPluginConfiguration(): Partial> { return { ...getTooltipOptions({ - colorScheme: this.colorScheme, - currency: this.baseCurrency, - locale: this.locale + colorScheme: this.colorScheme(), + currency: this.baseCurrency(), + locale: this.locale() }), // @ts-expect-error: no need to set all attributes in callbacks callbacks: { @@ -381,19 +383,19 @@ export class GfTreemapChartComponent return [ `${name ?? symbol} (${allocationInPercentage})`, - `${value?.toLocaleString(this.locale, { + `${value?.toLocaleString(this.locale(), { maximumFractionDigits: 2, minimumFractionDigits: 2 - })} ${this.baseCurrency}`, + })} ${this.baseCurrency()}`, '', $localize`Change` + ' (' + $localize`Performance` + ')', `${sign}${raw._data.netPerformanceWithCurrencyEffect.toLocaleString( - this.locale, + this.locale(), { maximumFractionDigits: 2, minimumFractionDigits: 2 } - )} ${this.baseCurrency} (${netPerformanceInPercentageWithSign})` + )} ${this.baseCurrency()} (${netPerformanceInPercentageWithSign})` ]; } else { return [