Browse Source

Feature/support calendar year date ranges on activities page (#6597)

* Support calendar year date ranges on activities page

* Update changelog
pull/6599/head
Thomas Kaul 4 days ago
committed by GitHub
parent
commit
088891a961
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      CHANGELOG.md
  2. 2
      apps/api/src/app/activities/activities.controller.ts
  3. 2
      apps/api/src/app/admin/admin.controller.ts
  4. 6
      apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts
  5. 10
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  6. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts
  7. 2
      apps/api/src/app/portfolio/portfolio.controller.ts
  8. 4
      apps/api/src/app/portfolio/portfolio.service.ts
  9. 14
      apps/client/src/app/pages/portfolio/activities/activities-page.component.ts
  10. 20
      libs/common/src/lib/calculation-helper.ts
  11. 4
      libs/ui/src/lib/treemap-chart/treemap-chart.component.ts

4
CHANGELOG.md

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
### Added
- Added support for specific calendar year date ranges (`2025`, `2024`, `2023`, etc.) on the portfolio activities page
### Changed ### Changed
- Consolidated the sign-out logic within the user service to unify cookie, state and token clearance - Consolidated the sign-out logic within the user service to unify cookie, state and token clearance

2
apps/api/src/app/activities/activities.controller.ts

@ -126,7 +126,7 @@ export class ActivitiesController {
let startDate: Date; let startDate: Date;
if (dateRange) { if (dateRange) {
({ endDate, startDate } = getIntervalFromDateRange(dateRange)); ({ endDate, startDate } = getIntervalFromDateRange({ dateRange }));
} }
const filters = this.apiService.buildFiltersFromQueryParams({ const filters = this.apiService.buildFiltersFromQueryParams({

2
apps/api/src/app/admin/admin.controller.ts

@ -172,7 +172,7 @@ export class AdminController {
let date: Date; let date: Date;
if (dateRange) { if (dateRange) {
const { startDate } = getIntervalFromDateRange(dateRange); const { startDate } = getIntervalFromDateRange({ dateRange });
date = startDate; date = startDate;
} }

6
apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts

@ -126,10 +126,10 @@ export class BenchmarksController {
@Query('tags') filterByTags?: string, @Query('tags') filterByTags?: string,
@Query('withExcludedAccounts') withExcludedAccountsParam = 'false' @Query('withExcludedAccounts') withExcludedAccountsParam = 'false'
): Promise<BenchmarkMarketDataDetailsResponse> { ): Promise<BenchmarkMarketDataDetailsResponse> {
const { endDate, startDate } = getIntervalFromDateRange( const { endDate, startDate } = getIntervalFromDateRange({
dateRange, dateRange,
new Date(startDateString) startDate: new Date(startDateString)
); });
const filters = this.apiService.buildFiltersFromQueryParams({ const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts, filterByAccounts,

10
apps/api/src/app/portfolio/calculator/portfolio-calculator.ts

@ -158,10 +158,10 @@ export abstract class PortfolioCalculator {
this.redisCacheService = redisCacheService; this.redisCacheService = redisCacheService;
this.userId = userId; this.userId = userId;
const { endDate, startDate } = getIntervalFromDateRange( const { endDate, startDate } = getIntervalFromDateRange({
'max', dateRange: 'max',
subDays(dateOfFirstActivity, 1) startDate: subDays(dateOfFirstActivity, 1)
); });
this.endDate = endOfDay(endDate); this.endDate = endOfDay(endDate);
this.startDate = startOfDay(startDate); this.startDate = startOfDay(startDate);
@ -885,7 +885,7 @@ export abstract class PortfolioCalculator {
// Make sure some key dates are present // Make sure some key dates are present
for (const dateRange of ['1d', '1y', '5y', 'max', 'mtd', 'wtd', 'ytd']) { for (const dateRange of ['1d', '1y', '5y', 'max', 'mtd', 'wtd', 'ytd']) {
const { endDate: dateRangeEnd, startDate: dateRangeStart } = const { endDate: dateRangeEnd, startDate: dateRangeStart } =
getIntervalFromDateRange(dateRange); getIntervalFromDateRange({ dateRange });
if ( if (
!isBefore(dateRangeStart, startDate) && !isBefore(dateRangeStart, startDate) &&

2
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts

@ -860,7 +860,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
return format(date, 'yyyy'); return format(date, 'yyyy');
}) })
] as DateRange[]) { ] as DateRange[]) {
const dateInterval = getIntervalFromDateRange(dateRange); const dateInterval = getIntervalFromDateRange({ dateRange });
const endDate = dateInterval.endDate; const endDate = dateInterval.endDate;
let startDate = dateInterval.startDate; let startDate = dateInterval.startDate;

2
apps/api/src/app/portfolio/portfolio.controller.ts

@ -320,7 +320,7 @@ export class PortfolioController {
await this.impersonationService.validateImpersonationId(impersonationId); await this.impersonationService.validateImpersonationId(impersonationId);
const userCurrency = this.request.user.settings.settings.baseCurrency; const userCurrency = this.request.user.settings.settings.baseCurrency;
const { endDate, startDate } = getIntervalFromDateRange(dateRange); const { endDate, startDate } = getIntervalFromDateRange({ dateRange });
const { activities } = await this.activitiesService.getActivities({ const { activities } = await this.activitiesService.getActivities({
endDate, endDate,

4
apps/api/src/app/portfolio/portfolio.service.ts

@ -403,7 +403,7 @@ export class PortfolioService {
const user = await this.userService.user({ id: userId }); const user = await this.userService.user({ id: userId });
const userCurrency = this.getUserCurrency(user); const userCurrency = this.getUserCurrency(user);
const { endDate, startDate } = getIntervalFromDateRange(dateRange); const { endDate, startDate } = getIntervalFromDateRange({ dateRange });
const { activities } = const { activities } =
await this.activitiesService.getActivitiesForPortfolioCalculator({ await this.activitiesService.getActivitiesForPortfolioCalculator({
@ -1047,7 +1047,7 @@ export class PortfolioService {
const { errors, hasErrors, historicalData } = const { errors, hasErrors, historicalData } =
await portfolioCalculator.getSnapshot(); await portfolioCalculator.getSnapshot();
const { endDate, startDate } = getIntervalFromDateRange(dateRange); const { endDate, startDate } = getIntervalFromDateRange({ dateRange });
const { chart } = await portfolioCalculator.getPerformance({ const { chart } = await portfolioCalculator.getPerformance({
end: endDate, end: endDate,

14
apps/client/src/app/pages/portfolio/activities/activities-page.component.ts

@ -10,6 +10,7 @@ import {
User User
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { DateRange } from '@ghostfolio/common/types';
import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table'; import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table';
import { DataService } from '@ghostfolio/ui/services'; import { DataService } from '@ghostfolio/ui/services';
@ -129,8 +130,13 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit {
} }
public fetchActivities() { public fetchActivities() {
const dateRange = this.user?.settings?.dateRange;
const range = this.isCalendarYear(dateRange) ? dateRange : undefined;
this.dataService this.dataService
.fetchActivities({ .fetchActivities({
range,
filters: this.userService.getFilters(), filters: this.userService.getFilters(),
skip: this.pageIndex * this.pageSize, skip: this.pageIndex * this.pageSize,
sortColumn: this.sortColumn, sortColumn: this.sortColumn,
@ -352,6 +358,14 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit {
this.unsubscribeSubject.complete(); this.unsubscribeSubject.complete();
} }
private isCalendarYear(dateRange: DateRange) {
if (!dateRange) {
return false;
}
return /^\d{4}$/.test(dateRange);
}
private openCreateActivityDialog(aActivity?: Activity) { private openCreateActivityDialog(aActivity?: Activity) {
this.userService this.userService
.get() .get()

20
libs/common/src/lib/calculation-helper.ts

@ -36,14 +36,16 @@ export function getAnnualizedPerformancePercent({
return new Big(0); return new Big(0);
} }
export function getIntervalFromDateRange( export function getIntervalFromDateRange(params: {
aDateRange: DateRange, dateRange: DateRange;
portfolioStart = new Date(0) endDate?: Date;
) { startDate?: Date;
let endDate = endOfDay(new Date()); }) {
let startDate = portfolioStart; const { dateRange } = params;
let endDate = params.endDate ?? endOfDay(new Date());
let startDate = params.startDate ?? new Date(0);
switch (aDateRange) { switch (dateRange) {
case '1d': case '1d':
startDate = max([startDate, subDays(resetHours(new Date()), 1)]); startDate = max([startDate, subDays(resetHours(new Date()), 1)]);
break; break;
@ -75,8 +77,8 @@ export function getIntervalFromDateRange(
break; break;
default: default:
// '2024', '2023', '2022', etc. // '2024', '2023', '2022', etc.
endDate = endOfYear(new Date(aDateRange)); endDate = endOfYear(new Date(dateRange));
startDate = max([startDate, new Date(aDateRange)]); startDate = max([startDate, new Date(dateRange)]);
} }
return { endDate, startDate }; return { endDate, startDate };

4
libs/ui/src/lib/treemap-chart/treemap-chart.component.ts

@ -162,7 +162,9 @@ export class GfTreemapChartComponent
private initialize() { private initialize() {
this.isLoading = true; this.isLoading = true;
const { endDate, startDate } = getIntervalFromDateRange(this.dateRange); const { endDate, startDate } = getIntervalFromDateRange({
dateRange: this.dateRange
});
const netPerformancePercentsWithCurrencyEffect = this.holdings.map( const netPerformancePercentsWithCurrencyEffect = this.holdings.map(
({ dateOfFirstActivity, netPerformancePercentWithCurrencyEffect }) => { ({ dateOfFirstActivity, netPerformancePercentWithCurrencyEffect }) => {

Loading…
Cancel
Save