- Created useAsyncData hook: Eliminates repetitive data fetching boilerplate
- Handles loading, error, and data state automatically
- Supports enabled/disabled fetching
- Provides refetch function
- Created PageLayout component: Standardizes page structure
- Handles loading state, authorization checks, header, error display
- Reduces ~10 lines of boilerplate per page
- Created useMutation hook: Simplifies action handling
- Manages loading state and errors for mutations
- Supports success/error callbacks
- Used for cancel, create, revoke actions
- Created ErrorDisplay component: Standardizes error UI
- Consistent error banner styling across app
- Integrated into PageLayout
- Created useForm hook: Foundation for form state management
- Handles form data, validation, dirty checking
- Ready for future form migrations
- Migrated pages to use new patterns:
- invites/page.tsx: useAsyncData + PageLayout
- trades/page.tsx: useAsyncData + PageLayout + useMutation
- trades/[id]/page.tsx: useAsyncData
- admin/price-history/page.tsx: useAsyncData + PageLayout
- admin/invites/page.tsx: useMutation for create/revoke
Benefits:
- ~40% reduction in boilerplate code
- Consistent patterns across pages
- Easier to maintain and extend
- Better type safety
All tests passing (32 frontend, 33 e2e)
- Created new api/ directory with domain-specific API modules:
- api/client.ts: Base API client with error handling
- api/auth.ts: Authentication endpoints
- api/exchange.ts: Exchange/price endpoints
- api/trades.ts: User trade endpoints
- api/profile.ts: Profile management endpoints
- api/invites.ts: Invite endpoints
- api/admin.ts: Admin endpoints
- api/index.ts: Centralized exports
- Migrated all API calls from ad-hoc api.get/post/put to typed domain APIs
- Updated all imports across codebase
- Fixed test mocks to use new API structure
- Fixed type issues in validation utilities
- Removed old api.ts file
Benefits:
- Type-safe endpoints (no more string typos)
- Centralized API surface (easy to discover endpoints)
- Better organization (domain-specific modules)
- Uses generated OpenAPI types automatically
Break down the 1300+ line Exchange page into smaller, focused components:
- Create useExchangePrice hook
- Handles price fetching and auto-refresh logic
- Manages price loading and error states
- Centralizes price-related state management
- Create useAvailableSlots hook
- Manages slot fetching and availability checking
- Handles date availability state
- Fetches availability when entering booking/confirmation steps
- Create PriceDisplay component
- Displays market price, agreed price, and premium
- Shows price update timestamp and stale warnings
- Handles loading and error states
- Create ExchangeDetailsStep component
- Step 1 of wizard: direction, payment method, amount selection
- Contains all form logic for trade details
- Validates and displays trade summary
- Create BookingStep component
- Step 2 of wizard: date and slot selection
- Shows trade summary card
- Handles date availability and existing trade warnings
- Create ConfirmationStep component
- Step 3 of wizard: final confirmation
- Shows compressed booking summary
- Displays all trade details for review
- Create StepIndicator component
- Visual indicator of current wizard step
- Shows completed and active steps
- Refactor ExchangePage
- Reduced from 1300+ lines to ~350 lines
- Uses new hooks and components
- Maintains all existing functionality
- Improved maintainability and testability
All frontend tests pass. Linting passes.
- Add commit() method to AvailabilityRepository for transaction control
- Add refresh() method to UserRepository
- Update AvailabilityService to use repository.commit() instead of db.commit()
- Update AuthService to use UserRepository.refresh() instead of db.refresh()
- All services now consistently delegate ALL persistence to repositories
- Add create() and update() methods to ExchangeRepository
- Update ExchangeService to use repository methods instead of direct db operations
- All persistence operations now go through repositories consistently
- Fix indentation errors in ExchangeService
- Add create(), update(), and reload_with_relationships() methods to InviteRepository
- Update InviteService to use repository methods instead of direct db operations
- Add create() and update() methods to UserRepository
- Update ProfileService to use repository.update()
- Update AuthService to use repository.create()
- Add create() and create_multiple() methods to AvailabilityRepository
- Update AvailabilityService to use repository methods instead of direct db operations
- Add get_available_slots() and _expand_availability_to_slots() to ExchangeService
- Update routes/exchange.py to use ExchangeService.get_available_slots()
- Remove all business logic from get_available_slots endpoint
- Add AvailabilityRepository to ExchangeService dependencies
- Add Availability and BookableSlot imports to ExchangeService
- Fix import path for validate_date_in_range (use date_validation module)
- Remove unused user_repo variable and import from routes/invites.py
- Fix mypy error in ValidationError by adding proper type annotation
- Create AvailabilityService with get_availability_for_range(), set_availability_for_date(), and copy_availability()
- Move slot validation logic to service
- Update routes/availability.py to use AvailabilityService
- Remove all direct database queries from routes
- Create PriceService with get_recent_prices() and fetch_and_store_price()
- Update routes/audit.py to use PriceService instead of direct queries
- Use PriceHistoryMapper consistently
- Update test to patch services.price.fetch_btc_eur_price
Replace single actioningId state with a Set of IDs to properly
track multiple concurrent actions. This prevents issues when
a user rapidly clicks actions on different trades before the
previous action completes.
- Return errors from fetch functions instead of setting state directly
- Clear error state before starting a new fetch
- Combine errors when both upcoming and past trades fail to load
- Handle fetch errors in handleAction as well
Replace 'import React from "react"' with direct imports of
CSSProperties and ChangeEvent. This eliminates unused imports
and follows modern React patterns where the namespace import
is not required for JSX (React 17+).