Browse Source

Setup allocations page and endpoint

pull/859/head
Thomas 3 years ago
parent
commit
df3d8e9d56
  1. 6
      apps/api/src/app/portfolio/portfolio.controller.ts
  2. 13
      apps/api/src/app/portfolio/portfolio.service.ts
  3. 38
      apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts
  4. 5
      apps/client/src/app/pages/portfolio/allocations/allocations-page.html
  5. 2
      apps/client/src/app/pages/portfolio/allocations/allocations-page.module.ts
  6. 10
      apps/client/src/app/services/data.service.ts

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

@ -105,7 +105,8 @@ export class PortfolioController {
@UseInterceptors(TransformDataSourceInResponseInterceptor)
public async getDetails(
@Headers('impersonation-id') impersonationId: string,
@Query('range') range
@Query('range') range,
@Query('tags') tags?: string
): Promise<PortfolioDetails & { hasError: boolean }> {
let hasError = false;
@ -113,7 +114,8 @@ export class PortfolioController {
await this.portfolioService.getDetails(
impersonationId,
this.request.user.id,
range
range,
tags?.split(',')
);
if (hasErrors || hasNotDefinedValuesInObject(holdings)) {

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

@ -303,7 +303,8 @@ export class PortfolioService {
public async getDetails(
aImpersonationId: string,
aUserId: string,
aDateRange: DateRange = 'max'
aDateRange: DateRange = 'max',
tags?: string[]
): Promise<PortfolioDetails & { hasErrors: boolean }> {
const userId = await this.getUserId(aImpersonationId, aUserId);
const user = await this.userService.user({ id: userId });
@ -318,6 +319,7 @@ export class PortfolioService {
const { orders, portfolioOrders, transactionPoints } =
await this.getTransactionPoints({
tags,
userId
});
@ -441,8 +443,10 @@ export class PortfolioService {
value: totalValue
});
for (const symbol of Object.keys(cashPositions)) {
holdings[symbol] = cashPositions[symbol];
if (tags === undefined) {
for (const symbol of Object.keys(cashPositions)) {
holdings[symbol] = cashPositions[symbol];
}
}
const accounts = await this.getValueOfAccounts(
@ -1178,9 +1182,11 @@ export class PortfolioService {
private async getTransactionPoints({
includeDrafts = false,
tags,
userId
}: {
includeDrafts?: boolean;
tags?: string[];
userId: string;
}): Promise<{
transactionPoints: TransactionPoint[];
@ -1191,6 +1197,7 @@ export class PortfolioService {
const orders = await this.orderService.getOrders({
includeDrafts,
tags,
userCurrency,
userId,
types: ['BUY', 'SELL']

38
apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts

@ -48,6 +48,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
{ label: 'Initial', value: 'original' },
{ label: 'Current', value: 'current' }
];
public placeholder = '';
public portfolioDetails: PortfolioDetails;
public positions: {
[symbol: string]: Pick<
@ -73,6 +74,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
value: number;
};
};
public tags = ['high-risk', 'pension'];
public user: User;
@ -120,17 +122,6 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
this.hasImpersonationId = !!aId;
});
this.dataService
.fetchPortfolioDetails({})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((portfolioDetails) => {
this.portfolioDetails = portfolioDetails;
this.initializeAnalysisData(this.period);
this.changeDetectorRef.markForCheck();
});
this.userService.stateChanged
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((state) => {
@ -142,7 +133,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
});
}
public initializeAnalysisData(aPeriod: string) {
public initialize() {
this.accounts = {};
this.continents = {
[UNKNOWN_KEY]: {
@ -185,6 +176,10 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
value: 0
}
};
}
public initializeAnalysisData(aPeriod: string) {
this.initialize();
for (const [id, { current, name, original }] of Object.entries(
this.portfolioDetails.accounts
@ -342,6 +337,25 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
}
}
public onUpdateFilters(tags: string[] = []) {
this.update(tags);
}
public update(tags?: string[]) {
this.initialize();
this.dataService
.fetchPortfolioDetails({ tags })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((portfolioDetails) => {
this.portfolioDetails = portfolioDetails;
this.initializeAnalysisData(this.period);
this.changeDetectorRef.markForCheck();
});
}
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();

5
apps/client/src/app/pages/portfolio/allocations/allocations-page.html

@ -2,6 +2,11 @@
<div class="row">
<div class="col">
<h3 class="d-flex justify-content-center mb-3" i18n>Allocations</h3>
<gf-activities-filter
[allFilters]="tags"
[placeholder]="placeholder"
(valueChanged)="onUpdateFilters($event)"
></gf-activities-filter>
</div>
</div>
<div class="proportion-charts row">

2
apps/client/src/app/pages/portfolio/allocations/allocations-page.module.ts

@ -4,6 +4,7 @@ import { MatCardModule } from '@angular/material/card';
import { GfPositionsTableModule } from '@ghostfolio/client/components/positions-table/positions-table.module';
import { GfToggleModule } from '@ghostfolio/client/components/toggle/toggle.module';
import { GfWorldMapChartModule } from '@ghostfolio/client/components/world-map-chart/world-map-chart.module';
import { GfActivitiesFilterModule } from '@ghostfolio/ui/activities-filter/activities-filter.module';
import { GfPortfolioProportionChartModule } from '@ghostfolio/ui/portfolio-proportion-chart/portfolio-proportion-chart.module';
import { GfValueModule } from '@ghostfolio/ui/value';
@ -16,6 +17,7 @@ import { AllocationsPageComponent } from './allocations-page.component';
imports: [
AllocationsPageRoutingModule,
CommonModule,
GfActivitiesFilterModule,
GfPortfolioProportionChartModule,
GfPositionsTableModule,
GfToggleModule,

10
apps/client/src/app/services/data.service.ts

@ -182,9 +182,15 @@ export class DataService {
);
}
public fetchPortfolioDetails(aParams: { [param: string]: any }) {
public fetchPortfolioDetails({ tags }: { tags?: string[] }) {
let params = new HttpParams();
if (tags?.length > 0) {
params = params.append('tags', tags.join(','));
}
return this.http.get<PortfolioDetails>('/api/v1/portfolio/details', {
params: aParams
params
});
}

Loading…
Cancel
Save