Local changes: Updated model training, removed debug instrumentation, and configuration improvements
This commit is contained in:
346
docs/developer/ui_development.md
Normal file
346
docs/developer/ui_development.md
Normal file
@@ -0,0 +1,346 @@
|
||||
# Frontend Development Guide
|
||||
|
||||
This guide explains how to develop and extend frontend components in Crypto Trader.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **React 18** - UI framework
|
||||
- **TypeScript** - Type safety
|
||||
- **Material-UI (MUI)** - Component library
|
||||
- **React Query** - Data fetching and caching
|
||||
- **React Router** - Routing
|
||||
- **Vite** - Build tool
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── pages/ # Page components
|
||||
│ ├── components/ # Reusable components
|
||||
│ ├── api/ # API client functions
|
||||
│ ├── hooks/ # Custom React hooks
|
||||
│ ├── types/ # TypeScript types
|
||||
│ └── App.tsx # Main app component
|
||||
├── public/ # Static assets
|
||||
└── package.json # Dependencies
|
||||
```
|
||||
|
||||
## Development Setup
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Access at: http://localhost:3000
|
||||
|
||||
## Creating a New Page
|
||||
|
||||
1. Create page component in `src/pages/`:
|
||||
|
||||
```typescript
|
||||
// src/pages/MyPage.tsx
|
||||
import { Box, Typography } from '@mui/material';
|
||||
|
||||
export function MyPage() {
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h4">My Page</Typography>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
2. Add route in `src/App.tsx`:
|
||||
|
||||
```typescript
|
||||
import { MyPage } from './pages/MyPage';
|
||||
|
||||
<Route path="/my-page" element={<MyPage />} />
|
||||
```
|
||||
|
||||
## API Integration
|
||||
|
||||
### Creating API Functions
|
||||
|
||||
```typescript
|
||||
// src/api/myService.ts
|
||||
import { apiClient } from './client';
|
||||
|
||||
export const myServiceApi = {
|
||||
async getData() {
|
||||
const response = await apiClient.get('/api/my-service/data');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async createItem(data: CreateItemDto) {
|
||||
const response = await apiClient.post('/api/my-service/items', data);
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Using React Query
|
||||
|
||||
```typescript
|
||||
import { useQuery, useMutation } from '@tanstack/react-query';
|
||||
import { myServiceApi } from '@/api/myService';
|
||||
|
||||
function MyComponent() {
|
||||
// Fetch data
|
||||
const { data, isLoading, error } = useQuery({
|
||||
queryKey: ['myData'],
|
||||
queryFn: myServiceApi.getData
|
||||
});
|
||||
|
||||
// Mutate data
|
||||
const mutation = useMutation({
|
||||
mutationFn: myServiceApi.createItem,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['myData'] });
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <Loading />}
|
||||
{data && <DataDisplay data={data} />}
|
||||
<button onClick={() => mutation.mutate(formData)}>Create</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Creating Reusable Components
|
||||
|
||||
```typescript
|
||||
// src/components/DataTable.tsx
|
||||
import { Table, TableBody, TableCell, TableHead, TableRow } from '@mui/material';
|
||||
|
||||
interface DataTableProps<T> {
|
||||
data: T[];
|
||||
columns: Column<T>[];
|
||||
}
|
||||
|
||||
export function DataTable<T>({ data, columns }: DataTableProps<T>) {
|
||||
return (
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{columns.map(col => (
|
||||
<TableCell key={col.key}>{col.header}</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{data.map((row, idx) => (
|
||||
<TableRow key={idx}>
|
||||
{columns.map(col => (
|
||||
<TableCell key={col.key}>{col.render(row)}</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Hooks
|
||||
|
||||
```typescript
|
||||
// src/hooks/useOrders.ts
|
||||
import { useQuery, useMutation } from '@tanstack/react-query';
|
||||
import { tradingApi } from '@/api/trading';
|
||||
|
||||
export function useOrders() {
|
||||
const { data: orders, isLoading, error } = useQuery({
|
||||
queryKey: ['orders'],
|
||||
queryFn: () => tradingApi.getOrders()
|
||||
});
|
||||
|
||||
const placeOrder = useMutation({
|
||||
mutationFn: tradingApi.placeOrder,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['orders'] });
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
orders: orders ?? [],
|
||||
isLoading,
|
||||
error,
|
||||
placeOrder: placeOrder.mutate
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## WebSocket Integration
|
||||
|
||||
The application uses an enhanced WebSocket system with message type handling:
|
||||
|
||||
```typescript
|
||||
// Using the WebSocket context
|
||||
import { useWebSocketContext } from '@/components/WebSocketProvider';
|
||||
import { useRealtimeData } from '@/hooks/useRealtimeData';
|
||||
|
||||
function MyComponent() {
|
||||
const { isConnected, lastMessage, subscribe } = useWebSocketContext();
|
||||
|
||||
// Subscribe to specific message types
|
||||
useEffect(() => {
|
||||
const unsubscribe = subscribe('order_update', (message) => {
|
||||
// Handle order update
|
||||
console.log('Order updated:', message);
|
||||
});
|
||||
|
||||
return unsubscribe;
|
||||
}, [subscribe]);
|
||||
|
||||
// Or use the real-time data hook for automatic query invalidation
|
||||
useRealtimeData(); // Automatically handles common message types
|
||||
}
|
||||
```
|
||||
|
||||
### Message Types
|
||||
|
||||
The WebSocket supports these message types:
|
||||
- `order_update`: Order status changes
|
||||
- `position_update`: Position changes
|
||||
- `price_update`: Price updates
|
||||
- `alert_triggered`: Alert notifications
|
||||
- `strategy_signal`: Strategy signal notifications
|
||||
- `system_event`: System events and errors
|
||||
|
||||
## Form Handling
|
||||
|
||||
```typescript
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import * as yup from 'yup';
|
||||
|
||||
const schema = yup.object({
|
||||
symbol: yup.string().required(),
|
||||
quantity: yup.number().positive().required()
|
||||
});
|
||||
|
||||
function OrderForm() {
|
||||
const { register, handleSubmit, formState: { errors } } = useForm({
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
await tradingApi.placeOrder(data);
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<TextField
|
||||
{...register('symbol')}
|
||||
error={!!errors.symbol}
|
||||
helperText={errors.symbol?.message}
|
||||
/>
|
||||
<Button type="submit">Place Order</Button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The application uses a centralized Snackbar context for error handling:
|
||||
|
||||
```typescript
|
||||
import { useSnackbar } from '@/contexts/SnackbarContext';
|
||||
import ErrorDisplay from '@/components/ErrorDisplay';
|
||||
|
||||
function MyComponent() {
|
||||
const { showError, showSuccess, showWarning, showInfo } = useSnackbar();
|
||||
|
||||
const handleAction = async () => {
|
||||
try {
|
||||
await apiCall();
|
||||
showSuccess('Action completed successfully');
|
||||
} catch (err) {
|
||||
showError(err instanceof Error ? err.message : 'An error occurred');
|
||||
}
|
||||
};
|
||||
|
||||
// For complex error display with retry
|
||||
return (
|
||||
<>
|
||||
{error && (
|
||||
<ErrorDisplay
|
||||
error={error}
|
||||
title="Operation Failed"
|
||||
onRetry={handleAction}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Available Components
|
||||
|
||||
- `ErrorDisplay`: Enhanced error display with retry functionality
|
||||
- `LoadingSkeleton`: Loading placeholders for tables, cards, lists
|
||||
- `ProgressOverlay`: Overlay with progress indicator
|
||||
- `StatusIndicator`: Connection status indicators
|
||||
- `DataFreshness`: Data freshness timestamps
|
||||
- `HelpTooltip`: Contextual help tooltips
|
||||
- `InfoCard`: Collapsible information cards
|
||||
- `OperationsPanel`: Panel showing running operations
|
||||
|
||||
## Styling
|
||||
|
||||
### Material-UI Theming
|
||||
|
||||
```typescript
|
||||
// src/theme.ts
|
||||
import { createTheme } from '@mui/material/styles';
|
||||
|
||||
export const theme = createTheme({
|
||||
palette: {
|
||||
mode: 'dark',
|
||||
primary: {
|
||||
main: '#1976d2'
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Component Styling
|
||||
|
||||
Use Material-UI's `sx` prop for inline styles:
|
||||
|
||||
```typescript
|
||||
<Box
|
||||
sx={{
|
||||
padding: 2,
|
||||
backgroundColor: 'background.paper',
|
||||
borderRadius: 1
|
||||
}}
|
||||
>
|
||||
Content
|
||||
</Box>
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
See [Testing Guide](./testing.md) for frontend testing strategies.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Type Safety**: Always use TypeScript types
|
||||
2. **Component Composition**: Prefer composition over inheritance
|
||||
3. **Custom Hooks**: Extract reusable logic into hooks
|
||||
4. **Error Handling**: Handle errors gracefully with user feedback
|
||||
5. **Loading States**: Always show loading indicators
|
||||
6. **Accessibility**: Use semantic HTML and ARIA labels
|
||||
7. **Performance**: Use React.memo, useMemo, useCallback appropriately
|
||||
8. **Code Splitting**: Use lazy loading for large components
|
||||
9. **Form Validation**: Validate on both client and server
|
||||
10. **Consistent Patterns**: Follow established patterns in the codebase
|
||||
Reference in New Issue
Block a user