diff --git a/CHANGELOG.md b/CHANGELOG.md index 364059f50..04e12a0e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added support for specific calendar year date ranges (`2025`, `2024`, `2023`, etc.) on the portfolio activities page + ### Changed - Consolidated the sign-out logic within the user service to unify cookie, state and token clearance diff --git a/apps/api/src/app/activities/activities.controller.ts b/apps/api/src/app/activities/activities.controller.ts index 49c8885a1..141fd4c82 100644 --- a/apps/api/src/app/activities/activities.controller.ts +++ b/apps/api/src/app/activities/activities.controller.ts @@ -126,7 +126,7 @@ export class ActivitiesController { let startDate: Date; if (dateRange) { - ({ endDate, startDate } = getIntervalFromDateRange(dateRange)); + ({ endDate, startDate } = getIntervalFromDateRange({ dateRange })); } const filters = this.apiService.buildFiltersFromQueryParams({ diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index 8a202a926..69b619625 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -172,7 +172,7 @@ export class AdminController { let date: Date; if (dateRange) { - const { startDate } = getIntervalFromDateRange(dateRange); + const { startDate } = getIntervalFromDateRange({ dateRange }); date = startDate; } diff --git a/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts b/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts index 629d90928..970925777 100644 --- a/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts +++ b/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts @@ -126,10 +126,10 @@ export class BenchmarksController { @Query('tags') filterByTags?: string, @Query('withExcludedAccounts') withExcludedAccountsParam = 'false' ): Promise { - const { endDate, startDate } = getIntervalFromDateRange( + const { endDate, startDate } = getIntervalFromDateRange({ dateRange, - new Date(startDateString) - ); + startDate: new Date(startDateString) + }); const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 553cb8c90..d57b85d8c 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -158,10 +158,10 @@ export abstract class PortfolioCalculator { this.redisCacheService = redisCacheService; this.userId = userId; - const { endDate, startDate } = getIntervalFromDateRange( - 'max', - subDays(dateOfFirstActivity, 1) - ); + const { endDate, startDate } = getIntervalFromDateRange({ + dateRange: 'max', + startDate: subDays(dateOfFirstActivity, 1) + }); this.endDate = endOfDay(endDate); this.startDate = startOfDay(startDate); @@ -885,7 +885,7 @@ export abstract class PortfolioCalculator { // Make sure some key dates are present for (const dateRange of ['1d', '1y', '5y', 'max', 'mtd', 'wtd', 'ytd']) { const { endDate: dateRangeEnd, startDate: dateRangeStart } = - getIntervalFromDateRange(dateRange); + getIntervalFromDateRange({ dateRange }); if ( !isBefore(dateRangeStart, startDate) && diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts index be69048df..2841e9975 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts @@ -860,7 +860,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { return format(date, 'yyyy'); }) ] as DateRange[]) { - const dateInterval = getIntervalFromDateRange(dateRange); + const dateInterval = getIntervalFromDateRange({ dateRange }); const endDate = dateInterval.endDate; let startDate = dateInterval.startDate; diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 73d4320d6..9c41aecb9 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -320,7 +320,7 @@ export class PortfolioController { await this.impersonationService.validateImpersonationId(impersonationId); const userCurrency = this.request.user.settings.settings.baseCurrency; - const { endDate, startDate } = getIntervalFromDateRange(dateRange); + const { endDate, startDate } = getIntervalFromDateRange({ dateRange }); const { activities } = await this.activitiesService.getActivities({ endDate, diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 5dab27939..60b413cf9 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -403,7 +403,7 @@ export class PortfolioService { const user = await this.userService.user({ id: userId }); const userCurrency = this.getUserCurrency(user); - const { endDate, startDate } = getIntervalFromDateRange(dateRange); + const { endDate, startDate } = getIntervalFromDateRange({ dateRange }); const { activities } = await this.activitiesService.getActivitiesForPortfolioCalculator({ @@ -1047,7 +1047,7 @@ export class PortfolioService { const { errors, hasErrors, historicalData } = await portfolioCalculator.getSnapshot(); - const { endDate, startDate } = getIntervalFromDateRange(dateRange); + const { endDate, startDate } = getIntervalFromDateRange({ dateRange }); const { chart } = await portfolioCalculator.getPerformance({ end: endDate, diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts index dd78a0221..4e5daf345 100644 --- a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts @@ -10,6 +10,7 @@ import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { DateRange } from '@ghostfolio/common/types'; import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table'; import { DataService } from '@ghostfolio/ui/services'; @@ -129,8 +130,13 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { } public fetchActivities() { + const dateRange = this.user?.settings?.dateRange; + + const range = this.isCalendarYear(dateRange) ? dateRange : undefined; + this.dataService .fetchActivities({ + range, filters: this.userService.getFilters(), skip: this.pageIndex * this.pageSize, sortColumn: this.sortColumn, @@ -352,6 +358,14 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { this.unsubscribeSubject.complete(); } + private isCalendarYear(dateRange: DateRange) { + if (!dateRange) { + return false; + } + + return /^\d{4}$/.test(dateRange); + } + private openCreateActivityDialog(aActivity?: Activity) { this.userService .get() diff --git a/libs/common/src/lib/calculation-helper.ts b/libs/common/src/lib/calculation-helper.ts index 76b38f9b2..2097fa52a 100644 --- a/libs/common/src/lib/calculation-helper.ts +++ b/libs/common/src/lib/calculation-helper.ts @@ -36,14 +36,16 @@ export function getAnnualizedPerformancePercent({ return new Big(0); } -export function getIntervalFromDateRange( - aDateRange: DateRange, - portfolioStart = new Date(0) -) { - let endDate = endOfDay(new Date()); - let startDate = portfolioStart; +export function getIntervalFromDateRange(params: { + dateRange: DateRange; + endDate?: Date; + startDate?: Date; +}) { + const { dateRange } = params; + let endDate = params.endDate ?? endOfDay(new Date()); + let startDate = params.startDate ?? new Date(0); - switch (aDateRange) { + switch (dateRange) { case '1d': startDate = max([startDate, subDays(resetHours(new Date()), 1)]); break; @@ -75,8 +77,8 @@ export function getIntervalFromDateRange( break; default: // '2024', '2023', '2022', etc. - endDate = endOfYear(new Date(aDateRange)); - startDate = max([startDate, new Date(aDateRange)]); + endDate = endOfYear(new Date(dateRange)); + startDate = max([startDate, new Date(dateRange)]); } return { endDate, startDate }; 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 a80876f6a..7069cabb0 100644 --- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts +++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts @@ -162,7 +162,9 @@ export class GfTreemapChartComponent private initialize() { this.isLoading = true; - const { endDate, startDate } = getIntervalFromDateRange(this.dateRange); + const { endDate, startDate } = getIntervalFromDateRange({ + dateRange: this.dateRange + }); const netPerformancePercentsWithCurrencyEffect = this.holdings.map( ({ dateOfFirstActivity, netPerformancePercentWithCurrencyEffect }) => {