moved dashboard to top level and created a new system plan
This commit is contained in:
parent
5e692f4ab5
commit
7993148a95
76 changed files with 783 additions and 500 deletions
|
|
@ -0,0 +1,198 @@
|
|||
import { Component, signal, OnInit, OnDestroy, inject } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSnackBarModule, MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ApiService } from '../../services/api.service';
|
||||
import { WebSocketService } from '../../services/websocket.service';
|
||||
import { interval, Subscription } from 'rxjs';
|
||||
|
||||
export interface ExtendedMarketData {
|
||||
symbol: string;
|
||||
price: number;
|
||||
change: number;
|
||||
changePercent: number;
|
||||
volume: number;
|
||||
marketCap: string;
|
||||
high52Week: number;
|
||||
low52Week: number;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-market-data',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatCardModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatTableModule,
|
||||
MatTabsModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatSnackBarModule
|
||||
],
|
||||
templateUrl: './market-data.component.html',
|
||||
styleUrl: './market-data.component.css'
|
||||
})
|
||||
export class MarketDataComponent implements OnInit, OnDestroy {
|
||||
private apiService = inject(ApiService);
|
||||
private webSocketService = inject(WebSocketService);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
private subscriptions: Subscription[] = [];
|
||||
|
||||
protected marketData = signal<ExtendedMarketData[]>([]);
|
||||
protected currentTime = signal<string>(new Date().toLocaleTimeString());
|
||||
protected isLoading = signal<boolean>(true);
|
||||
protected error = signal<string | null>(null);
|
||||
protected displayedColumns: string[] = ['symbol', 'price', 'change', 'changePercent', 'volume', 'marketCap'];
|
||||
ngOnInit() {
|
||||
// Update time every second
|
||||
const timeSubscription = interval(1000).subscribe(() => {
|
||||
this.currentTime.set(new Date().toLocaleTimeString());
|
||||
});
|
||||
this.subscriptions.push(timeSubscription);
|
||||
|
||||
// Load initial market data
|
||||
this.loadMarketData();
|
||||
|
||||
// Subscribe to real-time market data updates
|
||||
const wsSubscription = this.webSocketService.getMarketDataUpdates().subscribe({
|
||||
next: (update) => {
|
||||
this.updateMarketData(update);
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('WebSocket market data error:', err);
|
||||
}
|
||||
});
|
||||
this.subscriptions.push(wsSubscription);
|
||||
|
||||
// Fallback: Refresh market data every 30 seconds if WebSocket fails
|
||||
const dataSubscription = interval(30000).subscribe(() => {
|
||||
if (!this.webSocketService.isConnected()) {
|
||||
this.loadMarketData();
|
||||
}
|
||||
});
|
||||
this.subscriptions.push(dataSubscription);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subscriptions.forEach(sub => sub.unsubscribe());
|
||||
}
|
||||
private loadMarketData() {
|
||||
this.apiService.getMarketData().subscribe({
|
||||
next: (response) => {
|
||||
// Convert MarketData to ExtendedMarketData with mock extended properties
|
||||
const extendedData: ExtendedMarketData[] = response.data.map(item => ({
|
||||
...item,
|
||||
marketCap: this.getMockMarketCap(item.symbol),
|
||||
high52Week: item.price * 1.3, // Mock 52-week high (30% above current)
|
||||
low52Week: item.price * 0.7 // Mock 52-week low (30% below current)
|
||||
}));
|
||||
|
||||
this.marketData.set(extendedData);
|
||||
this.isLoading.set(false);
|
||||
this.error.set(null);
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Failed to load market data:', err);
|
||||
this.error.set('Failed to load market data');
|
||||
this.isLoading.set(false);
|
||||
this.snackBar.open('Failed to load market data', 'Dismiss', { duration: 5000 });
|
||||
|
||||
// Use mock data as fallback
|
||||
this.marketData.set(this.getMockData());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getMockMarketCap(symbol: string): string {
|
||||
const marketCaps: { [key: string]: string } = {
|
||||
'AAPL': '2.98T',
|
||||
'GOOGL': '1.78T',
|
||||
'MSFT': '3.08T',
|
||||
'TSLA': '789.2B',
|
||||
'AMZN': '1.59T'
|
||||
};
|
||||
return marketCaps[symbol] || '1.00T';
|
||||
}
|
||||
|
||||
private getMockData(): ExtendedMarketData[] {
|
||||
return [
|
||||
{
|
||||
symbol: 'AAPL',
|
||||
price: 192.53,
|
||||
change: 2.41,
|
||||
changePercent: 1.27,
|
||||
volume: 45230000,
|
||||
marketCap: '2.98T',
|
||||
high52Week: 199.62,
|
||||
low52Week: 164.08
|
||||
},
|
||||
{
|
||||
symbol: 'GOOGL',
|
||||
price: 2847.56,
|
||||
change: -12.34,
|
||||
changePercent: -0.43,
|
||||
volume: 12450000,
|
||||
marketCap: '1.78T',
|
||||
high52Week: 3030.93,
|
||||
low52Week: 2193.62
|
||||
},
|
||||
{
|
||||
symbol: 'MSFT',
|
||||
price: 415.26,
|
||||
change: 8.73,
|
||||
changePercent: 2.15,
|
||||
volume: 23180000,
|
||||
marketCap: '3.08T',
|
||||
high52Week: 468.35,
|
||||
low52Week: 309.45
|
||||
},
|
||||
{
|
||||
symbol: 'TSLA',
|
||||
price: 248.50,
|
||||
change: -5.21,
|
||||
changePercent: -2.05,
|
||||
volume: 89760000,
|
||||
marketCap: '789.2B',
|
||||
high52Week: 299.29,
|
||||
low52Week: 152.37
|
||||
},
|
||||
{
|
||||
symbol: 'AMZN',
|
||||
price: 152.74,
|
||||
change: 3.18,
|
||||
changePercent: 2.12,
|
||||
volume: 34520000,
|
||||
marketCap: '1.59T',
|
||||
high52Week: 170.17,
|
||||
low52Week: 118.35
|
||||
}
|
||||
];
|
||||
}
|
||||
refreshData() {
|
||||
this.isLoading.set(true);
|
||||
this.loadMarketData();
|
||||
}
|
||||
|
||||
private updateMarketData(update: any) {
|
||||
const currentData = this.marketData();
|
||||
const updatedData = currentData.map(item => {
|
||||
if (item.symbol === update.symbol) {
|
||||
return {
|
||||
...item,
|
||||
price: update.price,
|
||||
change: update.change,
|
||||
changePercent: update.changePercent,
|
||||
volume: update.volume
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
this.marketData.set(updatedData);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue