import { Component, signal, OnInit, OnDestroy, inject } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MatCardModule } from '@angular/material/card'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; import { MatTableModule } from '@angular/material/table'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSnackBarModule, MatSnackBar } from '@angular/material/snack-bar'; import { MatTabsModule } from '@angular/material/tabs'; import { ApiService } from '../../services/api.service'; import { interval, Subscription } from 'rxjs'; 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.50, currentPrice: 192.53, marketValue: 19253, unrealizedPnL: 1203, unrealizedPnLPercent: 6.67, dayChange: 241, dayChangePercent: 1.27 }, { symbol: 'MSFT', quantity: 50, avgPrice: 400.00, currentPrice: 415.26, marketValue: 20763, unrealizedPnL: 763, unrealizedPnLPercent: 3.82, dayChange: 436.50, dayChangePercent: 2.15 }, { symbol: 'GOOGL', quantity: 10, avgPrice: 2900.00, currentPrice: 2847.56, marketValue: 28475.60, unrealizedPnL: -524.40, unrealizedPnLPercent: -1.81, dayChange: -123.40, 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'; } }