- 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 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+).
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 /admin/trades page for managing exchange trades:
- Upcoming trades tab with user contact info
- History tab with status/user search filters
- Complete/No-show/Cancel actions for admin
- Trade details: direction, amounts, rates, premium
Update navigation:
- Admin home redirects to /admin/trades
- Regular user home redirects to /exchange
- Header shows 'Trades' for admin