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
### 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

2
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({

2
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;
}

6
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<BenchmarkMarketDataDetailsResponse> {
const { endDate, startDate } = getIntervalFromDateRange(
const { endDate, startDate } = getIntervalFromDateRange({
dateRange,
new Date(startDateString)
);
startDate: new Date(startDateString)
});
const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts,

10
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) &&

2
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;

2
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,

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 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,

14
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()

20
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 };

4
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 }) => {

Loading…
Cancel
Save