mirror of https://github.com/ghostfolio/ghostfolio
Thomas Kaul
3 years ago
committed by
GitHub
27 changed files with 739 additions and 705 deletions
@ -0,0 +1,84 @@ |
|||
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; |
|||
import { DataService } from '@ghostfolio/client/services/data.service'; |
|||
import { |
|||
RANGE, |
|||
SettingsStorageService |
|||
} from '@ghostfolio/client/services/settings-storage.service'; |
|||
import { UserService } from '@ghostfolio/client/services/user/user.service'; |
|||
import { Position, User } from '@ghostfolio/common/interfaces'; |
|||
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; |
|||
import { DateRange } from '@ghostfolio/common/types'; |
|||
import { DeviceDetectorService } from 'ngx-device-detector'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
|
|||
@Component({ |
|||
selector: 'gf-home-holdings', |
|||
styleUrls: ['./home-holdings.scss'], |
|||
templateUrl: './home-holdings.html' |
|||
}) |
|||
export class HomeHoldingsComponent implements OnDestroy, OnInit { |
|||
public dateRange: DateRange; |
|||
public deviceType: string; |
|||
public hasPermissionToCreateOrder: boolean; |
|||
public positions: Position[]; |
|||
public user: User; |
|||
|
|||
private unsubscribeSubject = new Subject<void>(); |
|||
|
|||
/** |
|||
* @constructor |
|||
*/ |
|||
public constructor( |
|||
private changeDetectorRef: ChangeDetectorRef, |
|||
private dataService: DataService, |
|||
private deviceService: DeviceDetectorService, |
|||
private settingsStorageService: SettingsStorageService, |
|||
private userService: UserService |
|||
) { |
|||
this.userService.stateChanged |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((state) => { |
|||
if (state?.user) { |
|||
this.user = state.user; |
|||
|
|||
this.hasPermissionToCreateOrder = hasPermission( |
|||
this.user.permissions, |
|||
permissions.createOrder |
|||
); |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Initializes the controller |
|||
*/ |
|||
public ngOnInit() { |
|||
this.deviceType = this.deviceService.getDeviceInfo().deviceType; |
|||
|
|||
this.dateRange = |
|||
<DateRange>this.settingsStorageService.getSetting(RANGE) || 'max'; |
|||
|
|||
this.update(); |
|||
} |
|||
|
|||
public ngOnDestroy() { |
|||
this.unsubscribeSubject.next(); |
|||
this.unsubscribeSubject.complete(); |
|||
} |
|||
|
|||
private update() { |
|||
this.dataService |
|||
.fetchPositions({ range: this.dateRange }) |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((response) => { |
|||
this.positions = response.positions; |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
}); |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
} |
|||
} |
@ -0,0 +1,26 @@ |
|||
<div class="container justify-content-center pb-3 px-3"> |
|||
<div class="row"> |
|||
<div class="align-items-center col-xs-12 col-md-8 offset-md-2"> |
|||
<mat-card class="p-0"> |
|||
<mat-card-content> |
|||
<gf-positions |
|||
[baseCurrency]="user?.settings?.baseCurrency" |
|||
[deviceType]="deviceType" |
|||
[locale]="user?.settings?.locale" |
|||
[positions]="positions" |
|||
[range]="dateRange" |
|||
></gf-positions> |
|||
</mat-card-content> |
|||
</mat-card> |
|||
<div *ngIf="hasPermissionToCreateOrder" class="text-center"> |
|||
<a |
|||
class="mt-3" |
|||
i18n |
|||
mat-button |
|||
[routerLink]="['/portfolio', 'transactions']" |
|||
>Manage Transactions...</a |
|||
> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
@ -0,0 +1,23 @@ |
|||
import { CommonModule } from '@angular/common'; |
|||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; |
|||
import { MatButtonModule } from '@angular/material/button'; |
|||
import { MatCardModule } from '@angular/material/card'; |
|||
import { RouterModule } from '@angular/router'; |
|||
import { GfPositionsModule } from '@ghostfolio/client/components/positions/positions.module'; |
|||
|
|||
import { HomeHoldingsComponent } from './home-holdings.component'; |
|||
|
|||
@NgModule({ |
|||
declarations: [HomeHoldingsComponent], |
|||
exports: [], |
|||
imports: [ |
|||
CommonModule, |
|||
GfPositionsModule, |
|||
MatButtonModule, |
|||
MatCardModule, |
|||
RouterModule |
|||
], |
|||
providers: [], |
|||
schemas: [CUSTOM_ELEMENTS_SCHEMA] |
|||
}) |
|||
export class GfHomeHoldingsModule {} |
@ -0,0 +1,5 @@ |
|||
@import '~apps/client/src/styles/ghostfolio-style'; |
|||
|
|||
:host { |
|||
display: block; |
|||
} |
@ -0,0 +1,74 @@ |
|||
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; |
|||
import { DataService } from '@ghostfolio/client/services/data.service'; |
|||
import { UserService } from '@ghostfolio/client/services/user/user.service'; |
|||
import { ghostfolioFearAndGreedIndexSymbol } from '@ghostfolio/common/config'; |
|||
import { User } from '@ghostfolio/common/interfaces'; |
|||
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; |
|||
import { DataSource } from '@prisma/client'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
|
|||
@Component({ |
|||
selector: 'gf-home-market', |
|||
styleUrls: ['./home-market.scss'], |
|||
templateUrl: './home-market.html' |
|||
}) |
|||
export class HomeMarketComponent implements OnDestroy, OnInit { |
|||
public fearAndGreedIndex: number; |
|||
public hasPermissionToAccessFearAndGreedIndex: boolean; |
|||
public isLoading = true; |
|||
public user: User; |
|||
|
|||
private unsubscribeSubject = new Subject<void>(); |
|||
|
|||
/** |
|||
* @constructor |
|||
*/ |
|||
public constructor( |
|||
private changeDetectorRef: ChangeDetectorRef, |
|||
private dataService: DataService, |
|||
private userService: UserService |
|||
) { |
|||
this.isLoading = true; |
|||
|
|||
this.userService.stateChanged |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((state) => { |
|||
if (state?.user) { |
|||
this.user = state.user; |
|||
|
|||
this.hasPermissionToAccessFearAndGreedIndex = hasPermission( |
|||
this.user.permissions, |
|||
permissions.accessFearAndGreedIndex |
|||
); |
|||
|
|||
if (this.hasPermissionToAccessFearAndGreedIndex) { |
|||
this.dataService |
|||
.fetchSymbolItem({ |
|||
dataSource: DataSource.RAKUTEN, |
|||
symbol: ghostfolioFearAndGreedIndexSymbol |
|||
}) |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe(({ marketPrice }) => { |
|||
this.fearAndGreedIndex = marketPrice; |
|||
this.isLoading = false; |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
}); |
|||
} |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Initializes the controller |
|||
*/ |
|||
public ngOnInit() {} |
|||
|
|||
public ngOnDestroy() { |
|||
this.unsubscribeSubject.next(); |
|||
this.unsubscribeSubject.complete(); |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
<div |
|||
class=" |
|||
align-items-center |
|||
container |
|||
d-flex |
|||
flex-grow-1 |
|||
h-100 |
|||
justify-content-center |
|||
w-100 |
|||
" |
|||
> |
|||
<div class="row w-100"> |
|||
<div class="col-xs-12 col-md-8 offset-md-2"> |
|||
<mat-card class="h-100"> |
|||
<mat-card-content> |
|||
<gf-fear-and-greed-index |
|||
class="d-flex justify-content-center" |
|||
[fearAndGreedIndex]="fearAndGreedIndex" |
|||
[hidden]="isLoading" |
|||
></gf-fear-and-greed-index> |
|||
</mat-card-content> |
|||
</mat-card> |
|||
</div> |
|||
</div> |
|||
</div> |
@ -0,0 +1,15 @@ |
|||
import { CommonModule } from '@angular/common'; |
|||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; |
|||
import { MatCardModule } from '@angular/material/card'; |
|||
import { GfFearAndGreedIndexModule } from '@ghostfolio/client/components/fear-and-greed-index/fear-and-greed-index.module'; |
|||
|
|||
import { HomeMarketComponent } from './home-market.component'; |
|||
|
|||
@NgModule({ |
|||
declarations: [HomeMarketComponent], |
|||
exports: [], |
|||
imports: [CommonModule, GfFearAndGreedIndexModule, MatCardModule], |
|||
providers: [], |
|||
schemas: [CUSTOM_ELEMENTS_SCHEMA] |
|||
}) |
|||
export class GfHomeMarketModule {} |
@ -0,0 +1,5 @@ |
|||
@import '~apps/client/src/styles/ghostfolio-style'; |
|||
|
|||
:host { |
|||
display: block; |
|||
} |
@ -0,0 +1,122 @@ |
|||
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; |
|||
import { ToggleOption } from '@ghostfolio/client/components/toggle/interfaces/toggle-option.type'; |
|||
import { DataService } from '@ghostfolio/client/services/data.service'; |
|||
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; |
|||
import { |
|||
RANGE, |
|||
SettingsStorageService |
|||
} from '@ghostfolio/client/services/settings-storage.service'; |
|||
import { UserService } from '@ghostfolio/client/services/user/user.service'; |
|||
import { PortfolioPerformance, User } from '@ghostfolio/common/interfaces'; |
|||
import { DateRange } from '@ghostfolio/common/types'; |
|||
import { LineChartItem } from '@ghostfolio/ui/line-chart/interfaces/line-chart.interface'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
|
|||
@Component({ |
|||
selector: 'gf-home-overview', |
|||
styleUrls: ['./home-overview.scss'], |
|||
templateUrl: './home-overview.html' |
|||
}) |
|||
export class HomeOverviewComponent implements OnDestroy, OnInit { |
|||
public dateRange: DateRange; |
|||
public dateRangeOptions: ToggleOption[] = [ |
|||
{ label: 'Today', value: '1d' }, |
|||
{ label: 'YTD', value: 'ytd' }, |
|||
{ label: '1Y', value: '1y' }, |
|||
{ label: '5Y', value: '5y' }, |
|||
{ label: 'Max', value: 'max' } |
|||
]; |
|||
public hasImpersonationId: boolean; |
|||
public historicalDataItems: LineChartItem[]; |
|||
public isAllTimeHigh: boolean; |
|||
public isAllTimeLow: boolean; |
|||
public isLoadingPerformance = true; |
|||
public performance: PortfolioPerformance; |
|||
public user: User; |
|||
|
|||
private unsubscribeSubject = new Subject<void>(); |
|||
|
|||
/** |
|||
* @constructor |
|||
*/ |
|||
public constructor( |
|||
private changeDetectorRef: ChangeDetectorRef, |
|||
private dataService: DataService, |
|||
private impersonationStorageService: ImpersonationStorageService, |
|||
private settingsStorageService: SettingsStorageService, |
|||
private userService: UserService |
|||
) { |
|||
this.userService.stateChanged |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((state) => { |
|||
if (state?.user) { |
|||
this.user = state.user; |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Initializes the controller |
|||
*/ |
|||
public ngOnInit() { |
|||
this.impersonationStorageService |
|||
.onChangeHasImpersonation() |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((aId) => { |
|||
this.hasImpersonationId = !!aId; |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
}); |
|||
|
|||
this.dateRange = |
|||
<DateRange>this.settingsStorageService.getSetting(RANGE) || 'max'; |
|||
|
|||
this.update(); |
|||
} |
|||
|
|||
public onChangeDateRange(aDateRange: DateRange) { |
|||
this.dateRange = aDateRange; |
|||
this.settingsStorageService.setSetting(RANGE, this.dateRange); |
|||
this.update(); |
|||
} |
|||
|
|||
public ngOnDestroy() { |
|||
this.unsubscribeSubject.next(); |
|||
this.unsubscribeSubject.complete(); |
|||
} |
|||
|
|||
private update() { |
|||
this.isLoadingPerformance = true; |
|||
|
|||
this.dataService |
|||
.fetchChart({ range: this.dateRange }) |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((chartData) => { |
|||
this.historicalDataItems = chartData.chart.map((chartDataItem) => { |
|||
return { |
|||
date: chartDataItem.date, |
|||
value: chartDataItem.value |
|||
}; |
|||
}); |
|||
this.isAllTimeHigh = chartData.isAllTimeHigh; |
|||
this.isAllTimeLow = chartData.isAllTimeLow; |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
}); |
|||
|
|||
this.dataService |
|||
.fetchPortfolioPerformance({ range: this.dateRange }) |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((response) => { |
|||
this.performance = response; |
|||
this.isLoadingPerformance = false; |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
}); |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
} |
|||
} |
@ -0,0 +1,55 @@ |
|||
<div |
|||
class=" |
|||
align-items-center |
|||
container |
|||
d-flex |
|||
flex-column |
|||
h-100 |
|||
justify-content-center |
|||
overview |
|||
position-relative |
|||
" |
|||
> |
|||
<div class="row w-100"> |
|||
<div class="chart-container col"> |
|||
<gf-line-chart |
|||
symbol="Performance" |
|||
[historicalDataItems]="historicalDataItems" |
|||
[showGradient]="true" |
|||
[showLoader]="false" |
|||
[showXAxis]="false" |
|||
[showYAxis]="false" |
|||
></gf-line-chart> |
|||
<div |
|||
*ngIf="historicalDataItems?.length === 0" |
|||
class="align-items-center d-flex h-100 justify-content-center w-100" |
|||
> |
|||
<div class="d-flex justify-content-center"> |
|||
<gf-no-transactions-info-indicator></gf-no-transactions-info-indicator> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="overview-container row mt-1"> |
|||
<div class="col"> |
|||
<gf-portfolio-performance |
|||
class="pb-4" |
|||
[baseCurrency]="user?.settings?.baseCurrency" |
|||
[isAllTimeHigh]="isAllTimeHigh" |
|||
[isAllTimeLow]="isAllTimeLow" |
|||
[isLoading]="isLoadingPerformance" |
|||
[locale]="user?.settings?.locale" |
|||
[performance]="performance" |
|||
[showDetails]="!hasImpersonationId && !user.settings.isRestrictedView" |
|||
></gf-portfolio-performance> |
|||
<div class="text-center"> |
|||
<gf-toggle |
|||
[defaultValue]="dateRange" |
|||
[isLoading]="isLoadingPerformance" |
|||
[options]="dateRangeOptions" |
|||
(change)="onChangeDateRange($event.value)" |
|||
></gf-toggle> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
@ -0,0 +1,25 @@ |
|||
import { CommonModule } from '@angular/common'; |
|||
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 { GfLineChartModule } from '@ghostfolio/ui/line-chart/line-chart.module'; |
|||
import { GfNoTransactionsInfoModule } from '@ghostfolio/ui/no-transactions-info'; |
|||
|
|||
import { HomeOverviewComponent } from './home-overview.component'; |
|||
|
|||
@NgModule({ |
|||
declarations: [HomeOverviewComponent], |
|||
exports: [], |
|||
imports: [ |
|||
CommonModule, |
|||
GfLineChartModule, |
|||
GfNoTransactionsInfoModule, |
|||
GfPortfolioPerformanceModule, |
|||
GfToggleModule, |
|||
RouterModule |
|||
], |
|||
providers: [], |
|||
schemas: [CUSTOM_ELEMENTS_SCHEMA] |
|||
}) |
|||
export class GfHomeOverviewModule {} |
@ -0,0 +1,34 @@ |
|||
@import '~apps/client/src/styles/ghostfolio-style'; |
|||
|
|||
:host { |
|||
display: block; |
|||
|
|||
.chart-container { |
|||
aspect-ratio: 16 / 9; |
|||
max-height: 50vh; |
|||
|
|||
// Fallback for aspect-ratio (using padding hack) |
|||
@supports not (aspect-ratio: 16 / 9) { |
|||
&::before { |
|||
float: left; |
|||
padding-top: 56.25%; |
|||
content: ''; |
|||
} |
|||
|
|||
&::after { |
|||
display: block; |
|||
content: ''; |
|||
clear: both; |
|||
} |
|||
} |
|||
|
|||
gf-line-chart { |
|||
bottom: 0; |
|||
left: 0; |
|||
position: absolute; |
|||
right: 0; |
|||
top: 0; |
|||
z-index: -1; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,66 @@ |
|||
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; |
|||
import { DataService } from '@ghostfolio/client/services/data.service'; |
|||
import { UserService } from '@ghostfolio/client/services/user/user.service'; |
|||
import { PortfolioSummary, User } from '@ghostfolio/common/interfaces'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
|
|||
@Component({ |
|||
selector: 'gf-home-summary', |
|||
styleUrls: ['./home-summary.scss'], |
|||
templateUrl: './home-summary.html' |
|||
}) |
|||
export class HomeSummaryComponent implements OnDestroy, OnInit { |
|||
public isLoading = true; |
|||
public summary: PortfolioSummary; |
|||
public user: User; |
|||
|
|||
private unsubscribeSubject = new Subject<void>(); |
|||
|
|||
/** |
|||
* @constructor |
|||
*/ |
|||
public constructor( |
|||
private changeDetectorRef: ChangeDetectorRef, |
|||
private dataService: DataService, |
|||
private userService: UserService |
|||
) { |
|||
this.userService.stateChanged |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((state) => { |
|||
if (state?.user) { |
|||
this.user = state.user; |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Initializes the controller |
|||
*/ |
|||
public ngOnInit() { |
|||
this.update(); |
|||
} |
|||
|
|||
public ngOnDestroy() { |
|||
this.unsubscribeSubject.next(); |
|||
this.unsubscribeSubject.complete(); |
|||
} |
|||
|
|||
private update() { |
|||
this.isLoading = true; |
|||
|
|||
this.dataService |
|||
.fetchPortfolioSummary() |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((response) => { |
|||
this.summary = response; |
|||
this.isLoading = false; |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
}); |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
} |
|||
} |
@ -0,0 +1,19 @@ |
|||
<div class="container pb-3 px-3"> |
|||
<div class="row"> |
|||
<div class="col-xs-12 col-md-8 offset-md-2"> |
|||
<mat-card class="h-100"> |
|||
<mat-card-header> |
|||
<mat-card-title i18n>Summary</mat-card-title> |
|||
</mat-card-header> |
|||
<mat-card-content> |
|||
<gf-portfolio-summary |
|||
[baseCurrency]="user?.settings?.baseCurrency" |
|||
[isLoading]="isLoading" |
|||
[locale]="user?.settings?.locale" |
|||
[summary]="summary" |
|||
></gf-portfolio-summary> |
|||
</mat-card-content> |
|||
</mat-card> |
|||
</div> |
|||
</div> |
|||
</div> |
@ -0,0 +1,21 @@ |
|||
import { CommonModule } from '@angular/common'; |
|||
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 { HomeSummaryComponent } from './home-summary.component'; |
|||
|
|||
@NgModule({ |
|||
declarations: [HomeSummaryComponent], |
|||
exports: [], |
|||
imports: [ |
|||
CommonModule, |
|||
GfPortfolioSummaryModule, |
|||
MatCardModule, |
|||
RouterModule |
|||
], |
|||
providers: [], |
|||
schemas: [CUSTOM_ELEMENTS_SCHEMA] |
|||
}) |
|||
export class GfHomeSummaryModule {} |
@ -0,0 +1,5 @@ |
|||
@import '~apps/client/src/styles/ghostfolio-style'; |
|||
|
|||
:host { |
|||
display: block; |
|||
} |
@ -1,169 +1,14 @@ |
|||
<mat-tab-group |
|||
animationDuration="0ms" |
|||
class="position-absolute" |
|||
headerPosition="below" |
|||
mat-align-tabs="center" |
|||
[disablePagination]="true" |
|||
(selectedTabChange)="onTabChanged($event)" |
|||
> |
|||
<mat-tab> |
|||
<ng-template mat-tab-label> |
|||
<ion-icon name="analytics-outline" size="large"></ion-icon> |
|||
</ng-template> |
|||
<div |
|||
class=" |
|||
align-items-center |
|||
container |
|||
d-flex |
|||
flex-column |
|||
h-100 |
|||
justify-content-center |
|||
overview |
|||
position-relative |
|||
" |
|||
> |
|||
<div class="row w-100"> |
|||
<div class="chart-container col"> |
|||
<gf-line-chart |
|||
class="mr-3" |
|||
symbol="Performance" |
|||
[historicalDataItems]="historicalDataItems" |
|||
[showGradient]="true" |
|||
[showLoader]="false" |
|||
[showXAxis]="false" |
|||
[showYAxis]="false" |
|||
></gf-line-chart> |
|||
<div |
|||
*ngIf="historicalDataItems?.length === 0" |
|||
class=" |
|||
align-items-center |
|||
chart-container |
|||
d-flex |
|||
justify-content-center |
|||
w-100 |
|||
" |
|||
> |
|||
<div class="d-flex justify-content-center"> |
|||
<gf-no-transactions-info-indicator></gf-no-transactions-info-indicator> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="overview-container row mt-1"> |
|||
<div class="col"> |
|||
<gf-portfolio-performance |
|||
class="pb-4" |
|||
[baseCurrency]="user?.settings?.baseCurrency" |
|||
[isAllTimeHigh]="isAllTimeHigh" |
|||
[isAllTimeLow]="isAllTimeLow" |
|||
[isLoading]="isLoadingPerformance" |
|||
[locale]="user?.settings?.locale" |
|||
[performance]="performance" |
|||
[showDetails]="!hasImpersonationId && !user.settings.isRestrictedView" |
|||
></gf-portfolio-performance> |
|||
<div class="text-center"> |
|||
<gf-toggle |
|||
[defaultValue]="dateRange" |
|||
[isLoading]="isLoadingPerformance" |
|||
[options]="dateRangeOptions" |
|||
(change)="onChangeDateRange($event.value)" |
|||
></gf-toggle> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</mat-tab> |
|||
<mat-tab> |
|||
<ng-template mat-tab-label> |
|||
<ion-icon name="wallet-outline" size="large"></ion-icon> |
|||
</ng-template> |
|||
<div class="container justify-content-center pb-3 px-3 positions"> |
|||
<h3 class="d-flex justify-content-center mb-3" i18n>Holdings</h3> |
|||
<div class="row"> |
|||
<div class="align-items-center col-xs-12 col-md-8 offset-md-2"> |
|||
<div class="pb-2 text-center"> |
|||
<gf-toggle |
|||
[defaultValue]="dateRange" |
|||
[isLoading]="isLoadingPerformance" |
|||
[options]="dateRangeOptions" |
|||
(change)="onChangeDateRange($event.value)" |
|||
></gf-toggle> |
|||
</div> |
|||
<mat-card class="p-0"> |
|||
<mat-card-content> |
|||
<gf-positions |
|||
[baseCurrency]="user?.settings?.baseCurrency" |
|||
[deviceType]="deviceType" |
|||
[locale]="user?.settings?.locale" |
|||
[positions]="positions" |
|||
[range]="dateRange" |
|||
></gf-positions> |
|||
</mat-card-content> |
|||
</mat-card> |
|||
<div *ngIf="hasPermissionToCreateOrder" class="text-center"> |
|||
<a |
|||
class="mt-3" |
|||
i18n |
|||
mat-button |
|||
[routerLink]="['/portfolio', 'transactions']" |
|||
>Manage Transactions...</a |
|||
> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</mat-tab> |
|||
<mat-tab> |
|||
<ng-template mat-tab-label> |
|||
<ion-icon name="reader-outline" size="large"></ion-icon> |
|||
</ng-template> |
|||
<div class="container pb-3 px-3 positions"> |
|||
<div class="row"> |
|||
<div class="col-xs-12 col-md-8 offset-md-2"> |
|||
<mat-card class="h-100"> |
|||
<mat-card-header> |
|||
<mat-card-title i18n>Summary</mat-card-title> |
|||
</mat-card-header> |
|||
<mat-card-content> |
|||
<gf-portfolio-summary |
|||
[baseCurrency]="user?.settings?.baseCurrency" |
|||
[isLoading]="isLoadingSummary" |
|||
[locale]="user?.settings?.locale" |
|||
[summary]="summary" |
|||
></gf-portfolio-summary> |
|||
</mat-card-content> |
|||
</mat-card> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</mat-tab> |
|||
<mat-tab *ngIf="hasPermissionToAccessFearAndGreedIndex"> |
|||
<ng-template mat-tab-label> |
|||
<ion-icon name="newspaper-outline" size="large"></ion-icon> |
|||
</ng-template> |
|||
<div |
|||
class=" |
|||
align-items-center |
|||
container |
|||
d-flex |
|||
flex-grow-1 |
|||
h-100 |
|||
justify-content-center |
|||
w-100 |
|||
" |
|||
> |
|||
<div class="row w-100"> |
|||
<div class="col-xs-12 col-md-8 offset-md-2"> |
|||
<mat-card class="h-100"> |
|||
<mat-card-content> |
|||
<gf-fear-and-greed-index |
|||
class="d-flex justify-content-center" |
|||
[fearAndGreedIndex]="fearAndGreedIndex" |
|||
></gf-fear-and-greed-index> |
|||
</mat-card-content> |
|||
</mat-card> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</mat-tab> |
|||
</mat-tab-group> |
|||
<router-outlet></router-outlet> |
|||
|
|||
<nav mat-align-tabs="center" mat-tab-nav-bar> |
|||
<a |
|||
*ngFor="let tab of tabs" |
|||
#rla="routerLinkActive" |
|||
mat-tab-link |
|||
routerLinkActive |
|||
[active]="rla.isActive" |
|||
[routerLink]="tab.path" |
|||
> |
|||
<ion-icon size="large" [name]="tab.iconName"></ion-icon> |
|||
</a> |
|||
</nav> |
|||
|
@ -1,94 +1,14 @@ |
|||
<mat-tab-group |
|||
animationDuration="0ms" |
|||
class="position-absolute" |
|||
headerPosition="below" |
|||
mat-align-tabs="center" |
|||
[disablePagination]="true" |
|||
(selectedTabChange)="onTabChanged($event)" |
|||
> |
|||
<mat-tab> |
|||
<ng-template mat-tab-label> |
|||
<ion-icon name="analytics-outline" size="large"></ion-icon> |
|||
</ng-template> |
|||
<div |
|||
class=" |
|||
container |
|||
d-flex |
|||
flex-column |
|||
h-100 |
|||
justify-content-center |
|||
overview |
|||
position-relative |
|||
" |
|||
> |
|||
<div class="row"> |
|||
<div |
|||
class="chart-container d-flex flex-column col justify-content-center" |
|||
> |
|||
<gf-line-chart |
|||
class="mr-3" |
|||
symbol="Performance" |
|||
[historicalDataItems]="historicalDataItems" |
|||
[showGradient]="true" |
|||
[showLoader]="false" |
|||
[showXAxis]="false" |
|||
[showYAxis]="false" |
|||
></gf-line-chart> |
|||
<div |
|||
*ngIf="historicalDataItems?.length === 0" |
|||
class="d-flex justify-content-center" |
|||
> |
|||
<gf-no-transactions-info-indicator></gf-no-transactions-info-indicator> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="overview-container row mb-5 mt-1"> |
|||
<div class="col"> |
|||
<gf-portfolio-performance |
|||
class="pb-4" |
|||
[baseCurrency]="user?.settings?.baseCurrency" |
|||
[isAllTimeHigh]="isAllTimeHigh" |
|||
[isAllTimeLow]="isAllTimeLow" |
|||
[isLoading]="isLoadingPerformance" |
|||
[locale]="user?.settings?.locale" |
|||
[performance]="performance" |
|||
[showDetails]="!hasImpersonationId && !user.settings.isRestrictedView" |
|||
></gf-portfolio-performance> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</mat-tab> |
|||
<router-outlet></router-outlet> |
|||
|
|||
<mat-tab> |
|||
<ng-template mat-tab-label> |
|||
<ion-icon name="wallet-outline" size="large"></ion-icon> |
|||
</ng-template> |
|||
<div class="container justify-content-center pb-3 px-3 positions"> |
|||
<h3 class="d-flex justify-content-center mb-3" i18n>Holdings</h3> |
|||
<div class="row"> |
|||
<div class="align-items-center col"> |
|||
<mat-card class="p-0"> |
|||
<mat-card-content> |
|||
<gf-positions |
|||
[baseCurrency]="user?.settings?.baseCurrency" |
|||
[deviceType]="deviceType" |
|||
[locale]="user?.settings?.locale" |
|||
[positions]="positions" |
|||
[range]="dateRange" |
|||
></gf-positions> |
|||
</mat-card-content> |
|||
</mat-card> |
|||
<div *ngIf="hasPermissionToCreateOrder" class="text-center"> |
|||
<a |
|||
class="mt-3" |
|||
i18n |
|||
mat-button |
|||
[routerLink]="['/portfolio', 'transactions']" |
|||
>Manage Transactions...</a |
|||
> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</mat-tab> |
|||
</mat-tab-group> |
|||
<nav mat-align-tabs="center" mat-tab-nav-bar> |
|||
<a |
|||
*ngFor="let tab of tabs" |
|||
#rla="routerLinkActive" |
|||
mat-tab-link |
|||
routerLinkActive |
|||
[active]="rla.isActive" |
|||
[routerLink]="tab.path" |
|||
> |
|||
<ion-icon size="large" [name]="tab.iconName"></ion-icon> |
|||
</a> |
|||
</nav> |
|||
|
Loading…
Reference in new issue