Feature/add top performers to analysis page (#613)

* Add Top 3 / Bottom 3 performers

* Update changelog
pull/615/head
Thomas Kaul 3 years ago committed by GitHub
parent 313d2a2f79
commit aca37a27f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
- Added the _Top 3_ and _Bottom 3_ performers to the analysis page
## 1.99.0 - 01.01.2022
### Added

@ -2,9 +2,10 @@ import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { DataService } from '@ghostfolio/client/services/data.service';
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { User } from '@ghostfolio/common/interfaces';
import { Position, User } from '@ghostfolio/common/interfaces';
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
import { differenceInDays } from 'date-fns';
import { sortBy } from 'lodash';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@ -16,10 +17,12 @@ import { takeUntil } from 'rxjs/operators';
templateUrl: './analysis-page.html'
})
export class AnalysisPageComponent implements OnDestroy, OnInit {
public bottom3: Position[];
public daysInMarket: number;
public deviceType: string;
public hasImpersonationId: boolean;
public investments: InvestmentItem[];
public top3: Position[];
public user: User;
private unsubscribeSubject = new Subject<void>();
@ -58,6 +61,26 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
this.changeDetectorRef.markForCheck();
});
this.dataService
.fetchPositions({ range: 'max' })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ positions }) => {
const positionsSorted = sortBy(
positions,
'netPerformancePercentage'
).reverse();
this.top3 = positionsSorted.slice(0, 3);
if (positions?.length > 3) {
this.bottom3 = positionsSorted.slice(-3).reverse();
} else {
this.bottom3 = [];
}
this.changeDetectorRef.markForCheck();
});
this.userService.stateChanged
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((state) => {

@ -5,7 +5,7 @@
<mat-card class="mb-3">
<mat-card-header>
<mat-card-title class="align-items-center d-flex" i18n
>Timeline</mat-card-title
>Investment Timeline</mat-card-title
>
</mat-card-header>
<mat-card-content>
@ -19,4 +19,82 @@
</mat-card>
</div>
</div>
<div class="row">
<div class="col-md-6">
<mat-card class="mb-3">
<mat-card-header>
<mat-card-title class="align-items-center d-flex" i18n
>Top 3</mat-card-title
>
</mat-card-header>
<mat-card-content>
<div *ngFor="let position of top3; let i = index" class="d-flex py-1">
<div class="flex-grow-1 mr-2 text-truncate">
{{ i + 1 }}. {{ position.name }}
</div>
<div class="d-flex justify-content-end">
<gf-value
class="justify-content-end"
position="end"
[colorizeSign]="true"
[isPercent]="true"
[locale]="user?.settings?.locale"
[value]="position.netPerformancePercentage"
></gf-value>
</div>
</div>
<div>
<ngx-skeleton-loader
*ngIf="!top3"
animation="pulse"
[theme]="{
height: '1.5rem',
width: '100%'
}"
></ngx-skeleton-loader>
</div>
</mat-card-content>
</mat-card>
</div>
<div class="col-md-6">
<mat-card class="mb-3">
<mat-card-header>
<mat-card-title class="align-items-center d-flex" i18n
>Bottom 3</mat-card-title
>
</mat-card-header>
<mat-card-content>
<div
*ngFor="let position of bottom3; let i = index"
class="d-flex py-1"
>
<div class="flex-grow-1 mr-2 text-truncate">
{{ i + 1 }}. {{ position.name }}
</div>
<div class="d-flex justify-content-end">
<gf-value
class="justify-content-end"
position="end"
[colorizeSign]="true"
[isPercent]="true"
[locale]="user?.settings?.locale"
[value]="position.netPerformancePercentage"
></gf-value>
</div>
</div>
<div>
<ngx-skeleton-loader
*ngIf="!bottom3"
animation="pulse"
[theme]="{
height: '1.5rem',
width: '100%'
}"
></ngx-skeleton-loader>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
</div>

@ -2,6 +2,8 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatCardModule } from '@angular/material/card';
import { GfInvestmentChartModule } from '@ghostfolio/client/components/investment-chart/investment-chart.module';
import { GfValueModule } from '@ghostfolio/ui/value';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { AnalysisPageRoutingModule } from './analysis-page-routing.module';
import { AnalysisPageComponent } from './analysis-page.component';
@ -13,7 +15,9 @@ import { AnalysisPageComponent } from './analysis-page.component';
AnalysisPageRoutingModule,
CommonModule,
GfInvestmentChartModule,
MatCardModule
GfValueModule,
MatCardModule,
NgxSkeletonLoaderModule
],
providers: [],
schemas: [CUSTOM_ELEMENTS_SCHEMA]

Loading…
Cancel
Save