Feature/add group by year option on analysis page (#1568)
* Add group by year option
This commit is contained in:
parent
158bb00b8a
commit
925d38703e
@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Added support for the dividend timeline grouped by year
|
||||||
|
- Added support for the investment timeline grouped by year
|
||||||
- Set up the language localization for Français (`fr`)
|
- Set up the language localization for Français (`fr`)
|
||||||
- Set up the language localization for Português (`pt`)
|
- Set up the language localization for Português (`pt`)
|
||||||
|
|
||||||
|
@ -64,7 +64,8 @@ describe('PortfolioCalculator', () => {
|
|||||||
|
|
||||||
const investments = portfolioCalculator.getInvestments();
|
const investments = portfolioCalculator.getInvestments();
|
||||||
|
|
||||||
const investmentsByMonth = portfolioCalculator.getInvestmentsByMonth();
|
const investmentsByMonth =
|
||||||
|
portfolioCalculator.getInvestmentsByGroup('month');
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
|
|
||||||
|
@ -53,7 +53,8 @@ describe('PortfolioCalculator', () => {
|
|||||||
|
|
||||||
const investments = portfolioCalculator.getInvestments();
|
const investments = portfolioCalculator.getInvestments();
|
||||||
|
|
||||||
const investmentsByMonth = portfolioCalculator.getInvestmentsByMonth();
|
const investmentsByMonth =
|
||||||
|
portfolioCalculator.getInvestmentsByGroup('month');
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
|
|
||||||
|
@ -64,7 +64,8 @@ describe('PortfolioCalculator', () => {
|
|||||||
|
|
||||||
const investments = portfolioCalculator.getInvestments();
|
const investments = portfolioCalculator.getInvestments();
|
||||||
|
|
||||||
const investmentsByMonth = portfolioCalculator.getInvestmentsByMonth();
|
const investmentsByMonth =
|
||||||
|
portfolioCalculator.getInvestmentsByGroup('month');
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
|
|
||||||
|
@ -41,7 +41,8 @@ describe('PortfolioCalculator', () => {
|
|||||||
|
|
||||||
const investments = portfolioCalculator.getInvestments();
|
const investments = portfolioCalculator.getInvestments();
|
||||||
|
|
||||||
const investmentsByMonth = portfolioCalculator.getInvestmentsByMonth();
|
const investmentsByMonth =
|
||||||
|
portfolioCalculator.getInvestmentsByGroup('month');
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
|
|
||||||
|
@ -64,7 +64,8 @@ describe('PortfolioCalculator', () => {
|
|||||||
|
|
||||||
const investments = portfolioCalculator.getInvestments();
|
const investments = portfolioCalculator.getInvestments();
|
||||||
|
|
||||||
const investmentsByMonth = portfolioCalculator.getInvestmentsByMonth();
|
const investmentsByMonth =
|
||||||
|
portfolioCalculator.getInvestmentsByGroup('month');
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
|
|
||||||
|
@ -68,7 +68,8 @@ describe('PortfolioCalculator', () => {
|
|||||||
|
|
||||||
const investments = portfolioCalculator.getInvestments();
|
const investments = portfolioCalculator.getInvestments();
|
||||||
|
|
||||||
const investmentsByMonth = portfolioCalculator.getInvestmentsByMonth();
|
const investmentsByMonth =
|
||||||
|
portfolioCalculator.getInvestmentsByGroup('month');
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import { TimelineInfoInterface } from '@ghostfolio/api/app/portfolio/interfaces/
|
|||||||
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
|
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||||
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
|
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
|
||||||
import { ResponseError, TimelinePosition } from '@ghostfolio/common/interfaces';
|
import { ResponseError, TimelinePosition } from '@ghostfolio/common/interfaces';
|
||||||
|
import { GroupBy } from '@ghostfolio/common/types';
|
||||||
import { Logger } from '@nestjs/common';
|
import { Logger } from '@nestjs/common';
|
||||||
import { Type as TypeOfOrder } from '@prisma/client';
|
import { Type as TypeOfOrder } from '@prisma/client';
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
@ -478,46 +479,60 @@ export class PortfolioCalculator {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getInvestmentsByMonth(): { date: string; investment: Big }[] {
|
public getInvestmentsByGroup(
|
||||||
|
groupBy: GroupBy
|
||||||
|
): { date: string; investment: Big }[] {
|
||||||
if (this.orders.length === 0) {
|
if (this.orders.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const investments = [];
|
const investments = [];
|
||||||
let currentDate: Date;
|
let currentDate: Date;
|
||||||
let investmentByMonth = new Big(0);
|
let investmentByGroup = new Big(0);
|
||||||
|
|
||||||
for (const [index, order] of this.orders.entries()) {
|
for (const [index, order] of this.orders.entries()) {
|
||||||
if (
|
if (
|
||||||
isSameMonth(parseDate(order.date), currentDate) &&
|
isSameYear(parseDate(order.date), currentDate) &&
|
||||||
isSameYear(parseDate(order.date), currentDate)
|
(groupBy === 'year' || isSameMonth(parseDate(order.date), currentDate))
|
||||||
) {
|
) {
|
||||||
// Same month: Add up investments
|
// Same group: Add up investments
|
||||||
|
|
||||||
investmentByMonth = investmentByMonth.plus(
|
investmentByGroup = investmentByGroup.plus(
|
||||||
order.quantity.mul(order.unitPrice).mul(this.getFactor(order.type))
|
order.quantity.mul(order.unitPrice).mul(this.getFactor(order.type))
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// New month: Store previous month and reset
|
// New group: Store previous group and reset
|
||||||
|
|
||||||
if (currentDate) {
|
if (currentDate) {
|
||||||
investments.push({
|
investments.push({
|
||||||
date: format(set(currentDate, { date: 1 }), DATE_FORMAT),
|
date: format(
|
||||||
investment: investmentByMonth
|
set(currentDate, {
|
||||||
|
date: 1,
|
||||||
|
month: groupBy === 'year' ? 0 : currentDate.getMonth()
|
||||||
|
}),
|
||||||
|
DATE_FORMAT
|
||||||
|
),
|
||||||
|
investment: investmentByGroup
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
currentDate = parseDate(order.date);
|
currentDate = parseDate(order.date);
|
||||||
investmentByMonth = order.quantity
|
investmentByGroup = order.quantity
|
||||||
.mul(order.unitPrice)
|
.mul(order.unitPrice)
|
||||||
.mul(this.getFactor(order.type));
|
.mul(this.getFactor(order.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index === this.orders.length - 1) {
|
if (index === this.orders.length - 1) {
|
||||||
// Store current month (latest order)
|
// Store current group (latest order)
|
||||||
investments.push({
|
investments.push({
|
||||||
date: format(set(currentDate, { date: 1 }), DATE_FORMAT),
|
date: format(
|
||||||
investment: investmentByMonth
|
set(currentDate, {
|
||||||
|
date: 1,
|
||||||
|
month: groupBy === 'year' ? 0 : currentDate.getMonth()
|
||||||
|
}),
|
||||||
|
DATE_FORMAT
|
||||||
|
),
|
||||||
|
investment: investmentByGroup
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,8 +235,8 @@ export class PortfolioService {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
if (groupBy === 'month') {
|
if (groupBy) {
|
||||||
dividends = this.getDividendsByMonth(dividends);
|
dividends = this.getDividendsByGroup({ dividends, groupBy });
|
||||||
}
|
}
|
||||||
|
|
||||||
const startDate = this.getStartDate(
|
const startDate = this.getStartDate(
|
||||||
@ -282,26 +282,31 @@ export class PortfolioService {
|
|||||||
|
|
||||||
let investments: InvestmentItem[];
|
let investments: InvestmentItem[];
|
||||||
|
|
||||||
if (groupBy === 'month') {
|
if (groupBy) {
|
||||||
investments = portfolioCalculator.getInvestmentsByMonth().map((item) => {
|
investments = portfolioCalculator
|
||||||
return {
|
.getInvestmentsByGroup(groupBy)
|
||||||
date: item.date,
|
.map((item) => {
|
||||||
investment: item.investment.toNumber()
|
return {
|
||||||
};
|
date: item.date,
|
||||||
});
|
investment: item.investment.toNumber()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// Add investment of current month
|
// Add investment of current group
|
||||||
const dateOfCurrentMonth = format(
|
const dateOfCurrentGroup = format(
|
||||||
set(new Date(), { date: 1 }),
|
set(new Date(), {
|
||||||
|
date: 1,
|
||||||
|
month: groupBy === 'year' ? 0 : new Date().getMonth()
|
||||||
|
}),
|
||||||
DATE_FORMAT
|
DATE_FORMAT
|
||||||
);
|
);
|
||||||
const investmentOfCurrentMonth = investments.filter(({ date }) => {
|
const investmentOfCurrentGroup = investments.filter(({ date }) => {
|
||||||
return date === dateOfCurrentMonth;
|
return date === dateOfCurrentGroup;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (investmentOfCurrentMonth.length <= 0) {
|
if (investmentOfCurrentGroup.length <= 0) {
|
||||||
investments.push({
|
investments.push({
|
||||||
date: dateOfCurrentMonth,
|
date: dateOfCurrentGroup,
|
||||||
investment: 0
|
investment: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1264,47 +1269,66 @@ export class PortfolioService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDividendsByMonth(aDividends: InvestmentItem[]): InvestmentItem[] {
|
private getDividendsByGroup({
|
||||||
if (aDividends.length === 0) {
|
dividends,
|
||||||
|
groupBy
|
||||||
|
}: {
|
||||||
|
dividends: InvestmentItem[];
|
||||||
|
groupBy: GroupBy;
|
||||||
|
}): InvestmentItem[] {
|
||||||
|
if (dividends.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const dividends = [];
|
const dividendsByGroup: InvestmentItem[] = [];
|
||||||
let currentDate: Date;
|
let currentDate: Date;
|
||||||
let investmentByMonth = new Big(0);
|
let investmentByGroup = new Big(0);
|
||||||
|
|
||||||
for (const [index, dividend] of aDividends.entries()) {
|
for (const [index, dividend] of dividends.entries()) {
|
||||||
if (
|
if (
|
||||||
isSameMonth(parseDate(dividend.date), currentDate) &&
|
isSameYear(parseDate(dividend.date), currentDate) &&
|
||||||
isSameYear(parseDate(dividend.date), currentDate)
|
(groupBy === 'year' ||
|
||||||
|
isSameMonth(parseDate(dividend.date), currentDate))
|
||||||
) {
|
) {
|
||||||
// Same month: Add up divididends
|
// Same group: Add up dividends
|
||||||
|
|
||||||
investmentByMonth = investmentByMonth.plus(dividend.investment);
|
investmentByGroup = investmentByGroup.plus(dividend.investment);
|
||||||
} else {
|
} else {
|
||||||
// New month: Store previous month and reset
|
// New group: Store previous group and reset
|
||||||
|
|
||||||
if (currentDate) {
|
if (currentDate) {
|
||||||
dividends.push({
|
dividendsByGroup.push({
|
||||||
date: format(set(currentDate, { date: 1 }), DATE_FORMAT),
|
date: format(
|
||||||
investment: investmentByMonth
|
set(currentDate, {
|
||||||
|
date: 1,
|
||||||
|
month: groupBy === 'year' ? 0 : currentDate.getMonth()
|
||||||
|
}),
|
||||||
|
DATE_FORMAT
|
||||||
|
),
|
||||||
|
investment: investmentByGroup.toNumber()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
currentDate = parseDate(dividend.date);
|
currentDate = parseDate(dividend.date);
|
||||||
investmentByMonth = new Big(dividend.investment);
|
investmentByGroup = new Big(dividend.investment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index === aDividends.length - 1) {
|
if (index === dividends.length - 1) {
|
||||||
// Store current month (latest order)
|
// Store current month (latest order)
|
||||||
dividends.push({
|
dividendsByGroup.push({
|
||||||
date: format(set(currentDate, { date: 1 }), DATE_FORMAT),
|
date: format(
|
||||||
investment: investmentByMonth
|
set(currentDate, {
|
||||||
|
date: 1,
|
||||||
|
month: groupBy === 'year' ? 0 : currentDate.getMonth()
|
||||||
|
}),
|
||||||
|
DATE_FORMAT
|
||||||
|
),
|
||||||
|
investment: investmentByGroup.toNumber()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dividends;
|
return dividendsByGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFees({
|
private getFees({
|
||||||
|
@ -198,6 +198,15 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
|
|||||||
this.chart.options.scales.x.min = this.daysInMarket
|
this.chart.options.scales.x.min = this.daysInMarket
|
||||||
? subDays(new Date(), this.daysInMarket).toISOString()
|
? subDays(new Date(), this.daysInMarket).toISOString()
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.savingsRate &&
|
||||||
|
this.chart.options.plugins.annotation.annotations.savingsRate
|
||||||
|
) {
|
||||||
|
this.chart.options.plugins.annotation.annotations.savingsRate.value =
|
||||||
|
this.savingsRate;
|
||||||
|
}
|
||||||
|
|
||||||
this.chart.update();
|
this.chart.update();
|
||||||
} else {
|
} else {
|
||||||
this.chart = new Chart(this.chartCanvas.nativeElement, {
|
this.chart = new Chart(this.chartCanvas.nativeElement, {
|
||||||
|
@ -39,19 +39,20 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
|
|||||||
public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS;
|
public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS;
|
||||||
public daysInMarket: number;
|
public daysInMarket: number;
|
||||||
public deviceType: string;
|
public deviceType: string;
|
||||||
public dividendsByMonth: InvestmentItem[];
|
public dividendsByGroup: InvestmentItem[];
|
||||||
public dividendTimelineDataLabel = $localize`Dividend`;
|
public dividendTimelineDataLabel = $localize`Dividend`;
|
||||||
public filters$ = new Subject<Filter[]>();
|
public filters$ = new Subject<Filter[]>();
|
||||||
public firstOrderDate: Date;
|
public firstOrderDate: Date;
|
||||||
public hasImpersonationId: boolean;
|
public hasImpersonationId: boolean;
|
||||||
public investments: InvestmentItem[];
|
public investments: InvestmentItem[];
|
||||||
public investmentTimelineDataLabel = $localize`Deposit`;
|
public investmentTimelineDataLabel = $localize`Deposit`;
|
||||||
public investmentsByMonth: InvestmentItem[];
|
public investmentsByGroup: InvestmentItem[];
|
||||||
public isLoadingBenchmarkComparator: boolean;
|
public isLoadingBenchmarkComparator: boolean;
|
||||||
public isLoadingInvestmentChart: boolean;
|
public isLoadingInvestmentChart: boolean;
|
||||||
public mode: GroupBy = 'month';
|
public mode: GroupBy = 'month';
|
||||||
public modeOptions: ToggleOption[] = [
|
public modeOptions: ToggleOption[] = [
|
||||||
{ label: $localize`Monthly`, value: 'month' }
|
{ label: $localize`Monthly`, value: 'month' },
|
||||||
|
{ label: $localize`Yearly`, value: 'year' }
|
||||||
];
|
];
|
||||||
public performanceDataItems: HistoricalDataItem[];
|
public performanceDataItems: HistoricalDataItem[];
|
||||||
public performanceDataItemsInPercentage: HistoricalDataItem[];
|
public performanceDataItemsInPercentage: HistoricalDataItem[];
|
||||||
@ -91,6 +92,17 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get savingsRate() {
|
||||||
|
const savingsRatePerMonth =
|
||||||
|
this.hasImpersonationId || this.user.settings.isRestrictedView
|
||||||
|
? undefined
|
||||||
|
: this.user?.settings?.savingsRate;
|
||||||
|
|
||||||
|
return this.mode === 'year'
|
||||||
|
? savingsRatePerMonth * 12
|
||||||
|
: savingsRatePerMonth;
|
||||||
|
}
|
||||||
|
|
||||||
public ngOnInit() {
|
public ngOnInit() {
|
||||||
this.deviceType = this.deviceService.getDeviceInfo().deviceType;
|
this.deviceType = this.deviceService.getDeviceInfo().deviceType;
|
||||||
|
|
||||||
@ -201,6 +213,7 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
|
|||||||
|
|
||||||
public onChangeGroupBy(aMode: GroupBy) {
|
public onChangeGroupBy(aMode: GroupBy) {
|
||||||
this.mode = aMode;
|
this.mode = aMode;
|
||||||
|
this.fetchDividendsAndInvestments();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnDestroy() {
|
public ngOnDestroy() {
|
||||||
@ -208,6 +221,34 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
|
|||||||
this.unsubscribeSubject.complete();
|
this.unsubscribeSubject.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fetchDividendsAndInvestments() {
|
||||||
|
this.dataService
|
||||||
|
.fetchDividends({
|
||||||
|
filters: this.activeFilters,
|
||||||
|
groupBy: this.mode,
|
||||||
|
range: this.user?.settings?.dateRange
|
||||||
|
})
|
||||||
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
|
.subscribe(({ dividends }) => {
|
||||||
|
this.dividendsByGroup = dividends;
|
||||||
|
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.dataService
|
||||||
|
.fetchInvestments({
|
||||||
|
filters: this.activeFilters,
|
||||||
|
groupBy: this.mode,
|
||||||
|
range: this.user?.settings?.dateRange
|
||||||
|
})
|
||||||
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
|
.subscribe(({ investments }) => {
|
||||||
|
this.investmentsByGroup = investments;
|
||||||
|
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private openPositionDialog({
|
private openPositionDialog({
|
||||||
dataSource,
|
dataSource,
|
||||||
symbol
|
symbol
|
||||||
@ -291,32 +332,6 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
|
|||||||
this.changeDetectorRef.markForCheck();
|
this.changeDetectorRef.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.dataService
|
|
||||||
.fetchDividends({
|
|
||||||
filters: this.activeFilters,
|
|
||||||
groupBy: 'month',
|
|
||||||
range: this.user?.settings?.dateRange
|
|
||||||
})
|
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
|
||||||
.subscribe(({ dividends }) => {
|
|
||||||
this.dividendsByMonth = dividends;
|
|
||||||
|
|
||||||
this.changeDetectorRef.markForCheck();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.dataService
|
|
||||||
.fetchInvestments({
|
|
||||||
filters: this.activeFilters,
|
|
||||||
groupBy: 'month',
|
|
||||||
range: this.user?.settings?.dateRange
|
|
||||||
})
|
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
|
||||||
.subscribe(({ investments }) => {
|
|
||||||
this.investmentsByMonth = investments;
|
|
||||||
|
|
||||||
this.changeDetectorRef.markForCheck();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.dataService
|
this.dataService
|
||||||
.fetchPositions({
|
.fetchPositions({
|
||||||
filters: this.activeFilters,
|
filters: this.activeFilters,
|
||||||
@ -340,6 +355,7 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
|
|||||||
this.changeDetectorRef.markForCheck();
|
this.changeDetectorRef.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.fetchDividendsAndInvestments();
|
||||||
this.changeDetectorRef.markForCheck();
|
this.changeDetectorRef.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,15 +180,15 @@
|
|||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<gf-investment-chart
|
<gf-investment-chart
|
||||||
class="h-100"
|
class="h-100"
|
||||||
groupBy="month"
|
[benchmarkDataItems]="investmentsByGroup"
|
||||||
[benchmarkDataItems]="investmentsByMonth"
|
|
||||||
[benchmarkDataLabel]="investmentTimelineDataLabel"
|
[benchmarkDataLabel]="investmentTimelineDataLabel"
|
||||||
[currency]="user?.settings?.baseCurrency"
|
[currency]="user?.settings?.baseCurrency"
|
||||||
[daysInMarket]="daysInMarket"
|
[daysInMarket]="daysInMarket"
|
||||||
|
[groupBy]="mode"
|
||||||
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
||||||
[locale]="user?.settings?.locale"
|
[locale]="user?.settings?.locale"
|
||||||
[range]="user?.settings?.dateRange"
|
[range]="user?.settings?.dateRange"
|
||||||
[savingsRate]="(hasImpersonationId || user.settings.isRestrictedView) ? undefined : user?.settings?.savingsRate"
|
[savingsRate]="savingsRate"
|
||||||
></gf-investment-chart>
|
></gf-investment-chart>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -217,11 +217,11 @@
|
|||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<gf-investment-chart
|
<gf-investment-chart
|
||||||
class="h-100"
|
class="h-100"
|
||||||
groupBy="month"
|
[benchmarkDataItems]="dividendsByGroup"
|
||||||
[benchmarkDataItems]="dividendsByMonth"
|
|
||||||
[benchmarkDataLabel]="dividendTimelineDataLabel"
|
[benchmarkDataLabel]="dividendTimelineDataLabel"
|
||||||
[currency]="user?.settings?.baseCurrency"
|
[currency]="user?.settings?.baseCurrency"
|
||||||
[daysInMarket]="daysInMarket"
|
[daysInMarket]="daysInMarket"
|
||||||
|
[groupBy]="mode"
|
||||||
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
||||||
[locale]="user?.settings?.locale"
|
[locale]="user?.settings?.locale"
|
||||||
[range]="user?.settings?.dateRange"
|
[range]="user?.settings?.dateRange"
|
||||||
|
@ -10,5 +10,6 @@ export interface UserSettings {
|
|||||||
isRestrictedView?: boolean;
|
isRestrictedView?: boolean;
|
||||||
language?: string;
|
language?: string;
|
||||||
locale?: string;
|
locale?: string;
|
||||||
|
savingsRate?: number;
|
||||||
viewMode?: ViewMode;
|
viewMode?: ViewMode;
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
export type GroupBy = 'month';
|
export type GroupBy = 'month' | 'year';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user