Feature/add dialog for benchmarks in markets overview (#3493)
* Add benchmarks dialog in markets overview * Update changelog
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
:host {
|
||||
display: block;
|
||||
|
||||
.mat-mdc-dialog-content {
|
||||
max-height: unset;
|
||||
|
||||
gf-line-chart {
|
||||
aspect-ratio: 16 / 9;
|
||||
margin: 0 -0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-footer/dialog-footer.module';
|
||||
import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module';
|
||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||
import { DATE_FORMAT } from '@ghostfolio/common/helper';
|
||||
import {
|
||||
AdminMarketDataDetails,
|
||||
LineChartItem
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { GfLineChartComponent } from '@ghostfolio/ui/line-chart';
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {
|
||||
CUSTOM_ELEMENTS_SCHEMA,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
Inject,
|
||||
OnDestroy,
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogModule,
|
||||
MatDialogRef
|
||||
} from '@angular/material/dialog';
|
||||
import { format } from 'date-fns';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { BenchmarkDetailDialogParams } from './interfaces/interfaces';
|
||||
|
||||
@Component({
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'd-flex flex-column h-100' },
|
||||
imports: [
|
||||
CommonModule,
|
||||
GfDialogFooterModule,
|
||||
GfDialogHeaderModule,
|
||||
GfLineChartComponent,
|
||||
MatDialogModule
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
selector: 'gf-benchmark-detail-dialog',
|
||||
standalone: true,
|
||||
styleUrls: ['./benchmark-detail-dialog.component.scss'],
|
||||
templateUrl: 'benchmark-detail-dialog.html'
|
||||
})
|
||||
export class GfBenchmarkDetailDialogComponent implements OnDestroy, OnInit {
|
||||
public assetProfile: AdminMarketDataDetails['assetProfile'];
|
||||
public historicalDataItems: LineChartItem[];
|
||||
|
||||
private unsubscribeSubject = new Subject<void>();
|
||||
|
||||
public constructor(
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private dataService: DataService,
|
||||
public dialogRef: MatDialogRef<GfBenchmarkDetailDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: BenchmarkDetailDialogParams
|
||||
) {}
|
||||
|
||||
public ngOnInit() {
|
||||
this.dataService
|
||||
.fetchAsset({
|
||||
dataSource: this.data.dataSource,
|
||||
symbol: this.data.symbol
|
||||
})
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(({ assetProfile, marketData }) => {
|
||||
this.assetProfile = assetProfile;
|
||||
|
||||
this.historicalDataItems = marketData.map(({ date, marketPrice }) => {
|
||||
return { date: format(date, DATE_FORMAT), value: marketPrice };
|
||||
});
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
public onClose() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
public ngOnDestroy() {
|
||||
this.unsubscribeSubject.next();
|
||||
this.unsubscribeSubject.complete();
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
<gf-dialog-header
|
||||
mat-dialog-title
|
||||
position="center"
|
||||
[deviceType]="data.deviceType"
|
||||
[title]="assetProfile?.name ?? assetProfile?.symbol"
|
||||
(closeButtonClicked)="onClose()"
|
||||
/>
|
||||
|
||||
<div class="flex-grow-1" mat-dialog-content>
|
||||
<div class="container p-0">
|
||||
<gf-line-chart
|
||||
benchmarkLabel="Average Unit Price"
|
||||
class="mb-4"
|
||||
[colorScheme]="data.colorScheme"
|
||||
[historicalDataItems]="historicalDataItems"
|
||||
[isAnimated]="true"
|
||||
[locale]="data.locale"
|
||||
[showGradient]="true"
|
||||
[showXAxis]="true"
|
||||
[showYAxis]="true"
|
||||
[symbol]="data.symbol"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<gf-dialog-footer
|
||||
mat-dialog-actions
|
||||
[deviceType]="data.deviceType"
|
||||
(closeButtonClicked)="onClose()"
|
||||
/>
|
@@ -0,0 +1,11 @@
|
||||
import { ColorScheme } from '@ghostfolio/common/types';
|
||||
|
||||
import { DataSource } from '@prisma/client';
|
||||
|
||||
export interface BenchmarkDetailDialogParams {
|
||||
colorScheme: ColorScheme;
|
||||
dataSource: DataSource;
|
||||
deviceType: string;
|
||||
locale: string;
|
||||
symbol: string;
|
||||
}
|
@@ -110,5 +110,15 @@
|
||||
</ng-container>
|
||||
|
||||
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
|
||||
<tr *matRowDef="let row; columns: displayedColumns" mat-row></tr>
|
||||
<tr
|
||||
*matRowDef="let row; columns: displayedColumns"
|
||||
class="cursor-pointer"
|
||||
mat-row
|
||||
(click)="
|
||||
onOpenBenchmarkDialog({
|
||||
dataSource: row.dataSource,
|
||||
symbol: row.symbol
|
||||
})
|
||||
"
|
||||
></tr>
|
||||
</table>
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import { getLocale, resolveMarketCondition } from '@ghostfolio/common/helper';
|
||||
import { Benchmark, User } from '@ghostfolio/common/interfaces';
|
||||
import { Benchmark, UniqueAsset, User } from '@ghostfolio/common/interfaces';
|
||||
import { translate } from '@ghostfolio/ui/i18n';
|
||||
import { GfTrendIndicatorComponent } from '@ghostfolio/ui/trend-indicator';
|
||||
import { GfValueComponent } from '@ghostfolio/ui/value';
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {
|
||||
@@ -8,13 +10,17 @@ import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
Input,
|
||||
OnChanges
|
||||
OnChanges,
|
||||
OnDestroy
|
||||
} from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
|
||||
import { GfTrendIndicatorComponent } from '../trend-indicator';
|
||||
import { GfValueComponent } from '../value';
|
||||
import { GfBenchmarkDetailDialogComponent } from './benchmark-detail-dialog/benchmark-detail-dialog.component';
|
||||
import { BenchmarkDetailDialogParams } from './benchmark-detail-dialog/interfaces/interfaces';
|
||||
|
||||
@Component({
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
@@ -23,7 +29,8 @@ import { GfValueComponent } from '../value';
|
||||
GfTrendIndicatorComponent,
|
||||
GfValueComponent,
|
||||
MatTableModule,
|
||||
NgxSkeletonLoaderModule
|
||||
NgxSkeletonLoaderModule,
|
||||
RouterModule
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
selector: 'gf-benchmark',
|
||||
@@ -31,8 +38,9 @@ import { GfValueComponent } from '../value';
|
||||
styleUrls: ['./benchmark.component.scss'],
|
||||
templateUrl: './benchmark.component.html'
|
||||
})
|
||||
export class GfBenchmarkComponent implements OnChanges {
|
||||
export class GfBenchmarkComponent implements OnChanges, OnDestroy {
|
||||
@Input() benchmarks: Benchmark[];
|
||||
@Input() deviceType: string;
|
||||
@Input() locale = getLocale();
|
||||
@Input() user: User;
|
||||
|
||||
@@ -40,7 +48,28 @@ export class GfBenchmarkComponent implements OnChanges {
|
||||
public resolveMarketCondition = resolveMarketCondition;
|
||||
public translate = translate;
|
||||
|
||||
public constructor() {}
|
||||
private unsubscribeSubject = new Subject<void>();
|
||||
|
||||
public constructor(
|
||||
private dialog: MatDialog,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router
|
||||
) {
|
||||
this.route.queryParams
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((params) => {
|
||||
if (
|
||||
params['benchmarkDetailDialog'] &&
|
||||
params['dataSource'] &&
|
||||
params['symbol']
|
||||
) {
|
||||
this.openBenchmarkDetailDialog({
|
||||
dataSource: params['dataSource'],
|
||||
symbol: params['symbol']
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnChanges() {
|
||||
if (this.user?.settings?.isExperimentalFeatures) {
|
||||
@@ -54,4 +83,36 @@ export class GfBenchmarkComponent implements OnChanges {
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public onOpenBenchmarkDialog({ dataSource, symbol }: UniqueAsset) {
|
||||
this.router.navigate([], {
|
||||
queryParams: { dataSource, symbol, benchmarkDetailDialog: true }
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy() {
|
||||
this.unsubscribeSubject.next();
|
||||
this.unsubscribeSubject.complete();
|
||||
}
|
||||
|
||||
private openBenchmarkDetailDialog({ dataSource, symbol }: UniqueAsset) {
|
||||
const dialogRef = this.dialog.open(GfBenchmarkDetailDialogComponent, {
|
||||
data: <BenchmarkDetailDialogParams>{
|
||||
dataSource,
|
||||
symbol,
|
||||
colorScheme: this.user?.settings?.colorScheme,
|
||||
deviceType: this.deviceType,
|
||||
locale: this.locale
|
||||
},
|
||||
height: this.deviceType === 'mobile' ? '97.5vh' : undefined,
|
||||
width: this.deviceType === 'mobile' ? '100vw' : '50rem'
|
||||
});
|
||||
|
||||
dialogRef
|
||||
.afterClosed()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(() => {
|
||||
this.router.navigate(['.'], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user