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,393 @@
|
||||
# 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:**
|
||||
```typescript
|
||||
import { useLocalStorage } from '@/hooks';
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```typescript
|
||||
// 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:**
|
||||
```typescript
|
||||
import { useApi } from '@/hooks';
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```typescript
|
||||
// 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:**
|
||||
```typescript
|
||||
import { formatCurrency, formatPercent, formatNumber, formatPriceChange } from '@/utils/indicators';
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```typescript
|
||||
// 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:**
|
||||
```typescript
|
||||
// ❌ 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:**
|
||||
```typescript
|
||||
import { Modal, ConfirmModal, AlertModal } from '@/components/shared/Modal';
|
||||
```
|
||||
|
||||
**Replace `confirm()`:**
|
||||
```typescript
|
||||
// ❌ 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()`:**
|
||||
```typescript
|
||||
// ❌ 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:**
|
||||
```typescript
|
||||
<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:**
|
||||
```typescript
|
||||
// ❌ 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`:
|
||||
```typescript
|
||||
export default function MyComponent() { ... }
|
||||
export type { MyComponentProps } from './types';
|
||||
```
|
||||
|
||||
### 3. Custom Hooks Pattern
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
// ✅ 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 `localStorage` patterns with `useLocalStorage`
|
||||
- [ ] Replace direct API calls with `useApi`
|
||||
- [ ] Replace `alert`/`confirm` with Modal components
|
||||
- [ ] Use formatting utilities from `@/utils/indicators`
|
||||
- [ ] Remove all `any` types
|
||||
- [ ] 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:
|
||||
```bash
|
||||
cd frontend
|
||||
npm run build
|
||||
```
|
||||
|
||||
Should compile without TypeScript errors!
|
||||
|
||||
### Runtime Test:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Check:
|
||||
1. Component loads without errors
|
||||
2. State updates work
|
||||
3. localStorage persists
|
||||
4. Modals open/close correctly
|
||||
5. No console warnings
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
- [React Hooks Documentation](https://react.dev/reference/react)
|
||||
- [TypeScript Handbook](https://www.typescriptlang.org/docs/)
|
||||
- [ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/)
|
||||
|
||||
---
|
||||
|
||||
## ❓ 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:
|
||||
|
||||
1. Check TypeScript errors in your IDE
|
||||
2. Review the summary document: `WEEK1_2_REFACTORING_SUMMARY.md`
|
||||
3. Look at refactored DailyTradingPlan as an example
|
||||
4. Ask the team!
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** Week 1-2 Refactoring
|
||||
**Next Update:** Week 3-4 (TradingJournal & AITradingCoach refactoring)
|
||||
Reference in New Issue
Block a user