From 345d76e06f474753980bee8fbde26f2b62791783 Mon Sep 17 00:00:00 2001 From: cryptooda Date: Thu, 14 Aug 2025 18:59:37 +0700 Subject: [PATCH] Update plateform summary --- .../Controllers/DataController.cs | 19 +- .../Models/Responses/AgentSummaryViewModel.cs | 5 - .../src/generated/ManagingApi.ts | 7 +- .../src/generated/ManagingApiTypes.ts | 1 - .../src/pages/dashboardPage/dashboard.tsx | 6 + .../pages/dashboardPage/platformSummary.tsx | 259 ++++++++++++++++++ 6 files changed, 272 insertions(+), 25 deletions(-) create mode 100644 src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx diff --git a/src/Managing.Api/Controllers/DataController.cs b/src/Managing.Api/Controllers/DataController.cs index 2e295eb..41d713c 100644 --- a/src/Managing.Api/Controllers/DataController.cs +++ b/src/Managing.Api/Controllers/DataController.cs @@ -459,19 +459,11 @@ public class DataController : ControllerBase /// /// Retrieves a summary of platform activity across all agents (platform-level data only) /// - /// Time filter to apply (24H, 3D, 1W, 1M, 1Y, Total) /// A summary of platform activity without individual agent details [HttpGet("GetPlatformSummary")] - public async Task> GetPlatformSummary(string timeFilter = "Total") + public async Task> GetPlatformSummary() { - // Validate time filter - var validTimeFilters = new[] { "24H", "3D", "1W", "1M", "1Y", "Total" }; - if (!validTimeFilters.Contains(timeFilter)) - { - timeFilter = "Total"; // Default to Total if invalid - } - - string cacheKey = $"PlatformSummary_{timeFilter}"; + const string cacheKey = "PlatformSummary"; // Check if the platform summary is already cached var cachedSummary = _cacheService.GetValue(cacheKey); @@ -481,15 +473,14 @@ public class DataController : ControllerBase return Ok(cachedSummary); } - // Get all agents and their strategies - var agentsWithStrategies = await _mediator.Send(new GetAllAgentsCommand(timeFilter)); + // Get all agents and their strategies (without time filter) + var agentsWithStrategies = await _mediator.Send(new GetAllAgentsCommand()); // Create the platform summary var summary = new PlatformSummaryViewModel { TotalAgents = agentsWithStrategies.Count, - TotalActiveStrategies = agentsWithStrategies.Values.Sum(list => list.Count), - TimeFilter = timeFilter + TotalActiveStrategies = agentsWithStrategies.Values.Sum(list => list.Count) }; // Calculate total platform metrics diff --git a/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs b/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs index e0ac7c0..0e46709 100644 --- a/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs +++ b/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs @@ -71,11 +71,6 @@ namespace Managing.Api.Models.Responses /// Total volume traded across all agents in the last 24 hours in USD /// public decimal TotalPlatformVolumeLast24h { get; set; } - - /// - /// Time filter applied to the data - /// - public string TimeFilter { get; set; } = "Total"; } /// diff --git a/src/Managing.WebApp/src/generated/ManagingApi.ts b/src/Managing.WebApp/src/generated/ManagingApi.ts index 1227bc4..7d1f6e7 100644 --- a/src/Managing.WebApp/src/generated/ManagingApi.ts +++ b/src/Managing.WebApp/src/generated/ManagingApi.ts @@ -1980,10 +1980,8 @@ export class DataClient extends AuthorizedApiBase { return Promise.resolve(null as any); } - data_GetPlatformSummary(timeFilter: string | null | undefined): Promise { - let url_ = this.baseUrl + "/Data/GetPlatformSummary?"; - if (timeFilter !== undefined && timeFilter !== null) - url_ += "timeFilter=" + encodeURIComponent("" + timeFilter) + "&"; + data_GetPlatformSummary(): Promise { + let url_ = this.baseUrl + "/Data/GetPlatformSummary"; url_ = url_.replace(/[?&]$/, ""); let options_: RequestInit = { @@ -4579,7 +4577,6 @@ export interface PlatformSummaryViewModel { totalPlatformPnL?: number; totalPlatformVolume?: number; totalPlatformVolumeLast24h?: number; - timeFilter?: string | null; } export interface PaginatedAgentIndexResponse { diff --git a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts index 6c68d00..9126d8f 100644 --- a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts +++ b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts @@ -967,7 +967,6 @@ export interface PlatformSummaryViewModel { totalPlatformPnL?: number; totalPlatformVolume?: number; totalPlatformVolumeLast24h?: number; - timeFilter?: string | null; } export interface PaginatedAgentIndexResponse { diff --git a/src/Managing.WebApp/src/pages/dashboardPage/dashboard.tsx b/src/Managing.WebApp/src/pages/dashboardPage/dashboard.tsx index 0366a60..e3cfa61 100644 --- a/src/Managing.WebApp/src/pages/dashboardPage/dashboard.tsx +++ b/src/Managing.WebApp/src/pages/dashboardPage/dashboard.tsx @@ -9,6 +9,7 @@ import BestAgents from './analytics/bestAgents' import AgentSearch from './agentSearch' import AgentIndex from './agentIndex' import AgentStrategy from './agentStrategy' +import PlatformSummary from './platformSummary' const tabs: ITabsType = [ { @@ -41,6 +42,11 @@ const tabs: ITabsType = [ index: 6, label: 'Agent Strategy', }, + { + Component: PlatformSummary, + index: 7, + label: 'Platform Summary', + }, ] const Dashboard: React.FC = () => { diff --git a/src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx b/src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx new file mode 100644 index 0000000..2d60031 --- /dev/null +++ b/src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx @@ -0,0 +1,259 @@ +import React, {useEffect, useState} from 'react' +import useApiUrlStore from '../../app/store/apiStore' +import { + DataClient, + type PlatformSummaryViewModel, + type StrategiesStatisticsViewModel, + type TopStrategiesViewModel +} from '../../generated/ManagingApi' + +function PlatformSummary({ index }: { index: number }) { + const { apiUrl } = useApiUrlStore() + const [platformData, setPlatformData] = useState(null) + const [strategiesStats, setStrategiesStats] = useState(null) + const [topStrategies, setTopStrategies] = useState(null) + const [isLoading, setIsLoading] = useState(true) + const [error, setError] = useState(null) + + const fetchPlatformData = async () => { + setIsLoading(true) + setError(null) + + try { + const client = new DataClient({}, apiUrl) + + // Fetch all platform data in parallel + const [platform, strategies, top] = await Promise.all([ + client.data_GetPlatformSummary(), + client.data_GetStrategiesStatistics(), + client.data_GetTopStrategies() + ]) + + setPlatformData(platform) + setStrategiesStats(strategies) + setTopStrategies(top) + } catch (err) { + setError('Failed to fetch platform data') + console.error('Error fetching platform data:', err) + } finally { + setIsLoading(false) + } + } + + useEffect(() => { + fetchPlatformData() + + // Set up refresh interval (every 30 seconds) + const interval = setInterval(fetchPlatformData, 30000) + return () => clearInterval(interval) + }, [apiUrl]) + + const formatCurrency = (value: number) => { + if (value >= 1000000) { + return `$${(value / 1000000).toFixed(1)}M` + } else if (value >= 1000) { + return `$${(value / 1000).toFixed(1)}K` + } + return `$${value.toFixed(0)}` + } + + const formatNumber = (value: number) => { + if (value >= 1000) { + return value.toLocaleString() + } + return value.toString() + } + + const formatChangeIndicator = (change: number) => { + if (change > 0) { + return ( + + +{change} Today + + ) + } else if (change < 0) { + return ( + + {change} Today + + ) + } + return ( + + No change + + ) + } + + if (isLoading) { + return ( +
+
+
+ ) + } + + if (error) { + return ( +
+ {error} +
+ ) + } + + return ( +
+ {/* Header */} +
+

+ {formatNumber(strategiesStats?.totalStrategiesRunning || 0)} Strategies Deployed +

+
+ {strategiesStats && formatChangeIndicator(strategiesStats.changeInLast24Hours || 0)} +
+
+ + {/* Main Stats Grid */} +
+ {/* Total Volume Traded */} +
+

Total Volume Traded

+
+ {formatCurrency(platformData?.totalPlatformVolume || 0)} +
+
+ +{formatCurrency(platformData?.totalPlatformVolumeLast24h || 0)} Today +
+ {/* Simple chart placeholder - you can replace with actual chart */} +
+
+
+
+ + {/* Top 3 Most Profitable */} +
+
+ 🤑 +

Top 3 Most Profitable

+
+
+ {topStrategies?.topStrategies?.slice(0, 3).map((strategy, index) => ( +
+
+
+ + {strategy.strategyName?.charAt(0) || 'S'} + +
+
+
+ {strategy.strategyName || '[Strategy Name]'} +
+
📧
+
+
+
= 0 ? 'text-green-500' : 'text-red-500'}`}> + {strategy.pnL && strategy.pnL >= 0 ? '+' : ''}{formatCurrency(strategy.pnL || 0)} +
+
+ )) || ( +
No profitable strategies found
+ )} +
+
+ + {/* Top 3 Rising (placeholder - using same data for now) */} +
+
+ 📈 +

Top 3 Rising

+
+
+ {topStrategies?.topStrategies?.slice(0, 3).map((strategy, index) => ( +
+
+
+ + {strategy.strategyName?.charAt(0) || 'S'} + +
+
+
+ {strategy.strategyName || '[Strategy Name]'} +
+
📧
+
+
+
+ 🔴 + 1,200 +
+
+ )) || ( +
No rising strategies found
+ )} +
+
+ + {/* Top 3 Strategies */} +
+
+ âš¡ +

Top 3 Strategies

+
+
+ {topStrategies?.topStrategies?.slice(0, 3).map((strategy, index) => { + // Calculate a mock percentage for display + const percentage = Math.abs((strategy.pnL || 0) / 100 * 10).toFixed(0) + return ( +
+
+
+ âš¡ +
+
+
+ {strategy.strategyName || '[Strategy Name]'} +
+
+
+
+ +{percentage}% +
+
+ ) + }) || ( +
No strategies found
+ )} +
+
+
+ + {/* Platform Summary Stats */} +
+
+

Total Agents

+
+ {formatNumber(platformData?.totalAgents || 0)} +
+
+ +
+

Active Strategies

+
+ {formatNumber(platformData?.totalActiveStrategies || 0)} +
+
+ +
+

Total Platform PnL

+
= 0 ? 'text-green-500' : 'text-red-500'}`}> + {(platformData?.totalPlatformPnL || 0) >= 0 ? '+' : ''}{formatCurrency(platformData?.totalPlatformPnL || 0)} +
+
+
+
+ ) +} + +export default PlatformSummary