learning_ai_invt_trdg/web/src/tabs/MarketplaceTab.tsx

120 lines
7.0 KiB
TypeScript

import React from 'react';
import { PresetMarketplace } from '../components/PresetMarketplace';
import type { StrategyPreset } from '../lib/PresetRegistry';
import type { BotState } from '../hooks/useWebSocket';
import { TrendingUp, Brain } from 'lucide-react';
import { PageHeader } from '../components/ui/page-header';
import { Card, CardContent } from '../components/ui/card';
interface MarketplaceTabProps {
onClone: (preset: StrategyPreset) => void;
botState: BotState;
}
export const MarketplaceTab: React.FC<MarketplaceTabProps> = ({ onClone, botState }) => {
const symbols = Object.keys(botState.symbols);
const aiSetups = symbols
.filter(s => botState.symbols[s]?.rules?.['AIAnalysisRule']?.metadata?.confidence !== undefined)
.sort((a, b) => (botState.symbols[b]?.rules?.['AIAnalysisRule']?.metadata?.confidence || 0) - (botState.symbols[a]?.rules?.['AIAnalysisRule']?.metadata?.confidence || 0))
.slice(0, 5);
const topVolatile = [...symbols]
.sort((a, b) => Math.abs(botState.symbols[b].change24h || 0) - Math.abs(botState.symbols[a].change24h || 0))
.slice(0, 6);
return (
<div style={{ animation: 'fadeIn 0.5s ease-out' }}>
<PageHeader
title="Marketplace"
description="Explore curated strategy presets and compare them against current market context."
/>
{/* Contextual Intelligence Row */}
<div style={{
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: '20px',
maxWidth: '1400px',
margin: '24px auto 0 auto',
padding: '0 20px'
}}>
{/* AI Best Setups Panel */}
<Card className="hero-surface">
<CardContent style={{ padding: '24px 28px' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '20px' }}>
<div style={{ width: '32px', height: '32px', borderRadius: '10px', background: 'var(--accent-soft)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Brain size={16} color="var(--accent)" />
</div>
<div>
<div className="section-title">Best AI Setups</div>
<div style={{ fontSize: '10px', color: 'var(--muted-foreground)', fontWeight: 700, marginTop: '1px' }}>High-confidence signals find the right strategy below</div>
</div>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
{aiSetups.map(s => {
const conf = botState.symbols[s]?.rules['AIAnalysisRule']?.metadata?.confidence || 0;
return (
<div key={s} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 14px', background: 'var(--card-elevated)', borderRadius: '12px', border: '1px solid var(--border)' }}>
<span style={{ fontWeight: 800, fontSize: '13px', color: 'var(--foreground)' }}>{s}</span>
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<div style={{ width: `${Math.min(conf, 60)}px`, height: '3px', background: `hsl(${conf * 1.2}, 100%, 55%)`, borderRadius: '99px' }} />
<span style={{ fontSize: '12px', fontWeight: 900, color: 'var(--accent)', fontFamily: 'monospace' }}>{conf}%</span>
</div>
</div>
);
})}
{aiSetups.length === 0 && (
<div style={{ textAlign: 'center', padding: '20px', color: 'var(--muted-foreground)', fontSize: '12px', fontStyle: 'italic' }}>AI analysis scanning markets...</div>
)}
</div>
</CardContent>
</Card>
{/* Top Volatile Panel */}
<Card className="hero-surface">
<CardContent style={{ padding: '24px 28px' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '20px' }}>
<div style={{ width: '32px', height: '32px', borderRadius: '10px', background: 'var(--bl-warning-muted)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<TrendingUp size={16} color="var(--bl-warning)" />
</div>
<div>
<div className="section-title">Top Volatile (24h)</div>
<div style={{ fontSize: '10px', color: 'var(--muted-foreground)', fontWeight: 700, marginTop: '1px' }}>Most active markets match with strategies below</div>
</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px' }}>
{topVolatile.map(s => {
const change = botState.symbols[s]?.change24h || 0;
return (
<div key={s} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 14px', background: 'var(--card-elevated)', borderRadius: '12px', border: '1px solid var(--border)' }}>
<span style={{ fontWeight: 800, fontSize: '12px', color: 'var(--foreground)' }}>{s.split('/')[0]}</span>
<span style={{ fontSize: '12px', fontWeight: 900, fontFamily: 'monospace', color: change >= 0 ? 'var(--bl-success)' : 'var(--bl-danger)' }}>
{change >= 0 ? '+' : ''}{change.toFixed(2)}%
</span>
</div>
);
})}
{topVolatile.length === 0 && (
<div style={{ gridColumn: '1/-1', textAlign: 'center', padding: '20px', color: 'var(--muted-foreground)', fontSize: '12px', fontStyle: 'italic' }}>Scanning markets...</div>
)}
</div>
</CardContent>
</Card>
</div>
{/* Strategy Marketplace Grid */}
<div style={{ maxWidth: '1400px', margin: '0 auto', padding: '0 0 40px 0' }}>
<PresetMarketplace onSelect={onClone} />
</div>
<style>{`
@keyframes fadeIn {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
`}</style>
</div>
);
};