Files
robinhood/UI_REFACTORING_IMPLEMENTATION.md
T
Krikorios 48e60d015f 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
2025-11-27 10:23:58 +02:00

15 KiB

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

// 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:

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:

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:

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:

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:

// ~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:

// 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:

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:

// 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:

// 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