Browse Source

feat: add filters for the tabs of the home page

pull/1290/head
Zakaria YAHI 3 years ago
parent
commit
989daeee7a
  1. 60
      apps/client/src/app/components/home-holdings/home-holdings.component.ts
  2. 10
      apps/client/src/app/components/home-holdings/home-holdings.html
  3. 2
      apps/client/src/app/components/home-holdings/home-holdings.module.ts
  4. 59
      apps/client/src/app/components/home-overview/home-overview.component.ts
  5. 12
      apps/client/src/app/components/home-overview/home-overview.html
  6. 2
      apps/client/src/app/components/home-overview/home-overview.module.ts
  7. 56
      apps/client/src/app/components/home-summary/home-summary.component.ts
  8. 10
      apps/client/src/app/components/home-summary/home-summary.html
  9. 2
      apps/client/src/app/components/home-summary/home-summary.module.ts

60
apps/client/src/app/components/home-holdings/home-holdings.component.ts

@ -6,13 +6,13 @@ import { ToggleComponent } from '@ghostfolio/client/components/toggle/toggle.com
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 { Position, User } from '@ghostfolio/common/interfaces';
import { Filter, Position, User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { DateRange } from '@ghostfolio/common/types';
import { DataSource } from '@prisma/client';
import { AssetClass, DataSource } from '@prisma/client';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { PositionDetailDialogParams } from '../position/position-detail-dialog/interfaces/interfaces';
@ -22,8 +22,12 @@ import { PositionDetailDialogParams } from '../position/position-detail-dialog/i
templateUrl: './home-holdings.html'
})
export class HomeHoldingsComponent implements OnDestroy, OnInit {
public activeFilters: Filter[] = [];
public allFilters: Filter[];
public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS;
public deviceType: string;
public filterPlaceholder = '';
public filters$ = new Subject<Filter[]>();
public hasImpersonationId: boolean;
public hasPermissionToCreateOrder: boolean;
public positions: Position[];
@ -67,6 +71,39 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
permissions.createOrder
);
const accountFilters: Filter[] = this.user.accounts
.filter(({ accountType }) => {
return accountType === 'SECURITIES';
})
.map(({ id, name }) => {
return {
id,
label: name,
type: 'ACCOUNT'
};
});
const assetClassFilters: Filter[] = [];
for (const assetClass of Object.keys(AssetClass)) {
assetClassFilters.push({
id: assetClass,
label: assetClass,
type: 'ASSET_CLASS'
});
}
const tagFilters: Filter[] = this.user.tags.map(({ id, name }) => {
return {
id,
label: name,
type: 'TAG'
};
});
this.allFilters = [
...accountFilters,
...assetClassFilters,
...tagFilters
];
this.update();
}
});
@ -82,6 +119,18 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
this.hasImpersonationId = !!aId;
});
this.filters$
.pipe(distinctUntilChanged(), takeUntil(this.unsubscribeSubject))
.subscribe((filters) => {
this.activeFilters = filters;
this.filterPlaceholder =
this.activeFilters.length <= 0
? $localize`Filter by account or tag...`
: '';
this.update();
this.changeDetectorRef.markForCheck();
});
this.update();
}
@ -152,7 +201,10 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
this.positions = undefined;
this.dataService
.fetchPositions({ range: this.user?.settings?.dateRange })
.fetchPositions({
range: this.user?.settings?.dateRange,
filters: this.activeFilters
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((response) => {
this.positions = response.positions;

10
apps/client/src/app/components/home-holdings/home-holdings.html

@ -1,4 +1,14 @@
<div class="container justify-content-center p-3">
<div class="row">
<div class="align-items-center col-xs-12 col-md-8 offset-md-2">
<gf-activities-filter
[allFilters]="allFilters"
[isLoading]="positions === undefined"
[placeholder]="filterPlaceholder"
(valueChanged)="filters$.next($event)"
></gf-activities-filter>
</div>
</div>
<div *ngIf="user.settings.viewMode !== 'ZEN'" class="mb-3 text-center">
<gf-toggle
[defaultValue]="user?.settings?.dateRange"

2
apps/client/src/app/components/home-holdings/home-holdings.module.ts

@ -6,6 +6,7 @@ import { RouterModule } from '@angular/router';
import { GfPositionDetailDialogModule } from '@ghostfolio/client/components/position/position-detail-dialog/position-detail-dialog.module';
import { GfPositionsModule } from '@ghostfolio/client/components/positions/positions.module';
import { GfToggleModule } from '@ghostfolio/client/components/toggle/toggle.module';
import { GfActivitiesFilterModule } from '@ghostfolio/ui/activities-filter/activities-filter.module';
import { HomeHoldingsComponent } from './home-holdings.component';
@ -13,6 +14,7 @@ import { HomeHoldingsComponent } from './home-holdings.component';
declarations: [HomeHoldingsComponent],
imports: [
CommonModule,
GfActivitiesFilterModule,
GfPositionDetailDialogModule,
GfPositionsModule,
GfToggleModule,

59
apps/client/src/app/components/home-overview/home-overview.component.ts

@ -4,6 +4,7 @@ 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 {
Filter,
LineChartItem,
PortfolioPerformance,
UniqueAsset,
@ -11,9 +12,10 @@ import {
} from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { DateRange } from '@ghostfolio/common/types';
import { AssetClass } from '@prisma/client';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { distinctUntilChanged, takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-home-overview',
@ -21,9 +23,13 @@ import { takeUntil } from 'rxjs/operators';
templateUrl: './home-overview.html'
})
export class HomeOverviewComponent implements OnDestroy, OnInit {
public activeFilters: Filter[] = [];
public allFilters: Filter[];
public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS;
public deviceType: string;
public errors: UniqueAsset[];
public filterPlaceholder = '';
public filters$ = new Subject<Filter[]>();
public hasError: boolean;
public hasImpersonationId: boolean;
public hasPermissionToCreateOrder: boolean;
@ -55,6 +61,39 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
permissions.createOrder
);
const accountFilters: Filter[] = this.user.accounts
.filter(({ accountType }) => {
return accountType === 'SECURITIES';
})
.map(({ id, name }) => {
return {
id,
label: name,
type: 'ACCOUNT'
};
});
const assetClassFilters: Filter[] = [];
for (const assetClass of Object.keys(AssetClass)) {
assetClassFilters.push({
id: assetClass,
label: assetClass,
type: 'ASSET_CLASS'
});
}
const tagFilters: Filter[] = this.user.tags.map(({ id, name }) => {
return {
id,
label: name,
type: 'TAG'
};
});
this.allFilters = [
...accountFilters,
...assetClassFilters,
...tagFilters
];
this.update();
}
});
@ -72,6 +111,18 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
this.changeDetectorRef.markForCheck();
});
this.filters$
.pipe(distinctUntilChanged(), takeUntil(this.unsubscribeSubject))
.subscribe((filters) => {
this.activeFilters = filters;
this.filterPlaceholder =
this.activeFilters.length <= 0
? $localize`Filter by account or tag...`
: '';
this.update();
this.changeDetectorRef.markForCheck();
});
this.showDetails =
!this.hasImpersonationId &&
!this.user.settings.isRestrictedView &&
@ -108,7 +159,8 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
this.dataService
.fetchPortfolioPerformance({
range: this.user?.settings?.dateRange,
version: this.user?.settings?.isExperimentalFeatures ? 2 : 1
version: this.user?.settings?.isExperimentalFeatures ? 2 : 1,
filters: this.activeFilters
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((response) => {
@ -128,7 +180,8 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
this.dataService
.fetchChart({
range: this.user?.settings?.dateRange,
version: 1
version: 1,
filters: this.activeFilters
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((chartData) => {

12
apps/client/src/app/components/home-overview/home-overview.html

@ -1,3 +1,15 @@
<div class="container">
<div class="row">
<div class="col">
<gf-activities-filter
[allFilters]="allFilters"
[isLoading]="isLoadingPerformance"
[placeholder]="filterPlaceholder"
(valueChanged)="filters$.next($event)"
></gf-activities-filter>
</div>
</div>
</div>
<div
class="align-items-center container d-flex flex-column h-100 justify-content-center overview p-0 position-relative"
>

2
apps/client/src/app/components/home-overview/home-overview.module.ts

@ -3,6 +3,7 @@ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { GfPortfolioPerformanceModule } from '@ghostfolio/client/components/portfolio-performance/portfolio-performance.module';
import { GfToggleModule } from '@ghostfolio/client/components/toggle/toggle.module';
import { GfActivitiesFilterModule } from '@ghostfolio/ui/activities-filter/activities-filter.module';
import { GfLineChartModule } from '@ghostfolio/ui/line-chart/line-chart.module';
import { GfNoTransactionsInfoModule } from '@ghostfolio/ui/no-transactions-info';
@ -12,6 +13,7 @@ import { HomeOverviewComponent } from './home-overview.component';
declarations: [HomeOverviewComponent],
imports: [
CommonModule,
GfActivitiesFilterModule,
GfLineChartModule,
GfNoTransactionsInfoModule,
GfPortfolioPerformanceModule,

56
apps/client/src/app/components/home-summary/home-summary.component.ts

@ -2,10 +2,11 @@ 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 { PortfolioSummary, User } from '@ghostfolio/common/interfaces';
import { Filter, PortfolioSummary, User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { AssetClass } from '@prisma/client';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { distinctUntilChanged, takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-home-summary',
@ -13,6 +14,10 @@ import { takeUntil } from 'rxjs/operators';
templateUrl: './home-summary.html'
})
export class HomeSummaryComponent implements OnDestroy, OnInit {
public activeFilters: Filter[] = [];
public allFilters: Filter[];
public filterPlaceholder = '';
public filters$ = new Subject<Filter[]>();
public hasImpersonationId: boolean;
public hasPermissionToUpdateUserSettings: boolean;
public isLoading = true;
@ -38,6 +43,39 @@ export class HomeSummaryComponent implements OnDestroy, OnInit {
permissions.updateUserSettings
);
const accountFilters: Filter[] = this.user.accounts
.filter(({ accountType }) => {
return accountType === 'SECURITIES';
})
.map(({ id, name }) => {
return {
id,
label: name,
type: 'ACCOUNT'
};
});
const assetClassFilters: Filter[] = [];
for (const assetClass of Object.keys(AssetClass)) {
assetClassFilters.push({
id: assetClass,
label: assetClass,
type: 'ASSET_CLASS'
});
}
const tagFilters: Filter[] = this.user.tags.map(({ id, name }) => {
return {
id,
label: name,
type: 'TAG'
};
});
this.allFilters = [
...accountFilters,
...assetClassFilters,
...tagFilters
];
this.update();
}
});
@ -51,6 +89,18 @@ export class HomeSummaryComponent implements OnDestroy, OnInit {
this.hasImpersonationId = !!aId;
});
this.filters$
.pipe(distinctUntilChanged(), takeUntil(this.unsubscribeSubject))
.subscribe((filters) => {
this.activeFilters = filters;
this.filterPlaceholder =
this.activeFilters.length <= 0
? $localize`Filter by account or tag...`
: '';
this.update();
this.changeDetectorRef.markForCheck();
});
this.update();
}
@ -81,7 +131,7 @@ export class HomeSummaryComponent implements OnDestroy, OnInit {
this.isLoading = true;
this.dataService
.fetchPortfolioSummary()
.fetchPortfolioSummary(this.activeFilters)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((response) => {
this.summary = response;

10
apps/client/src/app/components/home-summary/home-summary.html

@ -1,4 +1,14 @@
<div class="container pb-3 px-3">
<div class="row">
<div class="align-items-center col-xs-12 col-md-8 offset-md-2">
<gf-activities-filter
[allFilters]="allFilters"
[isLoading]="isLoading"
[placeholder]="filterPlaceholder"
(valueChanged)="filters$.next($event)"
></gf-activities-filter>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-md-8 offset-md-2">
<mat-card class="h-100">

2
apps/client/src/app/components/home-summary/home-summary.module.ts

@ -3,6 +3,7 @@ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatCardModule } from '@angular/material/card';
import { RouterModule } from '@angular/router';
import { GfPortfolioSummaryModule } from '@ghostfolio/client/components/portfolio-summary/portfolio-summary.module';
import { GfActivitiesFilterModule } from '@ghostfolio/ui/activities-filter/activities-filter.module';
import { HomeSummaryComponent } from './home-summary.component';
@ -10,6 +11,7 @@ import { HomeSummaryComponent } from './home-summary.component';
declarations: [HomeSummaryComponent],
imports: [
CommonModule,
GfActivitiesFilterModule,
GfPortfolioSummaryModule,
MatCardModule,
RouterModule

Loading…
Cancel
Save