- 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
9.1 KiB
Frontend Refactoring Quick Start Guide
🚀 What Changed?
Your frontend has been refactored to improve maintainability, type safety, and code organization. Here's what you need to know.
📦 New Shared Utilities
1. useLocalStorage Hook
Import:
import { useLocalStorage } from '@/hooks';
Usage:
// Instead of managing localStorage manually...
const [value, setValue, removeValue] = useLocalStorage<MyType>('storage-key', defaultValue);
// Works just like useState, but persists automatically!
setValue({ ...value, updated: true });
Features:
- Type-safe
- Automatic JSON serialization
- Error handling built-in
- Returns remove function as third element
2. useApi Hook
Import:
import { useApi } from '@/hooks';
Usage:
// Manages loading, error, and data states automatically
const { data, loading, error, execute } = useApi(
(id: number) => apiService.getData(id),
{
onSuccess: (data) => console.log('Success!', data),
onError: (error) => console.error('Error:', error)
}
);
// Later in your component...
<button onClick={() => execute(123)}>Load Data</button>
{loading && <Spinner />}
{error && <ErrorMessage>{error}</ErrorMessage>}
{data && <DataDisplay data={data} />}
Features:
- Automatic request cancellation on unmount
- Prevents memory leaks
- Consistent loading/error patterns
3. Formatting Utilities
Import:
import { formatCurrency, formatPercent, formatNumber, formatPriceChange } from '@/utils/indicators';
Usage:
// Currency formatting (handles null/undefined)
formatCurrency(1234.56) // "$1,234.56"
formatCurrency(null) // "—"
// Percentage with sign
formatPercent(5.25) // "+5.25%"
formatPercent(-2.5) // "-2.50%"
// Number formatting
formatNumber(1234.567) // "1,234.57"
// Price change with color
const { text, color } = formatPriceChange(5.25);
// { text: "+5.25", color: "text-green-400" }
Replace these patterns:
// ❌ Old way
const formatNumber = (value?: number | null) => {
if (value === undefined || value === null) return '—';
return new Intl.NumberFormat('en-US', { maximumFractionDigits: 2 }).format(value);
};
// ✅ New way
import { formatNumber } from '@/utils/indicators';
4. Modal Components
Import:
import { Modal, ConfirmModal, AlertModal } from '@/components/shared/Modal';
Replace confirm():
// ❌ Old way
if (confirm('Are you sure you want to delete this?')) {
handleDelete();
}
// ✅ New way
const [showConfirm, setShowConfirm] = useState(false);
<ConfirmModal
isOpen={showConfirm}
onClose={() => setShowConfirm(false)}
onConfirm={handleDelete}
title="Delete Item"
message="Are you sure you want to delete this?"
variant="danger"
/>
Replace alert():
// ❌ Old way
alert('Success! Your changes have been saved.');
// ✅ New way
const [showAlert, setShowAlert] = useState(false);
<AlertModal
isOpen={showAlert}
onClose={() => setShowAlert(false)}
title="Success"
message="Your changes have been saved."
variant="success"
/>
Custom Modal:
<Modal isOpen={open} onClose={() => setOpen(false)} title="Custom Dialog" size="lg">
<p>Your custom content here</p>
<div className="flex gap-2 mt-4">
<button onClick={handleAction}>Action</button>
<button onClick={() => setOpen(false)}>Cancel</button>
</div>
</Modal>
Modal Props:
size: 'sm' | 'md' | 'lg' | 'xl'showCloseButton: boolean (default: true)closeOnEscape: boolean (default: true)closeOnBackdropClick: boolean (default: true)
🏗️ New Component Structure
DailyTradingPlan Refactored
Location changed:
// ❌ Old import
import DailyTradingPlan from './components/DailyTradingPlan';
// ✅ New import
import DailyTradingPlan from './components/features/trading/DailyTradingPlan';
Props unchanged - no breaking changes!
Internal structure:
DailyTradingPlan/
├── index.tsx # Main container
├── types.ts # TypeScript interfaces
├── usePlanGeneration.ts # AI logic hook
├── PlanHeader.tsx # Sub-component
├── PlanBiasSelector.tsx # Sub-component
├── PlanRiskParameters.tsx # Sub-component
└── PlanKeyLevelsEditor.tsx # Sub-component
🎨 Patterns to Follow
1. Component Organization
components/
├── features/ # Feature-specific components
│ ├── trading/
│ ├── analytics/
│ ├── ai/
│ └── journal/
├── shared/ # Reusable UI components
│ ├── Modal.tsx
│ ├── Button.tsx
│ └── Input.tsx
└── layout/ # Layout components
└── DashboardLayout.tsx
2. Component File Structure
For complex components, create a directory:
MyComponent/
├── index.tsx # Main container
├── types.ts # TypeScript interfaces
├── useMyLogic.ts # Custom hooks
├── SubComponentA.tsx # Sub-component
└── SubComponentB.tsx # Sub-component
Export from index.tsx:
export default function MyComponent() { ... }
export type { MyComponentProps } from './types';
3. Custom Hooks Pattern
// useMyFeature.ts
import { useState, useCallback } from 'react';
export interface UseMyFeatureReturn {
data: MyData | null;
loading: boolean;
error: string | null;
execute: () => Promise<void>;
reset: () => void;
}
export function useMyFeature(): UseMyFeatureReturn {
const [data, setData] = useState<MyData | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const execute = useCallback(async () => {
setLoading(true);
setError(null);
try {
const result = await fetchData();
setData(result);
} catch (err) {
setError(err instanceof Error ? err.message : 'Unknown error');
} finally {
setLoading(false);
}
}, []);
const reset = useCallback(() => {
setData(null);
setError(null);
}, []);
return { data, loading, error, execute, reset };
}
4. TypeScript Best Practices
// ✅ Do: Explicit interfaces
interface MyComponentProps {
value: number;
onChange: (value: number) => void;
label?: string;
}
// ✅ Do: Explicit return types
function MyComponent({ value, onChange, label }: MyComponentProps): JSX.Element {
const handleChange = useCallback((newValue: number): void => {
onChange(newValue);
}, [onChange]);
return <div>...</div>;
}
// ❌ Don't: Use 'any'
const [data, setData] = useState<any>(null); // Bad!
// ✅ Do: Use proper types
interface MyData {
id: number;
name: string;
}
const [data, setData] = useState<MyData | null>(null); // Good!
🔧 Migration Checklist
When refactoring a component:
- Move to appropriate feature directory
- Extract types to
types.ts - Extract business logic to custom hooks
- Split into sub-components (if > 250 lines)
- Replace
localStoragepatterns withuseLocalStorage - Replace direct API calls with
useApi - Replace
alert/confirmwith Modal components - Use formatting utilities from
@/utils/indicators - Remove all
anytypes - Add explicit return types
- Wrap callbacks in
useCallback - Wrap expensive calculations in
useMemo - Add ARIA attributes for accessibility
- Update imports in parent components
🧪 Testing Your Changes
Quick Smoke Test:
cd frontend
npm run build
Should compile without TypeScript errors!
Runtime Test:
npm run dev
Check:
- Component loads without errors
- State updates work
- localStorage persists
- Modals open/close correctly
- No console warnings
📚 Additional Resources
❓ FAQ
Q: Can I still use the old DailyTradingPlan import? A: No, update imports to the new location. The old file will be removed.
Q: Do I need to refactor all components at once? A: No! Refactor incrementally. Start with components you're actively working on.
Q: What if I need localStorage outside a component? A: Create a separate utility function or use the hook in the nearest parent component.
Q: Should I use ConfirmModal for every confirmation?
A: Yes! It provides better UX and accessibility than native confirm().
Q: Can I customize Modal appearance? A: Yes! The Modal component uses Tailwind classes. Extend or override as needed.
🆘 Getting Help
If you encounter issues:
- Check TypeScript errors in your IDE
- Review the summary document:
WEEK1_2_REFACTORING_SUMMARY.md - Look at refactored DailyTradingPlan as an example
- Ask the team!
Last Updated: Week 1-2 Refactoring Next Update: Week 3-4 (TradingJournal & AITradingCoach refactoring)