Update plateform summary

This commit is contained in:
2025-08-14 18:59:37 +07:00
parent cfb04e9dc9
commit 345d76e06f
6 changed files with 272 additions and 25 deletions

View File

@@ -459,19 +459,11 @@ public class DataController : ControllerBase
/// <summary> /// <summary>
/// Retrieves a summary of platform activity across all agents (platform-level data only) /// Retrieves a summary of platform activity across all agents (platform-level data only)
/// </summary> /// </summary>
/// <param name="timeFilter">Time filter to apply (24H, 3D, 1W, 1M, 1Y, Total)</param>
/// <returns>A summary of platform activity without individual agent details</returns> /// <returns>A summary of platform activity without individual agent details</returns>
[HttpGet("GetPlatformSummary")] [HttpGet("GetPlatformSummary")]
public async Task<ActionResult<PlatformSummaryViewModel>> GetPlatformSummary(string timeFilter = "Total") public async Task<ActionResult<PlatformSummaryViewModel>> GetPlatformSummary()
{ {
// Validate time filter const string cacheKey = "PlatformSummary";
var validTimeFilters = new[] { "24H", "3D", "1W", "1M", "1Y", "Total" };
if (!validTimeFilters.Contains(timeFilter))
{
timeFilter = "Total"; // Default to Total if invalid
}
string cacheKey = $"PlatformSummary_{timeFilter}";
// Check if the platform summary is already cached // Check if the platform summary is already cached
var cachedSummary = _cacheService.GetValue<PlatformSummaryViewModel>(cacheKey); var cachedSummary = _cacheService.GetValue<PlatformSummaryViewModel>(cacheKey);
@@ -481,15 +473,14 @@ public class DataController : ControllerBase
return Ok(cachedSummary); return Ok(cachedSummary);
} }
// Get all agents and their strategies // Get all agents and their strategies (without time filter)
var agentsWithStrategies = await _mediator.Send(new GetAllAgentsCommand(timeFilter)); var agentsWithStrategies = await _mediator.Send(new GetAllAgentsCommand());
// Create the platform summary // Create the platform summary
var summary = new PlatformSummaryViewModel var summary = new PlatformSummaryViewModel
{ {
TotalAgents = agentsWithStrategies.Count, TotalAgents = agentsWithStrategies.Count,
TotalActiveStrategies = agentsWithStrategies.Values.Sum(list => list.Count), TotalActiveStrategies = agentsWithStrategies.Values.Sum(list => list.Count)
TimeFilter = timeFilter
}; };
// Calculate total platform metrics // Calculate total platform metrics

View File

@@ -71,11 +71,6 @@ namespace Managing.Api.Models.Responses
/// Total volume traded across all agents in the last 24 hours in USD /// Total volume traded across all agents in the last 24 hours in USD
/// </summary> /// </summary>
public decimal TotalPlatformVolumeLast24h { get; set; } public decimal TotalPlatformVolumeLast24h { get; set; }
/// <summary>
/// Time filter applied to the data
/// </summary>
public string TimeFilter { get; set; } = "Total";
} }
/// <summary> /// <summary>

View File

