Feature/add markets to public pages (#1062)
* Add Markets to public pages * Update changelog
This commit is contained in:
parent
fd2408dd62
commit
2060fcaf0b
@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- Added _Markets_ to the public pages
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Upgraded `ngx-markdown` from version `13.0.0` to `14.0.1`
|
- Upgraded `ngx-markdown` from version `13.0.0` to `14.0.1`
|
||||||
|
@ -3,8 +3,7 @@ import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interc
|
|||||||
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
||||||
import { PROPERTY_BENCHMARKS } from '@ghostfolio/common/config';
|
import { PROPERTY_BENCHMARKS } from '@ghostfolio/common/config';
|
||||||
import { BenchmarkResponse, UniqueAsset } from '@ghostfolio/common/interfaces';
|
import { BenchmarkResponse, UniqueAsset } from '@ghostfolio/common/interfaces';
|
||||||
import { Controller, Get, UseGuards, UseInterceptors } from '@nestjs/common';
|
import { Controller, Get, UseInterceptors } from '@nestjs/common';
|
||||||
import { AuthGuard } from '@nestjs/passport';
|
|
||||||
|
|
||||||
import { BenchmarkService } from './benchmark.service';
|
import { BenchmarkService } from './benchmark.service';
|
||||||
|
|
||||||
@ -16,7 +15,6 @@ export class BenchmarkController {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@UseGuards(AuthGuard('jwt'))
|
|
||||||
@UseInterceptors(TransformDataSourceInRequestInterceptor)
|
@UseInterceptors(TransformDataSourceInRequestInterceptor)
|
||||||
@UseInterceptors(TransformDataSourceInResponseInterceptor)
|
@UseInterceptors(TransformDataSourceInResponseInterceptor)
|
||||||
public async getBenchmark(): Promise<BenchmarkResponse> {
|
public async getBenchmark(): Promise<BenchmarkResponse> {
|
||||||
|
@ -63,6 +63,8 @@ export class InfoService {
|
|||||||
} else {
|
} else {
|
||||||
info.fearAndGreedDataSource = ghostfolioFearAndGreedIndexDataSource;
|
info.fearAndGreedDataSource = ghostfolioFearAndGreedIndexDataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
globalPermissions.push(permissions.enableFearAndGreedIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.configurationService.get('ENABLE_FEATURE_IMPORT')) {
|
if (this.configurationService.get('ENABLE_FEATURE_IMPORT')) {
|
||||||
|
@ -46,7 +46,6 @@ export class SymbolController {
|
|||||||
* Must be after /lookup
|
* Must be after /lookup
|
||||||
*/
|
*/
|
||||||
@Get(':dataSource/:symbol')
|
@Get(':dataSource/:symbol')
|
||||||
@UseGuards(AuthGuard('jwt'))
|
|
||||||
@UseInterceptors(TransformDataSourceInRequestInterceptor)
|
@UseInterceptors(TransformDataSourceInRequestInterceptor)
|
||||||
@UseInterceptors(TransformDataSourceInResponseInterceptor)
|
@UseInterceptors(TransformDataSourceInResponseInterceptor)
|
||||||
public async getSymbolData(
|
public async getSymbolData(
|
||||||
|
@ -158,10 +158,6 @@ export class UserService {
|
|||||||
|
|
||||||
let currentPermissions = getPermissions(user.role);
|
let currentPermissions = getPermissions(user.role);
|
||||||
|
|
||||||
if (this.configurationService.get('ENABLE_FEATURE_FEAR_AND_GREED_INDEX')) {
|
|
||||||
currentPermissions.push(permissions.accessFearAndGreedIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.subscription?.type === 'Premium') {
|
if (user.subscription?.type === 'Premium') {
|
||||||
currentPermissions.push(permissions.reportDataGlitch);
|
currentPermissions.push(permissions.reportDataGlitch);
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,13 @@ const routes: Routes = [
|
|||||||
loadChildren: () =>
|
loadChildren: () =>
|
||||||
import('./pages/home/home-page.module').then((m) => m.HomePageModule)
|
import('./pages/home/home-page.module').then((m) => m.HomePageModule)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'markets',
|
||||||
|
loadChildren: () =>
|
||||||
|
import('./pages/markets/markets-page.module').then(
|
||||||
|
(m) => m.MarketsPageModule
|
||||||
|
)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'p',
|
path: 'p',
|
||||||
loadChildren: () =>
|
loadChildren: () =>
|
||||||
|
@ -269,6 +269,18 @@
|
|||||||
[routerLink]="['/pricing']"
|
[routerLink]="['/pricing']"
|
||||||
>Pricing</a
|
>Pricing</a
|
||||||
>
|
>
|
||||||
|
<a
|
||||||
|
*ngIf="hasPermissionToAccessFearAndGreedIndex"
|
||||||
|
class="d-none d-sm-block mx-1"
|
||||||
|
i18n
|
||||||
|
mat-flat-button
|
||||||
|
[ngClass]="{
|
||||||
|
'font-weight-bold': currentRoute === 'markets',
|
||||||
|
'text-decoration-underline': currentRoute === 'markets'
|
||||||
|
}"
|
||||||
|
[routerLink]="['/markets']"
|
||||||
|
>Markets</a
|
||||||
|
>
|
||||||
<a
|
<a
|
||||||
class="d-none d-sm-block mx-1 no-min-width px-1"
|
class="d-none d-sm-block mx-1 no-min-width px-1"
|
||||||
href="https://github.com/ghostfolio/ghostfolio"
|
href="https://github.com/ghostfolio/ghostfolio"
|
||||||
|
@ -37,6 +37,7 @@ export class HeaderComponent implements OnChanges {
|
|||||||
public hasPermissionForSocialLogin: boolean;
|
public hasPermissionForSocialLogin: boolean;
|
||||||
public hasPermissionForSubscription: boolean;
|
public hasPermissionForSubscription: boolean;
|
||||||
public hasPermissionToAccessAdminControl: boolean;
|
public hasPermissionToAccessAdminControl: boolean;
|
||||||
|
public hasPermissionToAccessFearAndGreedIndex: boolean;
|
||||||
public impersonationId: string;
|
public impersonationId: string;
|
||||||
public isMenuOpen: boolean;
|
public isMenuOpen: boolean;
|
||||||
|
|
||||||
@ -73,6 +74,11 @@ export class HeaderComponent implements OnChanges {
|
|||||||
this.user?.permissions,
|
this.user?.permissions,
|
||||||
permissions.accessAdminControl
|
permissions.accessAdminControl
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.hasPermissionToAccessFearAndGreedIndex = hasPermission(
|
||||||
|
this.info?.globalPermissions,
|
||||||
|
permissions.enableFearAndGreedIndex
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public impersonateAccount(aId: string) {
|
public impersonateAccount(aId: string) {
|
||||||
|
@ -44,49 +44,49 @@ export class HomeMarketComponent implements OnDestroy, OnInit {
|
|||||||
if (state?.user) {
|
if (state?.user) {
|
||||||
this.user = state.user;
|
this.user = state.user;
|
||||||
|
|
||||||
this.hasPermissionToAccessFearAndGreedIndex = hasPermission(
|
|
||||||
this.user.permissions,
|
|
||||||
permissions.accessFearAndGreedIndex
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.hasPermissionToAccessFearAndGreedIndex) {
|
|
||||||
this.dataService
|
|
||||||
.fetchSymbolItem({
|
|
||||||
dataSource: this.info.fearAndGreedDataSource,
|
|
||||||
includeHistoricalData: this.numberOfDays,
|
|
||||||
symbol: ghostfolioFearAndGreedIndexSymbol
|
|
||||||
})
|
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
|
||||||
.subscribe(({ historicalData, marketPrice }) => {
|
|
||||||
this.fearAndGreedIndex = marketPrice;
|
|
||||||
this.historicalData = [
|
|
||||||
...historicalData,
|
|
||||||
{
|
|
||||||
date: resetHours(new Date()).toISOString(),
|
|
||||||
value: marketPrice
|
|
||||||
}
|
|
||||||
];
|
|
||||||
this.isLoading = false;
|
|
||||||
|
|
||||||
this.changeDetectorRef.markForCheck();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dataService
|
|
||||||
.fetchBenchmarks()
|
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
|
||||||
.subscribe(({ benchmarks }) => {
|
|
||||||
this.benchmarks = benchmarks;
|
|
||||||
|
|
||||||
this.changeDetectorRef.markForCheck();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.changeDetectorRef.markForCheck();
|
this.changeDetectorRef.markForCheck();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit() {}
|
public ngOnInit() {
|
||||||
|
this.hasPermissionToAccessFearAndGreedIndex = hasPermission(
|
||||||
|
this.info?.globalPermissions,
|
||||||
|
permissions.enableFearAndGreedIndex
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.hasPermissionToAccessFearAndGreedIndex) {
|
||||||
|
this.dataService
|
||||||
|
.fetchSymbolItem({
|
||||||
|
dataSource: this.info.fearAndGreedDataSource,
|
||||||
|
includeHistoricalData: this.numberOfDays,
|
||||||
|
symbol: ghostfolioFearAndGreedIndexSymbol
|
||||||
|
})
|
||||||
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
|
.subscribe(({ historicalData, marketPrice }) => {
|
||||||
|
this.fearAndGreedIndex = marketPrice;
|
||||||
|
this.historicalData = [
|
||||||
|
...historicalData,
|
||||||
|
{
|
||||||
|
date: resetHours(new Date()).toISOString(),
|
||||||
|
value: marketPrice
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dataService
|
||||||
|
.fetchBenchmarks()
|
||||||
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
|
.subscribe(({ benchmarks }) => {
|
||||||
|
this.benchmarks = benchmarks;
|
||||||
|
this.isLoading = false;
|
||||||
|
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public ngOnDestroy() {
|
public ngOnDestroy() {
|
||||||
this.unsubscribeSubject.next();
|
this.unsubscribeSubject.next();
|
||||||
|
@ -28,16 +28,17 @@
|
|||||||
<div class="mb-3 row">
|
<div class="mb-3 row">
|
||||||
<div class="col-xs-12 col-md-8 offset-md-2">
|
<div class="col-xs-12 col-md-8 offset-md-2">
|
||||||
<gf-benchmark
|
<gf-benchmark
|
||||||
*ngFor="let benchmark of benchmarks"
|
[benchmarks]="benchmarks"
|
||||||
class="py-2"
|
|
||||||
[benchmark]="benchmark"
|
|
||||||
[locale]="user?.settings?.locale"
|
[locale]="user?.settings?.locale"
|
||||||
></gf-benchmark>
|
></gf-benchmark>
|
||||||
<gf-benchmark
|
<ngx-skeleton-loader
|
||||||
*ngIf="!benchmarks"
|
*ngIf="isLoading"
|
||||||
class="py-2"
|
animation="pulse"
|
||||||
[benchmark]="undefined"
|
[theme]="{
|
||||||
></gf-benchmark>
|
height: '1.5rem',
|
||||||
|
width: '100%'
|
||||||
|
}"
|
||||||
|
></ngx-skeleton-loader>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,19 +3,20 @@ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
|||||||
import { GfFearAndGreedIndexModule } from '@ghostfolio/client/components/fear-and-greed-index/fear-and-greed-index.module';
|
import { GfFearAndGreedIndexModule } from '@ghostfolio/client/components/fear-and-greed-index/fear-and-greed-index.module';
|
||||||
import { GfBenchmarkModule } from '@ghostfolio/ui/benchmark/benchmark.module';
|
import { GfBenchmarkModule } from '@ghostfolio/ui/benchmark/benchmark.module';
|
||||||
import { GfLineChartModule } from '@ghostfolio/ui/line-chart/line-chart.module';
|
import { GfLineChartModule } from '@ghostfolio/ui/line-chart/line-chart.module';
|
||||||
|
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||||
|
|
||||||
import { HomeMarketComponent } from './home-market.component';
|
import { HomeMarketComponent } from './home-market.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [HomeMarketComponent],
|
declarations: [HomeMarketComponent],
|
||||||
exports: [],
|
exports: [HomeMarketComponent],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
GfBenchmarkModule,
|
GfBenchmarkModule,
|
||||||
GfFearAndGreedIndexModule,
|
GfFearAndGreedIndexModule,
|
||||||
GfLineChartModule
|
GfLineChartModule,
|
||||||
|
NgxSkeletonLoaderModule
|
||||||
],
|
],
|
||||||
providers: [],
|
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
})
|
})
|
||||||
export class GfHomeMarketModule {}
|
export class GfHomeMarketModule {}
|
||||||
|
@ -22,6 +22,7 @@ export class AuthGuard implements CanActivate {
|
|||||||
'/demo',
|
'/demo',
|
||||||
'/en/blog',
|
'/en/blog',
|
||||||
'/features',
|
'/features',
|
||||||
|
'/markets',
|
||||||
'/p',
|
'/p',
|
||||||
'/pricing',
|
'/pricing',
|
||||||
'/register',
|
'/register',
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||||
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
||||||
import { User } from '@ghostfolio/common/interfaces';
|
import { InfoItem, User } from '@ghostfolio/common/interfaces';
|
||||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
@ -24,6 +24,7 @@ export class HomePageComponent implements OnDestroy, OnInit {
|
|||||||
|
|
||||||
public hasMessage: boolean;
|
public hasMessage: boolean;
|
||||||
public hasPermissionToAccessFearAndGreedIndex: boolean;
|
public hasPermissionToAccessFearAndGreedIndex: boolean;
|
||||||
|
public info: InfoItem;
|
||||||
public tabs: { iconName: string; path: string }[] = [];
|
public tabs: { iconName: string; path: string }[] = [];
|
||||||
public user: User;
|
public user: User;
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ export class HomePageComponent implements OnDestroy, OnInit {
|
|||||||
private dataService: DataService,
|
private dataService: DataService,
|
||||||
private userService: UserService
|
private userService: UserService
|
||||||
) {
|
) {
|
||||||
const { systemMessage } = this.dataService.fetchInfo();
|
this.info = this.dataService.fetchInfo();
|
||||||
|
|
||||||
this.userService.stateChanged
|
this.userService.stateChanged
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
@ -51,11 +52,11 @@ export class HomePageComponent implements OnDestroy, OnInit {
|
|||||||
hasPermission(
|
hasPermission(
|
||||||
this.user?.permissions,
|
this.user?.permissions,
|
||||||
permissions.createUserAccount
|
permissions.createUserAccount
|
||||||
) || !!systemMessage;
|
) || !!this.info.systemMessage;
|
||||||
|
|
||||||
this.hasPermissionToAccessFearAndGreedIndex = hasPermission(
|
this.hasPermissionToAccessFearAndGreedIndex = hasPermission(
|
||||||
this.user.permissions,
|
this.info?.globalPermissions,
|
||||||
permissions.accessFearAndGreedIndex
|
permissions.enableFearAndGreedIndex
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.hasPermissionToAccessFearAndGreedIndex) {
|
if (this.hasPermissionToAccessFearAndGreedIndex) {
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
|
||||||
|
|
||||||
|
import { MarketsPageComponent } from './markets-page.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: '', component: MarketsPageComponent, canActivate: [AuthGuard] }
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class MarketsPageRoutingModule {}
|
21
apps/client/src/app/pages/markets/markets-page.component.ts
Normal file
21
apps/client/src/app/pages/markets/markets-page.component.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
host: { class: 'page' },
|
||||||
|
selector: 'gf-markets-page',
|
||||||
|
styleUrls: ['./markets-page.scss'],
|
||||||
|
templateUrl: './markets-page.html'
|
||||||
|
})
|
||||||
|
export class MarketsPageComponent implements OnDestroy, OnInit {
|
||||||
|
private unsubscribeSubject = new Subject<void>();
|
||||||
|
|
||||||
|
public constructor() {}
|
||||||
|
|
||||||
|
public ngOnInit() {}
|
||||||
|
|
||||||
|
public ngOnDestroy() {
|
||||||
|
this.unsubscribeSubject.next();
|
||||||
|
this.unsubscribeSubject.complete();
|
||||||
|
}
|
||||||
|
}
|
7
apps/client/src/app/pages/markets/markets-page.html
Normal file
7
apps/client/src/app/pages/markets/markets-page.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<gf-home-market></gf-home-market>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
13
apps/client/src/app/pages/markets/markets-page.module.ts
Normal file
13
apps/client/src/app/pages/markets/markets-page.module.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||||
|
import { GfHomeMarketModule } from '@ghostfolio/client/components/home-market/home-market.module';
|
||||||
|
|
||||||
|
import { MarketsPageRoutingModule } from './markets-page-routing.module';
|
||||||
|
import { MarketsPageComponent } from './markets-page.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [MarketsPageComponent],
|
||||||
|
imports: [CommonModule, GfHomeMarketModule, MarketsPageRoutingModule],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
})
|
||||||
|
export class MarketsPageModule {}
|
3
apps/client/src/app/pages/markets/markets-page.scss
Normal file
3
apps/client/src/app/pages/markets/markets-page.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
@ -40,6 +40,10 @@
|
|||||||
<loc>https://ghostfol.io/features</loc>
|
<loc>https://ghostfol.io/features</loc>
|
||||||
<lastmod>2022-07-01T00:00:00+00:00</lastmod>
|
<lastmod>2022-07-01T00:00:00+00:00</lastmod>
|
||||||
</url>
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://ghostfol.io/markets</loc>
|
||||||
|
<lastmod>2022-07-01T00:00:00+00:00</lastmod>
|
||||||
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://ghostfol.io/pricing</loc>
|
<loc>https://ghostfol.io/pricing</loc>
|
||||||
<lastmod>2022-07-01T00:00:00+00:00</lastmod>
|
<lastmod>2022-07-01T00:00:00+00:00</lastmod>
|
||||||
|
@ -4,7 +4,6 @@ import { UserWithSettings } from './interfaces';
|
|||||||
|
|
||||||
export const permissions = {
|
export const permissions = {
|
||||||
accessAdminControl: 'accessAdminControl',
|
accessAdminControl: 'accessAdminControl',
|
||||||
accessFearAndGreedIndex: 'accessFearAndGreedIndex',
|
|
||||||
createAccess: 'createAccess',
|
createAccess: 'createAccess',
|
||||||
createAccount: 'createAccount',
|
createAccount: 'createAccount',
|
||||||
createOrder: 'createOrder',
|
createOrder: 'createOrder',
|
||||||
@ -14,6 +13,7 @@ export const permissions = {
|
|||||||
deleteAuthDevice: 'deleteAuthDevice',
|
deleteAuthDevice: 'deleteAuthDevice',
|
||||||
deleteOrder: 'deleteOrder',
|
deleteOrder: 'deleteOrder',
|
||||||
deleteUser: 'deleteUser',
|
deleteUser: 'deleteUser',
|
||||||
|
enableFearAndGreedIndex: 'enableFearAndGreedIndex',
|
||||||
enableImport: 'enableImport',
|
enableImport: 'enableImport',
|
||||||
enableBlog: 'enableBlog',
|
enableBlog: 'enableBlog',
|
||||||
enableSocialLogin: 'enableSocialLogin',
|
enableSocialLogin: 'enableSocialLogin',
|
||||||
|
@ -1,49 +1,50 @@
|
|||||||
<div class="align-items-center d-flex">
|
<table class="gf-table w-100">
|
||||||
<div *ngIf="benchmark?.name" class="flex-grow-1 text-truncate">
|
<thead>
|
||||||
{{ benchmark.name }}
|
<tr class="mat-header-row">
|
||||||
</div>
|
<th class="mat-header-cell px-1 py-2" i18n>Index</th>
|
||||||
<div *ngIf="!benchmark?.name" class="flex-grow-1">
|
<th class="mat-header-cell px-1 py-2 text-right">
|
||||||
<ngx-skeleton-loader
|
<span class="d-none d-sm-block text-nowrap" i18n
|
||||||
animation="pulse"
|
>Change from All Time High</span
|
||||||
[theme]="{
|
>
|
||||||
width: '67%'
|
<span class="d-block d-sm-none text-nowrap" i18n>from ATH</span>
|
||||||
}"
|
</th>
|
||||||
></ngx-skeleton-loader>
|
<th class="mat-header-cell px-1 py-2 text-right" i18n></th>
|
||||||
</div>
|
</tr>
|
||||||
<gf-value
|
</thead>
|
||||||
class="mx-2"
|
<tbody>
|
||||||
size="medium"
|
<tr *ngFor="let benchmark of benchmarks" class="mat-row">
|
||||||
[isPercent]="true"
|
<td class="mat-cell px-1 py-2">
|
||||||
[locale]="locale"
|
<div class="d-flex align-items-center">
|
||||||
[ngClass]="{
|
{{ benchmark.name }}
|
||||||
'text-danger':
|
</div>
|
||||||
benchmark?.performances?.allTimeHigh?.performancePercent < 0,
|
</td>
|
||||||
'text-success':
|
<td class="mat-cell px-1 py-2 text-right">
|
||||||
benchmark?.performances?.allTimeHigh?.performancePercent > 0
|
<gf-value
|
||||||
}"
|
class="d-inline-block justify-content-end"
|
||||||
[value]="
|
size="medium"
|
||||||
benchmark?.performances?.allTimeHigh?.performancePercent ?? undefined
|
[isPercent]="true"
|
||||||
"
|
[locale]="locale"
|
||||||
></gf-value>
|
[ngClass]="{
|
||||||
<div class="text-muted">
|
'text-danger':
|
||||||
<small class="d-none d-sm-block text-nowrap" i18n>from All Time High</small
|
benchmark?.performances?.allTimeHigh?.performancePercent < 0,
|
||||||
><small class="d-block d-sm-none text-nowrap" i18n>from ATH</small>
|
'text-success':
|
||||||
</div>
|
benchmark?.performances?.allTimeHigh?.performancePercent > 0
|
||||||
<div class="ml-2">
|
}"
|
||||||
<div
|
[value]="
|
||||||
*ngIf="benchmark?.marketCondition"
|
benchmark?.performances?.allTimeHigh?.performancePercent ??
|
||||||
[title]="benchmark?.marketCondition"
|
undefined
|
||||||
>
|
"
|
||||||
{{ resolveMarketCondition(benchmark.marketCondition).emoji }}
|
></gf-value>
|
||||||
</div>
|
</td>
|
||||||
<ngx-skeleton-loader
|
<td class="mat-cell px-1 py-2">
|
||||||
*ngIf="!benchmark?.marketCondition"
|
<div
|
||||||
animation="pulse"
|
*ngIf="benchmark?.marketCondition"
|
||||||
appearance="circle"
|
class="text-center"
|
||||||
[theme]="{
|
[title]="benchmark?.marketCondition"
|
||||||
height: '1rem',
|
>
|
||||||
width: '1rem'
|
{{ resolveMarketCondition(benchmark.marketCondition).emoji }}
|
||||||
}"
|
</div>
|
||||||
></ngx-skeleton-loader>
|
</td>
|
||||||
</div>
|
</tr>
|
||||||
</div>
|
</tbody>
|
||||||
|
</table>
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
OnChanges
|
||||||
|
} from '@angular/core';
|
||||||
|
import { locale } from '@ghostfolio/common/config';
|
||||||
import { resolveMarketCondition } from '@ghostfolio/common/helper';
|
import { resolveMarketCondition } from '@ghostfolio/common/helper';
|
||||||
import { Benchmark } from '@ghostfolio/common/interfaces';
|
import { Benchmark } from '@ghostfolio/common/interfaces';
|
||||||
|
|
||||||
@ -8,11 +14,17 @@ import { Benchmark } from '@ghostfolio/common/interfaces';
|
|||||||
templateUrl: './benchmark.component.html',
|
templateUrl: './benchmark.component.html',
|
||||||
styleUrls: ['./benchmark.component.scss']
|
styleUrls: ['./benchmark.component.scss']
|
||||||
})
|
})
|
||||||
export class BenchmarkComponent {
|
export class BenchmarkComponent implements OnChanges {
|
||||||
@Input() benchmark: Benchmark;
|
@Input() benchmarks: Benchmark[];
|
||||||
@Input() locale: string;
|
@Input() locale: string;
|
||||||
|
|
||||||
public resolveMarketCondition = resolveMarketCondition;
|
public resolveMarketCondition = resolveMarketCondition;
|
||||||
|
|
||||||
public constructor() {}
|
public constructor() {}
|
||||||
|
|
||||||
|
public ngOnChanges() {
|
||||||
|
if (!this.locale) {
|
||||||
|
this.locale = locale;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,11 @@ import {
|
|||||||
getTooltipPositionerMapTop,
|
getTooltipPositionerMapTop,
|
||||||
getVerticalHoverLinePlugin
|
getVerticalHoverLinePlugin
|
||||||
} from '@ghostfolio/common/chart-helper';
|
} from '@ghostfolio/common/chart-helper';
|
||||||
import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config';
|
import {
|
||||||
|
locale,
|
||||||
|
primaryColorRgb,
|
||||||
|
secondaryColorRgb
|
||||||
|
} from '@ghostfolio/common/config';
|
||||||
import {
|
import {
|
||||||
getBackgroundColor,
|
getBackgroundColor,
|
||||||
getDateFormatString,
|
getDateFormatString,
|
||||||
@ -97,6 +101,10 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
|
|||||||
this.changeDetectorRef.markForCheck();
|
this.changeDetectorRef.markForCheck();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.locale) {
|
||||||
|
this.locale = locale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnDestroy() {
|
public ngOnDestroy() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user