- 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
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+).
Move duplicate style definitions from trades/page.tsx and
admin/trades/page.tsx to a new tradeCardStyles export in shared.ts.
Both pages now import and use these shared styles, keeping only
page-specific styles locally. This improves maintainability and
ensures visual consistency.
- Create frontend/app/utils/exchange.ts with shared formatting functions
- Update exchange/page.tsx to use shared formatEur
- Update trades/page.tsx to use shared formatEur and getTradeStatusDisplay
- Update admin/trades/page.tsx to use shared formatEur and getTradeStatusDisplay
- SatsDisplay was already extracted (confirmed it's in components/SatsDisplay.tsx)
The agreed_price depends on trade direction (buy/sell) and must be
calculated on the frontend. Returning a buy-side-only agreed_price
from the API was misleading and unused.
Frontend already calculates the direction-aware price correctly.
- Updated auth-context.tsx to use new exchange permissions
(CREATE_EXCHANGE, VIEW_OWN_EXCHANGES, etc.) instead of old
appointment permissions (BOOK_APPOINTMENT, etc.)
- Updated exchange/page.tsx, trades/page.tsx, admin/trades/page.tsx
to use correct permission constants
- Updated profile/page.test.tsx mock permissions
- Updated admin/availability/page.tsx to use constants.exchange
instead of constants.booking
- Added /api/exchange/slots endpoint to return available slots
for a date, filtering out already booked slots
- Fixed E2E tests:
- exchange.spec.ts: Wait for button to be enabled before clicking
- permissions.spec.ts: Use more specific heading selector
- price-history.spec.ts: Expect /exchange redirect for regular users
New /trades page for viewing user's Bitcoin trades:
- Upcoming trades with cancel functionality
- Trade history (completed, cancelled, no-show)
- Direction badges (BUY/SELL with colors)
- EUR ↔ BTC amounts in readable format
- Rate and premium display
Update Header navigation:
- Exchange replaces Book for regular users
- My Trades replaces Appointments
Update profile page test for new nav items.