import { ConfirmationDialogType } from '@ghostfolio/common/enums'; import { getLocale, getLowercase, resolveMarketCondition } from '@ghostfolio/common/helper'; import { AssetProfileIdentifier, Benchmark, User } from '@ghostfolio/common/interfaces'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, DestroyRef, computed, effect, inject, input, output, viewChild } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { MatMenuModule } from '@angular/material/menu'; import { MatSort, MatSortModule } from '@angular/material/sort'; import { MatTableDataSource, MatTableModule } from '@angular/material/table'; import { ActivatedRoute, Router, RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { ellipsisHorizontal, trashOutline } from 'ionicons/icons'; import { isNumber } from 'lodash'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { translate } from '../i18n'; import { GfTrendIndicatorComponent } from '../trend-indicator/trend-indicator.component'; import { GfValueComponent } from '../value/value.component'; import { GfBenchmarkDetailDialogComponent } from './benchmark-detail-dialog/benchmark-detail-dialog.component'; import { BenchmarkDetailDialogParams } from './benchmark-detail-dialog/interfaces/interfaces'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, imports: [ GfTrendIndicatorComponent, GfValueComponent, IonIcon, MatButtonModule, MatMenuModule, MatSortModule, MatTableModule, NgxSkeletonLoaderModule, RouterModule ], schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-benchmark', styleUrls: ['./benchmark.component.scss'], templateUrl: './benchmark.component.html' }) export class GfBenchmarkComponent { public readonly benchmarks = input.required(); public readonly deviceType = input.required(); public readonly hasPermissionToDeleteItem = input(); public readonly locale = input(getLocale()); public readonly showSymbol = input(true); public readonly user = input(); public readonly itemDeleted = output(); protected readonly sort = viewChild(MatSort); protected readonly dataSource = new MatTableDataSource([]); protected readonly displayedColumns = computed(() => { return [ 'name', ...(this.user()?.settings?.isExperimentalFeatures ? ['trend50d', 'trend200d'] : []), 'date', 'change', 'marketCondition', 'actions' ]; }); protected isLoading = true; protected readonly isNumber = isNumber; protected readonly resolveMarketCondition = resolveMarketCondition; protected readonly translate = translate; private readonly destroyRef = inject(DestroyRef); private readonly dialog = inject(MatDialog); private readonly notificationService = inject(NotificationService); private readonly route = inject(ActivatedRoute); private readonly router = inject(Router); public constructor() { effect(() => { const benchmarks = this.benchmarks(); if (benchmarks) { this.dataSource.data = benchmarks; this.dataSource.sortingDataAccessor = getLowercase; this.dataSource.sort = this.sort() ?? null; this.isLoading = false; } }); this.route.queryParams .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if ( params['benchmarkDetailDialog'] && params['dataSource'] && params['symbol'] ) { this.openBenchmarkDetailDialog({ dataSource: params['dataSource'], symbol: params['symbol'] }); } }); addIcons({ ellipsisHorizontal, trashOutline }); } protected onDeleteItem({ dataSource, symbol }: AssetProfileIdentifier) { this.notificationService.confirm({ confirmFn: () => { this.itemDeleted.emit({ dataSource, symbol }); }, confirmType: ConfirmationDialogType.Warn, title: $localize`Do you really want to delete this item?` }); } protected onOpenBenchmarkDialog({ dataSource, symbol }: AssetProfileIdentifier) { this.router.navigate([], { queryParams: { dataSource, symbol, benchmarkDetailDialog: true } }); } private openBenchmarkDetailDialog({ dataSource, symbol }: AssetProfileIdentifier) { const dialogRef = this.dialog.open< GfBenchmarkDetailDialogComponent, BenchmarkDetailDialogParams >(GfBenchmarkDetailDialogComponent, { data: { dataSource, symbol, colorScheme: this.user()?.settings?.colorScheme, deviceType: this.deviceType(), locale: this.locale() }, height: this.deviceType() === 'mobile' ? '98vh' : undefined, width: this.deviceType() === 'mobile' ? '100vw' : '50rem' }); dialogRef .afterClosed() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.router.navigate(['.'], { relativeTo: this.route }); }); } }