Feature/extend public page (#445)

* Extend public page

* Update changelog
pull/446/head
Thomas Kaul 3 years ago committed by GitHub
parent e7fb31d1a6
commit 1397cd62a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Added more details to the public page (currencies, sectors, continents and regions)
- Added a `Dockerfile` and documentation to build a _Docker_ image - Added a `Dockerfile` and documentation to build a _Docker_ image
## 1.66.0 - 30.10.2021 ## 1.66.0 - 30.10.2021

@ -266,18 +266,27 @@ export class PortfolioController {
@Res() res: Response @Res() res: Response
): Promise<PortfolioPublicDetails> { ): Promise<PortfolioPublicDetails> {
const access = await this.accessService.access({ id: accessId }); const access = await this.accessService.access({ id: accessId });
const user = await this.userService.user({
id: access.userId
});
if (!access) { if (!access) {
res.status(StatusCodes.NOT_FOUND); res.status(StatusCodes.NOT_FOUND);
return <any>res.json({ accounts: {}, holdings: {} }); return <any>res.json({ accounts: {}, holdings: {} });
} }
let hasDetails = true;
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
hasDetails = user.subscription.type === 'Premium';
}
const { holdings } = await this.portfolioService.getDetails( const { holdings } = await this.portfolioService.getDetails(
access.userId, access.userId,
access.userId access.userId
); );
const portfolioPublicDetails: PortfolioPublicDetails = { const portfolioPublicDetails: PortfolioPublicDetails = {
hasDetails,
holdings: {} holdings: {}
}; };
@ -298,9 +307,10 @@ export class PortfolioController {
if (portfolioPosition.assetClass === 'EQUITY') { if (portfolioPosition.assetClass === 'EQUITY') {
portfolioPublicDetails.holdings[symbol] = { portfolioPublicDetails.holdings[symbol] = {
allocationCurrent: portfolioPosition.allocationCurrent, allocationCurrent: portfolioPosition.allocationCurrent,
countries: [], countries: hasDetails ? portfolioPosition.countries : [],
currency: portfolioPosition.currency,
name: portfolioPosition.name, name: portfolioPosition.name,
sectors: [], sectors: hasDetails ? portfolioPosition.sectors : [],
value: portfolioPosition.value / totalValue value: portfolioPosition.value / totalValue
}; };
} }

@ -159,9 +159,9 @@
</mat-card-header> </mat-card-header>
<mat-card-content> <mat-card-content>
<gf-portfolio-proportion-chart <gf-portfolio-proportion-chart
[keys]="['name']"
[baseCurrency]="user?.settings?.baseCurrency" [baseCurrency]="user?.settings?.baseCurrency"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView" [isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[keys]="['name']"
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[maxItems]="10" [maxItems]="10"
[positions]="countries" [positions]="countries"

@ -27,7 +27,7 @@ export class PublicPageComponent implements OnInit {
public deviceType: string; public deviceType: string;
public portfolioPublicDetails: PortfolioPublicDetails; public portfolioPublicDetails: PortfolioPublicDetails;
public positions: { public positions: {
[symbol: string]: Pick<PortfolioPosition, 'name' | 'value'>; [symbol: string]: Pick<PortfolioPosition, 'currency' | 'name' | 'value'>;
}; };
public sectors: { public sectors: {
[name: string]: { name: string; value: number }; [name: string]: { name: string; value: number };
@ -117,6 +117,7 @@ export class PublicPageComponent implements OnInit {
this.positions[symbol] = { this.positions[symbol] = {
value, value,
currency: position.currency,
name: position.name name: position.name
}; };

@ -9,6 +9,9 @@
<div class="proportion-charts row"> <div class="proportion-charts row">
<div class="col-md-12 allocations-by-symbol"> <div class="col-md-12 allocations-by-symbol">
<mat-card class="mb-3"> <mat-card class="mb-3">
<mat-card-header class="overflow-hidden w-100">
<mat-card-title class="text-truncate" i18n>Symbols</mat-card-title>
</mat-card-header>
<mat-card-content> <mat-card-content>
<gf-portfolio-proportion-chart <gf-portfolio-proportion-chart
class="mx-auto" class="mx-auto"
@ -20,6 +23,65 @@
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</div> </div>
<div *ngIf="portfolioPublicDetails?.hasDetails" class="col-md-4">
<mat-card class="mb-3">
<mat-card-header class="overflow-hidden w-100">
<mat-card-title class="text-truncate" i18n>Currencies</mat-card-title>
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
[isInPercent]="true"
[keys]="['currency']"
[maxItems]="10"
[positions]="positions"
></gf-portfolio-proportion-chart>
</mat-card-content>
</mat-card>
</div>
<div *ngIf="portfolioPublicDetails?.hasDetails" class="col-md-4">
<mat-card class="mb-3">
<mat-card-header class="overflow-hidden w-100">
<mat-card-title class="text-truncate" i18n>Sectors</mat-card-title>
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
[isInPercent]="true"
[keys]="['name']"
[maxItems]="10"
[positions]="sectors"
></gf-portfolio-proportion-chart>
</mat-card-content>
</mat-card>
</div>
<div *ngIf="portfolioPublicDetails?.hasDetails" class="col-md-4">
<mat-card class="mb-3">
<mat-card-header class="overflow-hidden w-100">
<mat-card-title class="text-truncate" i18n>Continents</mat-card-title>
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
[isInPercent]="true"
[keys]="['name']"
[positions]="continents"
></gf-portfolio-proportion-chart>
</mat-card-content>
</mat-card>
</div>
</div>
<div *ngIf="portfolioPublicDetails?.hasDetails" class="row world-map-chart">
<div class="col-lg">
<mat-card class="mb-3">
<mat-card-header class="overflow-hidden w-100">
<mat-card-title class="text-truncate" i18n>Regions</mat-card-title>
</mat-card-header>
<mat-card-content>
<gf-world-map-chart
[countries]="countries"
[isInPercent]="true"
></gf-world-map-chart>
</mat-card-content>
</mat-card>
</div>
</div> </div>
<div class="row my-5"> <div class="row my-5">
<div class="col-md-8 offset-md-2"> <div class="col-md-8 offset-md-2">

@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { GfWorldMapChartModule } from '@ghostfolio/client/components/world-map-chart/world-map-chart.module';
import { GfPortfolioProportionChartModule } from '@ghostfolio/ui/portfolio-proportion-chart/portfolio-proportion-chart.module'; import { GfPortfolioProportionChartModule } from '@ghostfolio/ui/portfolio-proportion-chart/portfolio-proportion-chart.module';
import { PublicPageRoutingModule } from './public-page-routing.module'; import { PublicPageRoutingModule } from './public-page-routing.module';
@ -13,6 +14,7 @@ import { PublicPageComponent } from './public-page.component';
imports: [ imports: [
CommonModule, CommonModule,
GfPortfolioProportionChartModule, GfPortfolioProportionChartModule,
GfWorldMapChartModule,
MatButtonModule, MatButtonModule,
MatCardModule, MatCardModule,
PublicPageRoutingModule PublicPageRoutingModule

@ -2,11 +2,21 @@
color: rgb(var(--dark-primary-text)); color: rgb(var(--dark-primary-text));
display: block; display: block;
.allocations-by-symbol {
gf-portfolio-proportion-chart { gf-portfolio-proportion-chart {
max-width: 80vh; max-width: 80vh;
} }
} }
.world-map-chart {
.mat-card {
.mat-card-content {
aspect-ratio: 16 / 9;
}
}
}
}
:host-context(.is-dark-theme) { :host-context(.is-dark-theme) {
color: rgb(var(--light-primary-text)); color: rgb(var(--light-primary-text));
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 289 KiB

@ -1,10 +1,16 @@
import { PortfolioPosition } from '@ghostfolio/common/interfaces'; import { PortfolioPosition } from '@ghostfolio/common/interfaces';
export interface PortfolioPublicDetails { export interface PortfolioPublicDetails {
hasDetails: boolean;
holdings: { holdings: {
[symbol: string]: Pick< [symbol: string]: Pick<
PortfolioPosition, PortfolioPosition,
'allocationCurrent' | 'countries' | 'name' | 'sectors' | 'value' | 'allocationCurrent'
| 'countries'
| 'currency'
| 'name'
| 'sectors'
| 'value'
>; >;
}; };
} }

@ -318,10 +318,10 @@ export class PortfolioProportionChartComponent
type: 'doughnut' type: 'doughnut'
}); });
} }
}
this.isLoading = false; this.isLoading = false;
} }
}
/** /**
* Color palette, inspired by https://yeun.github.io/open-color * Color palette, inspired by https://yeun.github.io/open-color

Loading…
Cancel
Save