feat: Add Phase 4 advanced metrics and components
- Add advanced metrics dashboard with trade analytics - Add new trading components (EntryTypeAnalysis, MultiDayPositionTracker, NewsEventTracker, etc.) - Add strategy mode selector and trend confirmation - Add risk automation panel and slippage correlation analysis - Add daily trading plan enhancements with modal components - Add custom hooks (useApi, useLocalStorage, useAdvancedTradeMetrics) - Add broker service integration and trading API - Add test setup and vitest configuration - Include parquet data files for live market data - Add comprehensive documentation in docs/ folder
This commit is contained in:
@@ -0,0 +1,455 @@
|
||||
# UI Refactoring - Implementation Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This document provides a detailed breakdown of how to refactor the App.tsx from a 3-tab workflow (Prep/Trade/Review + 4 legacy tabs) into a clean 5-view navigation system.
|
||||
|
||||
## Current State (App.tsx - 859 lines)
|
||||
|
||||
```
|
||||
App.tsx (Current Problems)
|
||||
├── Imports (HabitTracker, MLPatternRecognition, DecisionLogPanel - unused in focused flow)
|
||||
├── Types: MainTab = 'Prep' | 'Trade' | 'Review'
|
||||
├── Types: LegacyTab = 'AI Coach' | 'ML Patterns' | 'Settings' | 'Prompts'
|
||||
├── State Management (1 activeTab + 1 legacyTab = scattered focus)
|
||||
├── renderPrepTab() - lots of panels
|
||||
├── renderTradeTab() - execution cockpit
|
||||
├── renderReviewTab() - analytics
|
||||
└── renderLegacyPanels() - HIDDEN FEATURES (problem!)
|
||||
```
|
||||
|
||||
### Issues with Current Structure
|
||||
|
||||
```tsx
|
||||
// PROBLEM 1: Scattered state
|
||||
const [activeTab, setActiveTab] = useState<MainTab>('Trade')
|
||||
const [legacyTab, setLegacyTab] = useState<LegacyTab>('AI Coach') // Two separate navigations!
|
||||
|
||||
// PROBLEM 2: Hidden features at bottom
|
||||
const renderLegacyPanels = () => (
|
||||
<div className="rounded-3xl border border-slate-800...">
|
||||
<p className="text-xs uppercase tracking-[0.3em] text-slate-500">Need something familiar?</p>
|
||||
<h3 className="text-lg font-semibold text-white">Legacy views stay close by</h3>
|
||||
{/* AI Coach, ML Patterns, Settings, Prompts hidden in tabs */}
|
||||
</div>
|
||||
)
|
||||
|
||||
// PROBLEM 3: Duplicate component usage
|
||||
<DailyChecklistPanel /> vs <DailyChecklist /> - which one to use?
|
||||
<RiskManagement /> alongside <RiskAutomationPanel /> - overlapping concerns
|
||||
<AnalyticsDashboard /> vs <AdvancedMetricsDashboard /> - two sources of truth
|
||||
```
|
||||
|
||||
## Target State (Proposed App.tsx - ~800 lines)
|
||||
|
||||
```
|
||||
App.tsx (Proposed Solution)
|
||||
├── Imports (clean, no unused components)
|
||||
├── Types: MainView = 'dashboard' | 'trade' | 'journal' | 'ai' | 'settings'
|
||||
├── NavItems configuration with icons and descriptions
|
||||
├── State Management (single activeView, cleaner)
|
||||
├── Callbacks (shared across all views)
|
||||
├── View Functions:
|
||||
│ ├── renderDashboard() - Market Prep & Overview
|
||||
│ ├── renderTrade() - Live Execution Cockpit
|
||||
│ ├── renderJournal() - Post-Trading Analysis
|
||||
│ ├── renderAI() - AI Coaching & Prompts (consolidated)
|
||||
│ └── renderSettings() - Configuration & Profile Setup
|
||||
├── Sticky Navigation Bar (primary UI)
|
||||
├── Quick Trade Drawer (accessible from all views)
|
||||
└── renderActiveView() - simple switch statement
|
||||
```
|
||||
|
||||
## Code Transformation Guide
|
||||
|
||||
### Step 1: Update Type Definitions
|
||||
|
||||
**BEFORE:**
|
||||
```tsx
|
||||
type MainTab = 'Prep' | 'Trade' | 'Review'
|
||||
type LegacyTab = 'AI Coach' | 'ML Patterns' | 'Settings' | 'Prompts'
|
||||
|
||||
type WorkflowTabConfig = {
|
||||
id: MainTab
|
||||
label: string
|
||||
description: string
|
||||
icon: JSX.Element
|
||||
}
|
||||
|
||||
const workflowTabs: WorkflowTabConfig[] = [...]
|
||||
const legacyTabs: Array<{ id: LegacyTab; label: string; description: string }> = [...]
|
||||
```
|
||||
|
||||
**AFTER:**
|
||||
```tsx
|
||||
type MainView = 'dashboard' | 'trade' | 'journal' | 'ai' | 'settings'
|
||||
|
||||
interface NavItem {
|
||||
id: MainView
|
||||
label: string
|
||||
icon: JSX.Element
|
||||
description: string
|
||||
}
|
||||
|
||||
const navItems: NavItem[] = [
|
||||
{ id: 'dashboard', label: 'Dashboard', icon: <BarChart3 className="w-5 h-5" />, description: 'Market overview & prep' },
|
||||
{ id: 'trade', label: 'Trade', icon: <Activity className="w-5 h-5" />, description: 'Execute & manage positions' },
|
||||
{ id: 'journal', label: 'Journal', icon: <CalendarDays className="w-5 h-5" />, description: 'Review & analytics' },
|
||||
{ id: 'ai', label: 'AI Coach', icon: <Brain className="w-5 h-5" />, description: 'AI insights & coaching' },
|
||||
{ id: 'settings', label: 'Settings', icon: <Settings className="w-5 h-5" />, description: 'Configure preferences' },
|
||||
]
|
||||
```
|
||||
|
||||
### Step 2: Simplify State
|
||||
|
||||
**BEFORE:**
|
||||
```tsx
|
||||
const [activeTab, setActiveTab] = useState<MainTab>('Trade')
|
||||
const [legacyTab, setLegacyTab] = useState<LegacyTab>('AI Coach')
|
||||
const [tourActive, setTourActive] = useState(false)
|
||||
const [tourCounter, setTourCounter] = useState(60)
|
||||
// ... 30+ more state variables
|
||||
```
|
||||
|
||||
**AFTER:**
|
||||
```tsx
|
||||
const [activeView, setActiveView] = useState<MainView>('dashboard')
|
||||
const [showQuickTrade, setShowQuickTrade] = useState(false)
|
||||
// ... same number of feature state variables, just cleaner organization
|
||||
```
|
||||
|
||||
### Step 3: Remove Complex Hero/Workflow Display
|
||||
|
||||
**BEFORE:**
|
||||
```tsx
|
||||
// ~100+ lines of workflowHero with tab progression UI
|
||||
const workflowHero = (
|
||||
<div className="bg-slate-900 text-white rounded-3xl border border-slate-800 p-6 space-y-6 shadow-2xl">
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<div className="inline-flex items-center gap-2 rounded-full bg-amber-400/20 px-3 py-1 text-amber-200 text-sm font-semibold">
|
||||
<Sparkles className="w-4 h-4" aria-hidden="true" />
|
||||
Trader-first workflow
|
||||
</div>
|
||||
<button type="button" onClick={() => setTourActive((prev) => !prev)} ...>
|
||||
{tourActive ? `Guided tour · ${tourCounter}s` : 'Ask Copilot to guide me'}
|
||||
</button>
|
||||
</div>
|
||||
{/* Grid of workflow tabs... */}
|
||||
</div>
|
||||
)
|
||||
|
||||
// Used in return:
|
||||
<section className="space-y-6">
|
||||
{workflowHero}
|
||||
{renderActiveTab()}
|
||||
</section>
|
||||
```
|
||||
|
||||
**AFTER:**
|
||||
```tsx
|
||||
// Replace with simple, clean navigation in sticky header
|
||||
<nav className="sticky top-0 z-50 border-b border-slate-800 bg-slate-950/95 backdrop-blur-sm">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Logo */}
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="p-1.5 rounded-lg bg-amber-500/20">
|
||||
<TrendingUp className="w-5 h-5 text-amber-400" />
|
||||
</div>
|
||||
<span className="text-lg font-bold text-amber-400">Gold Trading</span>
|
||||
</div>
|
||||
|
||||
{/* Main Navigation */}
|
||||
<div className="hidden md:flex items-center gap-1 ml-8">
|
||||
{navItems.map((item) => (
|
||||
<button
|
||||
key={item.id}
|
||||
onClick={() => setActiveView(item.id)}
|
||||
className={cx(
|
||||
'flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-all',
|
||||
activeView === item.id
|
||||
? 'bg-amber-500/20 text-amber-300'
|
||||
: 'text-slate-400 hover:text-white hover:bg-slate-800'
|
||||
)}
|
||||
>
|
||||
{item.icon}{item.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Side - Status & Quick Actions */}
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="hidden sm:flex items-center gap-2 px-3 py-1.5 rounded-lg bg-slate-800 border border-slate-700">
|
||||
<span className="w-2 h-2 rounded-full bg-emerald-400 animate-pulse" />
|
||||
<span className="text-sm font-medium text-white">{formatUsd(currentPrice)}</span>
|
||||
</div>
|
||||
|
||||
{hasPosition && (
|
||||
<div className={cx(
|
||||
'hidden sm:flex items-center gap-2 px-3 py-1.5 rounded-lg',
|
||||
portfolio.totalPnl >= 0 ? 'bg-emerald-500/10 text-emerald-300' : 'bg-red-500/10 text-red-300'
|
||||
)}>
|
||||
<span className="text-sm font-medium">
|
||||
{portfolio.totalPnl >= 0 ? '+' : ''}{formatUsd(portfolio.totalPnl)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={() => setShowQuickTrade(!showQuickTrade)}
|
||||
className="flex items-center gap-2 px-4 py-2 rounded-lg bg-amber-500 hover:bg-amber-400 text-slate-900 font-medium transition-colors"
|
||||
>
|
||||
<Activity className="w-4 h-4" />
|
||||
<span className="hidden sm:inline">Quick Trade</span>
|
||||
</button>
|
||||
|
||||
<NotificationCenter />
|
||||
|
||||
<div className="text-xs text-slate-500 hidden lg:block">
|
||||
{backendStatus ? (
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400" />
|
||||
API Connected
|
||||
</span>
|
||||
) : (
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-amber-400 animate-pulse" />
|
||||
Connecting...
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
```
|
||||
|
||||
### Step 4: Consolidate View Rendering
|
||||
|
||||
**BEFORE:**
|
||||
```tsx
|
||||
const renderPrepTab = () => (...) // ~20 lines
|
||||
const renderTradeTab = () => (...) // ~25 lines
|
||||
const renderReviewTab = () => (...) // ~40 lines
|
||||
const renderLegacyPanels = () => (...) // ~45 lines - COMPLEX, HIDDEN
|
||||
|
||||
const renderActiveTab = () => {
|
||||
switch (activeTab) {
|
||||
case 'Prep': return renderPrepTab()
|
||||
case 'Trade': return renderTradeTab()
|
||||
case 'Review': return renderReviewTab()
|
||||
default: return null
|
||||
}
|
||||
}
|
||||
|
||||
// In return:
|
||||
<section className="space-y-6">
|
||||
{renderActiveTab()}
|
||||
</section>
|
||||
|
||||
{renderLegacyPanels()} {/* Always rendered at bottom! */}
|
||||
```
|
||||
|
||||
**AFTER:**
|
||||
```tsx
|
||||
// Dashboard - Morning Prep & Overview
|
||||
const renderDashboard = () => (
|
||||
<div className="space-y-6">
|
||||
{/* Quick Stats Cards */}
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
||||
<QuickStatCard title="Gold Price" value={formatUsd(currentPrice)} ... />
|
||||
<QuickStatCard title="Portfolio Value" value={formatUsd(portfolio.totalValue)} ... />
|
||||
<QuickStatCard title="Today's P&L" value={...} ... />
|
||||
<QuickStatCard title="Available Cash" value={formatUsd(portfolio.cash)} ... />
|
||||
</div>
|
||||
|
||||
{/* Main Content Grid */}
|
||||
<div className="grid gap-6 xl:grid-cols-3">
|
||||
<div className="xl:col-span-2 space-y-6">
|
||||
<LiveMarketPanel />
|
||||
<div className="grid gap-6 md:grid-cols-2">
|
||||
<AlertsPanel />
|
||||
<NewsFeed />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<DailyChecklistPanel checklistType="morning" />
|
||||
<DailyMarketSummary currentPrice={currentPrice} />
|
||||
<DailyTradingPlan
|
||||
currentPrice={currentPrice}
|
||||
onPlanUpdate={() => setActiveView('trade')}
|
||||
advancedTrades={advancedTrades}
|
||||
advancedTradesSource={advancedTradeSource}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
// Trade - Live Execution
|
||||
const renderTrade = () => (
|
||||
<div className="space-y-6">
|
||||
<MultiChartSSEPanel />
|
||||
<div className="grid gap-6 xl:grid-cols-3">
|
||||
<div className="space-y-6">
|
||||
<TradeControls {...props} />
|
||||
<RiskManagement {...props} variant="embedded" />
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<PortfolioTracker {...props} />
|
||||
<AIAnalysisPanel {...props} />
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<RiskAutomationPanel {...props} variant="embedded" />
|
||||
<BrokerBridgePanel {...props} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
// Journal - Post-Trading Analysis
|
||||
const renderJournal = () => (
|
||||
<div className="space-y-6">
|
||||
<div className="rounded-2xl border border-slate-800 bg-slate-900/60 p-6">
|
||||
<div className="flex flex-wrap items-center justify-between gap-4 mb-4">
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-white">Performance Analytics</h2>
|
||||
<p className="text-sm text-slate-400">
|
||||
{advancedTradeSource === 'live'
|
||||
? `Analyzing ${advancedTrades.length} trades from your session`
|
||||
: 'Sample data shown until you complete trades'}
|
||||
</p>
|
||||
</div>
|
||||
<span className={cx(
|
||||
'px-3 py-1 rounded-full text-xs font-medium',
|
||||
advancedTradeSource === 'live' ? 'bg-emerald-500/20 text-emerald-300' : 'bg-amber-500/20 text-amber-300'
|
||||
)}>
|
||||
{advancedTradeSource === 'live' ? 'Live Data' : 'Sample Preview'}
|
||||
</span>
|
||||
</div>
|
||||
<AdvancedMetricsDashboard {...props} />
|
||||
</div>
|
||||
<div className="grid gap-6 xl:grid-cols-2">
|
||||
<div className="space-y-6">
|
||||
<TradingJournal />
|
||||
<EquityPerformancePanel />
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<AnalyticsDashboard />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
// AI Coach - Consolidated AI Features
|
||||
const renderAI = () => (
|
||||
<div className="space-y-6">
|
||||
<div className="rounded-2xl border border-slate-800 bg-gradient-to-br from-slate-900 to-slate-950 p-6">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="p-2 rounded-xl bg-purple-500/20">
|
||||
<Brain className="w-6 h-6 text-purple-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-white">AI Trading Coach</h2>
|
||||
<p className="text-sm text-slate-400">Get personalized coaching and insights</p>
|
||||
</div>
|
||||
</div>
|
||||
<AITradingCoach />
|
||||
</div>
|
||||
<div className="grid gap-6 md:grid-cols-2">
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-lg font-semibold text-white">Quick Analysis</h3>
|
||||
<AIAnalysisPanel analysis={aiAnalysis} isLoading={isAnalyzing} title="Market Analysis" />
|
||||
<button onClick={handleRunAnalysis} disabled={isAnalyzing} className="...">
|
||||
Run AI Analysis
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-lg font-semibold text-white">Prompt Templates</h3>
|
||||
<PromptTemplatesPanel />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
// Settings - Configuration
|
||||
const renderSettings = () => (
|
||||
<div className="space-y-6">
|
||||
<div className="rounded-2xl border border-slate-800 bg-slate-900/60 p-6">
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<div className="p-2 rounded-xl bg-slate-700">
|
||||
<Settings className="w-6 h-6 text-slate-300" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-white">Settings</h2>
|
||||
<p className="text-sm text-slate-400">Configure your trading preferences</p>
|
||||
</div>
|
||||
</div>
|
||||
<SettingsPanel />
|
||||
</div>
|
||||
<button onClick={() => setShowProfileSetup(true)} className="...">
|
||||
Trading Profile Setup
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
|
||||
const renderActiveView = () => {
|
||||
switch (activeView) {
|
||||
case 'dashboard': return renderDashboard()
|
||||
case 'trade': return renderTrade()
|
||||
case 'journal': return renderJournal()
|
||||
case 'ai': return renderAI()
|
||||
case 'settings': return renderSettings()
|
||||
default: return null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Components to Remove from Imports
|
||||
|
||||
These are currently imported but can be removed or reorganized:
|
||||
|
||||
```tsx
|
||||
// REMOVE (used in legacy panels, consolidated elsewhere):
|
||||
import HabitTracker from './components/HabitTracker'
|
||||
import DecisionLogPanel from './components/DecisionLogPanel'
|
||||
import MLPatternRecognition from './components/MLPatternRecognition'
|
||||
|
||||
// KEEP (still used, just organized differently):
|
||||
import AITradingCoach from './components/AITradingCoach'
|
||||
import PromptTemplatesPanel from './components/PromptTemplatesPanel'
|
||||
import SettingsPanel from './components/SettingsPanel'
|
||||
```
|
||||
|
||||
## Files Modified
|
||||
|
||||
- **App.tsx**: Main refactoring (~60 lines removed, ~200 lines reorganized)
|
||||
- **package.json**: No changes needed
|
||||
- **Component files**: No changes (they stay the same, just reused in different places)
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] All 5 navigation items clickable and visible
|
||||
- [ ] State persists when navigating between views
|
||||
- [ ] Dashboard shows correct stats and components
|
||||
- [ ] Trade view has all execution tools
|
||||
- [ ] Journal shows analytics
|
||||
- [ ] AI Coach displays training features
|
||||
- [ ] Settings allows configuration
|
||||
- [ ] Quick Trade button works from navbar
|
||||
- [ ] Mobile responsive (collapsed nav)
|
||||
- [ ] Sticky header position correct
|
||||
- [ ] Price ticker updates live
|
||||
- [ ] P&L badge shows/hides correctly
|
||||
- [ ] API status indicator works
|
||||
- [ ] Profile setup modal opens
|
||||
- [ ] All callbacks work (buy/sell/reset/analyze)
|
||||
|
||||
## Result
|
||||
|
||||
**Before**: Confusing workflow with hidden features
|
||||
**After**: Clean, organized, trader-friendly interface
|
||||
|
||||
Lines removed: ~150 (complex hero, legacy panels)
|
||||
Lines added: ~80 (cleaner layouts)
|
||||
Net change: -70 lines with MORE features visible and organized
|
||||
Reference in New Issue
Block a user