"use client" import React, { useState, useRef, useEffect } from 'react' interface TradePosition { id: string symbol: string side: 'LONG' | 'SHORT' entryPrice: number currentPrice: number amount: number unrealizedPnl: number pnlPercentage: number totalValue: number stopLoss?: number takeProfit?: number timestamp: number status: string leverage: number txId: string entryAnalysis?: string } interface ChatMessage { id: string type: 'user' | 'assistant' | 'system' content: string timestamp: string analysis?: any screenshots?: string[] } interface TradeFollowUpPanelProps { onClose: () => void } export default function TradeFollowUpPanel({ onClose }: TradeFollowUpPanelProps) { const [activePosition, setActivePosition] = useState(null) const [chatMessages, setChatMessages] = useState([]) const [currentMessage, setCurrentMessage] = useState('') const [isLoading, setIsLoading] = useState(false) const [isAnalyzing, setIsAnalyzing] = useState(false) const [systemStatus, setSystemStatus] = useState(null) const chatEndRef = useRef(null) // Auto-scroll to bottom of chat useEffect(() => { chatEndRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [chatMessages]) // Load active positions on mount useEffect(() => { const initializePanel = async () => { await loadSystemStatus() await loadActivePositions() } initializePanel() }, []) const loadSystemStatus = async () => { try { // Test multiple endpoints to get status const [statusRes, walletRes, healthRes] = await Promise.allSettled([ fetch('/api/status'), fetch('/api/wallet/balance'), fetch('/api/trading/health') ]) const systemInfo = { api: statusRes.status === 'fulfilled', wallet: walletRes.status === 'fulfilled', trading: healthRes.status === 'fulfilled', timestamp: new Date().toLocaleTimeString() } setSystemStatus(systemInfo) } catch (error) { console.error('Error loading system status:', error) } } const loadActivePositions = async () => { try { const response = await fetch('/api/trading/positions') const data = await response.json() if (data.success && data.positions?.length > 0) { // For now, take the first active position // TODO: Add position selector if multiple positions setActivePosition(data.positions[0]) // Add welcome message with system status const statusEmoji = systemStatus ? `🟢 API ${systemStatus.api ? 'āœ“' : 'āœ—'} | šŸ’° Wallet ${systemStatus.wallet ? 'āœ“' : 'āœ—'} | šŸ“ˆ Trading ${systemStatus.trading ? 'āœ“' : 'āœ—'}` : 'šŸ”„ Loading system status...' setChatMessages([{ id: Date.now().toString(), type: 'system', content: `šŸŽÆ **Trade Follow-up Assistant**\n\n**System:** ${statusEmoji}\n\n**Active Position:**\n• ${data.positions[0].symbol} ${data.positions[0].side}\n• Entry: $${data.positions[0].entryPrice} | Size: ${data.positions[0].amount}\n• P&L: ${data.positions[0].unrealizedPnl > 0 ? '+' : ''}$${data.positions[0].unrealizedPnl.toFixed(2)}\n\nAsk: "exit?", "analysis", "risk", or type your question.`, timestamp: new Date().toISOString() }]) } else { const statusEmoji = systemStatus ? `🟢 API ${systemStatus.api ? 'āœ“' : 'āœ—'} | šŸ’° Wallet ${systemStatus.wallet ? 'āœ“' : 'āœ—'} | šŸ“ˆ Trading ${systemStatus.trading ? 'āœ“' : 'āœ—'}` : 'šŸ”„ Loading system status...' setChatMessages([{ id: Date.now().toString(), type: 'system', content: `āš ļø **No Active Positions**\n\n**System:** ${statusEmoji}\n\nExecute a trade first, then mark it as traded for follow-up analysis.\n\nType "status" for system diagnostics.`, timestamp: new Date().toISOString() }]) } } catch (error) { console.error('Error loading positions:', error) setChatMessages([{ id: Date.now().toString(), type: 'system', content: `āŒ **Error Loading Positions**\n\n**System:** ${systemStatus ? `API ${systemStatus.api ? 'āœ“' : 'āœ—'} Wallet ${systemStatus.wallet ? 'āœ“' : 'āœ—'} Trading ${systemStatus.trading ? 'āœ“' : 'āœ—'}` : 'Unknown'}\n\nConnection issues detected. Type "status" for diagnostics.`, timestamp: new Date().toISOString() }]) } } const handleSendMessage = async () => { if (!currentMessage.trim() || isLoading) return const userMessage: ChatMessage = { id: Date.now().toString(), type: 'user', content: currentMessage, timestamp: new Date().toISOString() } setChatMessages(prev => [...prev, userMessage]) setCurrentMessage('') setIsLoading(true) try { // Check if user is asking for status or system information const isStatusRequest = currentMessage.toLowerCase().includes('status') || currentMessage.toLowerCase().includes('system') || currentMessage.toLowerCase().includes('health') || currentMessage.toLowerCase().includes('diagnostic') if (isStatusRequest) { // Refresh system status and provide detailed information await loadSystemStatus() const statusMessage: ChatMessage = { id: (Date.now() + 1).toString(), type: 'assistant', content: `šŸ“Š **System Status** (${new Date().toLocaleTimeString()})\n\n**Core Services:**\n• API: ${systemStatus?.api ? '🟢' : 'šŸ”“'} | Wallet: ${systemStatus?.wallet ? '🟢' : 'šŸ”“'} | Trading: ${systemStatus?.trading ? '🟢' : 'šŸ”“'}\n\n**Trading:**\n• Drift Protocol: ${systemStatus?.trading ? '🟢 Connected' : 'šŸ”“ Disconnected'}\n• Screenshot Service: ${systemStatus?.api ? '🟢 Ready' : 'šŸ”“ Not ready'}\n• AI Analysis: ${process.env.OPENAI_API_KEY ? '🟢 Ready' : 'šŸ”“ No API key'}\n\n**Container:**\n• Docker: 🟢 Running (Port 9001)\n• Database: 🟢 SQLite Connected\n\n${!activePosition ? 'āš ļø No active positions for follow-up' : 'āœ… Ready for trade management'}`, timestamp: new Date().toISOString() } setChatMessages(prev => [...prev, statusMessage]) setIsLoading(false) return } // Check if user is asking for updated analysis const needsScreenshot = currentMessage.toLowerCase().includes('analysis') || currentMessage.toLowerCase().includes('update') || currentMessage.toLowerCase().includes('current') || currentMessage.toLowerCase().includes('now') let screenshots: string[] = [] if (needsScreenshot && activePosition) { setIsAnalyzing(true) // Add thinking message const thinkingMessage: ChatMessage = { id: (Date.now() + 1).toString(), type: 'assistant', content: 'šŸ”„ **Capturing fresh screenshots and analyzing...**', timestamp: new Date().toISOString() } setChatMessages(prev => [...prev, thinkingMessage]) // Get fresh screenshots const screenshotResponse = await fetch('/api/enhanced-screenshot', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ symbol: activePosition.symbol, timeframe: '240', // 4h default for trade follow-up layouts: ['ai', 'diy'], analyze: false // We'll analyze separately with trade context }) }) const screenshotData = await screenshotResponse.json() if (screenshotData.success && screenshotData.screenshots) { screenshots = screenshotData.screenshots } setIsAnalyzing(false) } // Send to trade follow-up API const response = await fetch('/api/trade-followup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: currentMessage, position: activePosition, screenshots: screenshots, chatHistory: chatMessages.slice(-5) // Last 5 messages for context }) }) const data = await response.json() if (data.success) { const assistantMessage: ChatMessage = { id: (Date.now() + 2).toString(), type: 'assistant', content: data.response, timestamp: new Date().toISOString(), analysis: data.analysis, screenshots: screenshots } setChatMessages(prev => [...prev.filter(m => !m.content.includes('Getting Updated Analysis')), assistantMessage]) } else { throw new Error(data.error || 'Failed to get response') } } catch (error) { console.error('Error sending message:', error) const errorMessage: ChatMessage = { id: (Date.now() + 3).toString(), type: 'assistant', content: 'āŒ **Error**\n\nSorry, I encountered an error. Please try again.', timestamp: new Date().toISOString() } setChatMessages(prev => [...prev.filter(m => !m.content.includes('Getting Updated Analysis')), errorMessage]) } finally { setIsLoading(false) setIsAnalyzing(false) } } const handleKeyPress = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault() handleSendMessage() } } const formatMessage = (content: string) => { // Convert markdown-style formatting to JSX return content.split('\n').map((line, index) => { if (line.startsWith('**') && line.endsWith('**')) { return
{line.slice(2, -2)}
} if (line.startsWith('• ')) { return
{line}
} return
{line}
}) } const quickActions = [ "Exit now?", "Move stop loss", "Fresh analysis", "Risk check", "status" ] return (
{/* Header */}
šŸ’¬

Trade Follow-up Assistant

{activePosition ? (

{activePosition.symbol} {activePosition.side} • Entry: ${activePosition.entryPrice}

) : (

No active positions

)}
{/* System Status Indicator */}
{systemStatus?.api && systemStatus?.wallet && systemStatus?.trading ? 'All Systems' : 'System Issues'}
{/* Chat Messages */}
{chatMessages.map((message) => (
{formatMessage(message.content)} {/* Show screenshots if available */} {message.screenshots && message.screenshots.length > 0 && (
{message.screenshots.map((screenshot, index) => ( {`Analysis { // TODO: Open enlarged view }} /> ))}
)}
{new Date(message.timestamp).toLocaleTimeString()}
))} {isAnalyzing && (
Analyzing market conditions...
)}
{/* Quick Actions */} {activePosition && (
Quick Actions:
{quickActions.map((action, index) => ( ))}
)} {/* Message Input */}