import { CommonModule } from '@angular/common'; import { Component, inject, OnDestroy, OnInit, signal } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatIconModule } from '@angular/material/icon'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatTableModule } from '@angular/material/table'; import { MatTabsModule } from '@angular/material/tabs'; import { interval, Subscription } from 'rxjs'; import { ApiService } from '../../services/api.service'; export interface Position { symbol: string; quantity: number; avgPrice: number; currentPrice: number; marketValue: number; unrealizedPnL: number; unrealizedPnLPercent: number; dayChange: number; dayChangePercent: number; } export interface PortfolioSummary { totalValue: number; totalCost: number; totalPnL: number; totalPnLPercent: number; dayChange: number; dayChangePercent: number; cash: number; positionsCount: number; } @Component({ selector: 'app-portfolio', standalone: true, imports: [ CommonModule, MatCardModule, MatIconModule, MatButtonModule, MatTableModule, MatProgressSpinnerModule, MatSnackBarModule, MatTabsModule, ], templateUrl: './portfolio.component.html', styleUrl: './portfolio.component.css', }) export class PortfolioComponent implements OnInit, OnDestroy { private apiService = inject(ApiService); private snackBar = inject(MatSnackBar); private subscriptions: Subscription[] = []; protected portfolioSummary = signal({ totalValue: 0, totalCost: 0, totalPnL: 0, totalPnLPercent: 0, dayChange: 0, dayChangePercent: 0, cash: 0, positionsCount: 0, }); protected positions = signal([]); protected isLoading = signal(true); protected error = signal(null); protected displayedColumns = [ 'symbol', 'quantity', 'avgPrice', 'currentPrice', 'marketValue', 'unrealizedPnL', 'dayChange', ]; ngOnInit() { this.loadPortfolioData(); // Refresh portfolio data every 30 seconds const portfolioSubscription = interval(30000).subscribe(() => { this.loadPortfolioData(); }); this.subscriptions.push(portfolioSubscription); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } private loadPortfolioData() { // Since we don't have a portfolio endpoint yet, let's create mock data // In a real implementation, this would call this.apiService.getPortfolio() setTimeout(() => { const mockPositions: Position[] = [ { symbol: 'AAPL', quantity: 100, avgPrice: 180.5, currentPrice: 192.53, marketValue: 19253, unrealizedPnL: 1203, unrealizedPnLPercent: 6.67, dayChange: 241, dayChangePercent: 1.27, }, { symbol: 'MSFT', quantity: 50, avgPrice: 400.0, currentPrice: 415.26, marketValue: 20763, unrealizedPnL: 763, unrealizedPnLPercent: 3.82, dayChange: 436.5, dayChangePercent: 2.15, }, { symbol: 'GOOGL', quantity: 10, avgPrice: 2900.0, currentPrice: 2847.56, marketValue: 28475.6, unrealizedPnL: -524.4, unrealizedPnLPercent: -1.81, dayChange: -123.4, dayChangePercent: -0.43, }, ]; const summary: PortfolioSummary = { totalValue: mockPositions.reduce((sum, pos) => sum + pos.marketValue, 0) + 25000, // + cash totalCost: mockPositions.reduce((sum, pos) => sum + pos.avgPrice * pos.quantity, 0), totalPnL: mockPositions.reduce((sum, pos) => sum + pos.unrealizedPnL, 0), totalPnLPercent: 0, dayChange: mockPositions.reduce((sum, pos) => sum + pos.dayChange, 0), dayChangePercent: 0, cash: 25000, positionsCount: mockPositions.length, }; summary.totalPnLPercent = (summary.totalPnL / summary.totalCost) * 100; summary.dayChangePercent = (summary.dayChange / (summary.totalValue - summary.dayChange)) * 100; this.positions.set(mockPositions); this.portfolioSummary.set(summary); this.isLoading.set(false); this.error.set(null); }, 1000); } refreshData() { this.isLoading.set(true); this.loadPortfolioData(); } getPnLColor(value: number): string { if (value > 0) { return 'text-green-600'; } if (value < 0) { return 'text-red-600'; } return 'text-gray-600'; } }