@@ -1980,10 +1980,8 @@ export class DataClient extends AuthorizedApiBase {
return Promise.resolve<UserStrategyDetailsViewModel>(null as any); return Promise.resolve<UserStrategyDetailsViewModel>(null as any);
} }
data_GetPlatformSummary(timeFilter: string | null | undefined): Promise<PlatformSummaryViewModel> { data_GetPlatformSummary(): Promise<PlatformSummaryViewModel> {
let url_ = this.baseUrl + "/Data/GetPlatformSummary?"; let url_ = this.baseUrl + "/Data/GetPlatformSummary";
if (timeFilter !== undefined && timeFilter !== null)
url_ += "timeFilter=" + encodeURIComponent("" + timeFilter) + "&";
url_ = url_.replace(/[?&]$/, ""); url_ = url_.replace(/[?&]$/, "");
let options_: RequestInit = { let options_: RequestInit = {
@@ -4579,7 +4577,6 @@ export interface PlatformSummaryViewModel {
totalPlatformPnL?: number; totalPlatformPnL?: number;
totalPlatformVolume?: number; totalPlatformVolume?: number;
totalPlatformVolumeLast24h?: number; totalPlatformVolumeLast24h?: number;
timeFilter?: string | null;
} }
export interface PaginatedAgentIndexResponse { export interface PaginatedAgentIndexResponse {

View File

@@ -967,7 +967,6 @@ export interface PlatformSummaryViewModel {
totalPlatformPnL?: number; totalPlatformPnL?: number;
totalPlatformVolume?: number; totalPlatformVolume?: number;
totalPlatformVolumeLast24h?: number; totalPlatformVolumeLast24h?: number;
timeFilter?: string | null;
} }
export interface PaginatedAgentIndexResponse { export interface PaginatedAgentIndexResponse {

View File

@@ -9,6 +9,7 @@ import BestAgents from './analytics/bestAgents'
import AgentSearch from './agentSearch' import AgentSearch from './agentSearch'
import AgentIndex from './agentIndex' import AgentIndex from './agentIndex'
import AgentStrategy from './agentStrategy' import AgentStrategy from './agentStrategy'
import PlatformSummary from './platformSummary'
const tabs: ITabsType = [ const tabs: ITabsType = [
{ {
@@ -41,6 +42,11 @@ const tabs: ITabsType = [
index: 6, index: 6,
label: 'Agent Strategy', label: 'Agent Strategy',
}, },
{
Component: PlatformSummary,
index: 7,
label: 'Platform Summary',
},
] ]
const Dashboard: React.FC = () => { const Dashboard: React.FC = () => {

View File

@@ -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<PlatformSummaryViewModel | null>(null)
const [strategiesStats, setStrategiesStats] = useState<StrategiesStatisticsViewModel | null>(null)
const [topStrategies, setTopStrategies] = useState<TopStrategiesViewModel | null>(null)
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<string | null>(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 (
<span className="text-green-500">
+{change} Today
</span>
)
} else if (change < 0) {
return (
<span className="text-red-500">
{change} Today
</span>
)
}
return (
<span className="text-gray-500">
No change
</span>
)
}
if (isLoading) {
return (
<div className="flex justify-center items-center min-h-96">
<div className="loading loading-spinner loading-lg"></div>
</div>
)
}
if (error) {
return (
<div className="alert alert-error">
<span>{error}</span>
</div>
)
}
return (
<div className="p-6 bg-base-100 min-h-screen">
{/* Header */}
<div className="mb-8">
<h1 className="text-4xl font-bold text-white mb-2">
{formatNumber(strategiesStats?.totalStrategiesRunning || 0)} Strategies Deployed
</h1>
<div className="text-lg">
{strategiesStats && formatChangeIndicator(strategiesStats.changeInLast24Hours || 0)}
</div>
</div>
{/* Main Stats Grid */}
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6 mb-8">
{/* Total Volume Traded */}
<div className="bg-base-200 rounded-lg p-6">
<h3 className="text-lg font-semibold text-gray-400 mb-2">Total Volume Traded</h3>
<div className="text-3xl font-bold text-white mb-1">
{formatCurrency(platformData?.totalPlatformVolume || 0)}
</div>
<div className="text-green-500">
+{formatCurrency(platformData?.totalPlatformVolumeLast24h || 0)} Today
</div>
{/* Simple chart placeholder - you can replace with actual chart */}
<div className="mt-4 h-16 flex items-end">
<div className="w-full h-8 bg-green-500 rounded opacity-20"></div>
</div>
</div>
{/* Top 3 Most Profitable */}
<div className="bg-base-200 rounded-lg p-6">
<div className="flex items-center gap-2 mb-4">
<span className="text-2xl">🤑</span>
<h3 className="text-lg font-semibold text-gray-400">Top 3 Most Profitable</h3>
</div>
<div className="space-y-3">
{topStrategies?.topStrategies?.slice(0, 3).map((strategy, index) => (
<div key={index} className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center">
<span className="text-xs font-bold text-white">
{strategy.strategyName?.charAt(0) || 'S'}
</span>
</div>
<div>
<div className="text-sm text-white font-medium">
{strategy.strategyName || '[Strategy Name]'}
</div>
<div className="text-xs text-gray-400">📧</div>
</div>
</div>
<div className={`text-sm font-bold ${strategy.pnL && strategy.pnL >= 0 ? 'text-green-500' : 'text-red-500'}`}>
{strategy.pnL && strategy.pnL >= 0 ? '+' : ''}{formatCurrency(strategy.pnL || 0)}
</div>
</div>
)) || (
<div className="text-gray-500 text-sm">No profitable strategies found</div>
)}
</div>
</div>
{/* Top 3 Rising (placeholder - using same data for now) */}
<div className="bg-base-200 rounded-lg p-6">
<div className="flex items-center gap-2 mb-4">
<span className="text-2xl">📈</span>
<h3 className="text-lg font-semibold text-gray-400">Top 3 Rising</h3>
</div>
<div className="space-y-3">
{topStrategies?.topStrategies?.slice(0, 3).map((strategy, index) => (
<div key={index} className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center">
<span className="text-xs font-bold text-white">
{strategy.strategyName?.charAt(0) || 'S'}
</span>
</div>
<div>
<div className="text-sm text-white font-medium">
{strategy.strategyName || '[Strategy Name]'}
</div>
<div className="text-xs text-gray-400">📧</div>
</div>
</div>
<div className="flex items-center gap-1">
<span className="text-red-500">🔴</span>
<span className="text-sm text-white">1,200</span>
</div>
</div>
)) || (
<div className="text-gray-500 text-sm">No rising strategies found</div>
)}
</div>
</div>
{/* Top 3 Strategies */}
<div className="bg-base-200 rounded-lg p-6">
<div className="flex items-center gap-2 mb-4">
<span className="text-2xl"></span>
<h3 className="text-lg font-semibold text-gray-400">Top 3 Strategies</h3>
</div>
<div className="space-y-3">
{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 (
<div key={index} className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-yellow-500 rounded-full flex items-center justify-center">
<span className="text-xs font-bold text-black"></span>
</div>
<div>
<div className="text-sm text-white font-medium">
{strategy.strategyName || '[Strategy Name]'}
</div>
</div>
</div>
<div className="text-green-500 text-sm font-bold">
+{percentage}%
</div>
</div>
)
}) || (
<div className="text-gray-500 text-sm">No strategies found</div>
)}
</div>
</div>
</div>
{/* Platform Summary Stats */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="bg-base-200 rounded-lg p-6">
<h3 className="text-lg font-semibold text-gray-400 mb-2">Total Agents</h3>
<div className="text-3xl font-bold text-white">
{formatNumber(platformData?.totalAgents || 0)}
</div>
</div>
<div className="bg-base-200 rounded-lg p-6">
<h3 className="text-lg font-semibold text-gray-400 mb-2">Active Strategies</h3>
<div className="text-3xl font-bold text-white">
{formatNumber(platformData?.totalActiveStrategies || 0)}
</div>
</div>
<div className="bg-base-200 rounded-lg p-6">
<h3 className="text-lg font-semibold text-gray-400 mb-2">Total Platform PnL</h3>
<div className={`text-3xl font-bold ${(platformData?.totalPlatformPnL || 0) >= 0 ? 'text-green-500' : 'text-red-500'}`}>
{(platformData?.totalPlatformPnL || 0) >= 0 ? '+' : ''}{formatCurrency(platformData?.totalPlatformPnL || 0)}
</div>
</div>
</div>
</div>
)
}
export default PlatformSummary