Feature/extend public page (#445)
* Extend public page * Update changelog
This commit is contained in:
parent
e7fb31d1a6
commit
1397cd62a8
@ -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,8 +2,18 @@
|
|||||||
color: rgb(var(--dark-primary-text));
|
color: rgb(var(--dark-primary-text));
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
gf-portfolio-proportion-chart {
|
.allocations-by-symbol {
|
||||||
max-width: 80vh;
|
gf-portfolio-proportion-chart {
|
||||||
|
max-width: 80vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.world-map-chart {
|
||||||
|
.mat-card {
|
||||||
|
.mat-card-content {
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,9 +318,9 @@ export class PortfolioProportionChartComponent
|
|||||||
type: 'doughnut'
|
type: 'doughnut'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isLoading = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user