192 lines
7.1 KiB
TypeScript
192 lines
7.1 KiB
TypeScript
/**
|
|
* Investment Page - STC Theme (Gold/Black)
|
|
*/
|
|
|
|
import { FC, useState } from 'react';
|
|
import { useAgents, useAllocations, useInvestmentSummary } from '../hooks/useInvestment';
|
|
import { AgentCard, AllocationCard, AllocationModal } from '../components';
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
import type { AgentConfig, AllocationWithAgent, AgentType } from '../types';
|
|
|
|
export const InvestmentPage: FC = () => {
|
|
const [showModal, setShowModal] = useState(false);
|
|
const [selectedAgent, setSelectedAgent] = useState<AgentConfig | null>(null);
|
|
const [selectedAllocation, setSelectedAllocation] = useState<AllocationWithAgent | null>(null);
|
|
|
|
const { data: agents, isLoading: agentsLoading } = useAgents();
|
|
const { data: allocations, isLoading: allocationsLoading } = useAllocations();
|
|
const { data: summary } = useInvestmentSummary();
|
|
|
|
const handleAllocate = (agentType: AgentType) => {
|
|
const agent = agents?.find((a) => a.agentType === agentType);
|
|
const existingAllocation = allocations?.find(
|
|
(a) => a.agentType === agentType && a.status === 'active'
|
|
);
|
|
|
|
setSelectedAgent(agent || null);
|
|
setSelectedAllocation(existingAllocation || null);
|
|
setShowModal(true);
|
|
};
|
|
|
|
const handleManageAllocation = (allocation: AllocationWithAgent) => {
|
|
const agent = agents?.find((a) => a.agentType === allocation.agentType);
|
|
setSelectedAgent(agent || null);
|
|
setSelectedAllocation(allocation);
|
|
setShowModal(true);
|
|
};
|
|
|
|
const handleCloseModal = () => {
|
|
setShowModal(false);
|
|
setSelectedAgent(null);
|
|
setSelectedAllocation(null);
|
|
};
|
|
|
|
// Get allocation value by agent type
|
|
const getAllocationValue = (agentType: AgentType) => {
|
|
const allocation = allocations?.find(
|
|
(a) => a.agentType === agentType && a.status === 'active'
|
|
);
|
|
return allocation?.currentValue || 0;
|
|
};
|
|
|
|
if (agentsLoading || allocationsLoading) {
|
|
return (
|
|
<div className="min-h-screen bg-background p-6">
|
|
<div className="max-w-6xl mx-auto">
|
|
<div className="space-y-6">
|
|
<Skeleton className="h-32 w-full bg-primary-800" />
|
|
<div className="grid grid-cols-3 gap-6">
|
|
{[1, 2, 3].map((i) => (
|
|
<Skeleton key={i} className="h-96 w-full bg-primary-800" />
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const activeAllocations = allocations?.filter((a) => a.status === 'active') || [];
|
|
|
|
return (
|
|
<div className="min-h-screen bg-background p-6">
|
|
<div className="max-w-6xl mx-auto space-y-8">
|
|
{/* Header */}
|
|
<div>
|
|
<h1 className="text-3xl font-bold text-white">
|
|
Investment <span className="text-gold">Agents</span>
|
|
</h1>
|
|
<p className="text-gray-400 mt-1">
|
|
Allocate funds to AI-powered trading agents
|
|
</p>
|
|
</div>
|
|
|
|
{/* Portfolio Summary */}
|
|
{summary && (summary.totalAllocated > 0 || activeAllocations.length > 0) && (
|
|
<div className="bg-gradient-to-r from-gold/20 to-primary-700/50 rounded-xl border border-gold/30 p-6">
|
|
<h2 className="text-lg font-semibold text-white mb-4">Your Portfolio</h2>
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div>
|
|
<p className="text-gray-400 text-sm">Total Allocated</p>
|
|
<p className="text-2xl font-bold text-white">
|
|
${summary.totalAllocated.toLocaleString()}
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-gray-400 text-sm">Current Value</p>
|
|
<p className="text-2xl font-bold text-gold">
|
|
${summary.currentValue.toLocaleString()}
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-gray-400 text-sm">Total P&L</p>
|
|
<p className={`text-2xl font-bold ${summary.totalPnl >= 0 ? 'text-green-400' : 'text-red-400'}`}>
|
|
{summary.totalPnl >= 0 ? '+' : ''}${summary.totalPnl.toFixed(2)}
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-gray-400 text-sm">Return</p>
|
|
<p className={`text-2xl font-bold ${summary.totalPnlPercent >= 0 ? 'text-green-400' : 'text-red-400'}`}>
|
|
{summary.totalPnlPercent >= 0 ? '+' : ''}{summary.totalPnlPercent.toFixed(2)}%
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Agent Cards */}
|
|
<div>
|
|
<h2 className="text-xl font-semibold text-gold mb-4">Available Agents</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
{agents?.map((agent) => (
|
|
<AgentCard
|
|
key={agent.id}
|
|
agent={agent}
|
|
userAllocationValue={getAllocationValue(agent.agentType)}
|
|
onAllocate={handleAllocate}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Active Allocations */}
|
|
{activeAllocations.length > 0 && (
|
|
<div>
|
|
<h2 className="text-xl font-semibold text-gold mb-4">Your Allocations</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
{activeAllocations.map((allocation) => (
|
|
<AllocationCard
|
|
key={allocation.id}
|
|
allocation={allocation}
|
|
onManage={handleManageAllocation}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Info Section */}
|
|
<Card className="bg-primary-800 border-primary-700">
|
|
<CardHeader>
|
|
<CardTitle className="text-white">How It Works</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<div className="text-center">
|
|
<div className="text-4xl mb-3">1</div>
|
|
<h4 className="text-gold font-medium mb-1">Choose an Agent</h4>
|
|
<p className="text-gray-400 text-sm">
|
|
Select based on your risk tolerance and return expectations
|
|
</p>
|
|
</div>
|
|
<div className="text-center">
|
|
<div className="text-4xl mb-3">2</div>
|
|
<h4 className="text-gold font-medium mb-1">Allocate Funds</h4>
|
|
<p className="text-gray-400 text-sm">
|
|
Transfer credits from your wallet to the agent
|
|
</p>
|
|
</div>
|
|
<div className="text-center">
|
|
<div className="text-4xl mb-3">3</div>
|
|
<h4 className="text-gold font-medium mb-1">Earn Returns</h4>
|
|
<p className="text-gray-400 text-sm">
|
|
Profits are distributed monthly after fees
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* Allocation Modal */}
|
|
<AllocationModal
|
|
isOpen={showModal}
|
|
onClose={handleCloseModal}
|
|
agent={selectedAgent}
|
|
existingAllocation={selectedAllocation}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|