Commit graph

143 commits

Author SHA1 Message Date
4481c6b71a
Add payment method selector to exchange form with threshold enforcement 2025-12-23 14:50:22 +01:00
cb173a7442
Regenerate API types with bitcoin_transfer_method field 2025-12-23 14:49:09 +01:00
f618e5bbd6
fix: use Set for actioningIds to prevent race condition
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.
2025-12-23 12:28:16 +01:00
b5d831b364
fix: replace hardcoded wait with explicit wait for loading
Replace page.waitForTimeout(1000) with a proper wait for the
loading state to disappear. This makes the test more reliable
and faster.
2025-12-23 12:26:43 +01:00
06ad7fefe1
fix: improve error handling in admin trades fetch functions
- 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
2025-12-23 12:25:15 +01:00
e8d0ee2eca
refactor: import React types directly instead of namespace
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+).
2025-12-23 12:23:32 +01:00
c9c36971d8
refactor: extract shared trade card styles to shared.ts
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.
2025-12-23 12:22:04 +01:00
0d8369ce65
fix: e2e tests need to click 'Continue to Booking' before date selection
The exchange page is a two-step wizard:
- Step 1: Direction, amount, price selection
- Step 2: Date and slot selection

Tests were looking for date elements before navigating to step 2.
2025-12-23 11:30:27 +01:00
ca3a08a236
test: improve e2e tests and add COMPLETE_EXCHANGE permission tests
- Fix E2E test assertion for buy/sell direction change
- Add data-testid to date buttons for reliable e2e selection
- Update e2e tests to use data-testid instead of fragile weekday matching
- Add tests for regular user cannot complete/no-show trades (COMPLETE_EXCHANGE permission)
2025-12-23 11:00:32 +01:00
27896ed136
refactor: use shared constants for MIN/MAX_ADVANCE_DAYS
- Import constants from shared/constants.json in exchange page
- Remove hardcoded values for minAdvanceDays and maxAdvanceDays
2025-12-23 10:54:04 +01:00
110e5ec07f
refactor: extract shared formatEur and getTradeStatusDisplay utilities
- 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)
2025-12-23 10:52:53 +01:00
4e6f38e4a1
refactor: Extract SatsDisplay component and fix page IDs
- Extract SatsDisplay component to shared components directory
- Fix page IDs: rename 'admin-appointments' to 'admin-trades'
- Fix trades page using correct 'trades' page ID
2025-12-23 10:44:11 +01:00
bf57fc6b77
fix: Remove agreed_price from price API response
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.
2025-12-23 10:36:18 +01:00
1008eea2d9
Fix: Update permissions and add missing /api/exchange/slots endpoint
- 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
2025-12-22 21:42:42 +01:00
65ba4dc42a
Fix: Update auth E2E tests for exchange redirect
The auth tests expected '/' to show user email (old counter page).
Now regular users redirect to '/exchange' after login/signup.

Updated tests to:
- Expect /exchange URL after login/signup
- Check for 'Exchange Bitcoin' heading instead of email
- Update logout tests to verify /exchange access
- Update invite redirect tests for /exchange
2025-12-22 21:15:27 +01:00
bbd9fae763
Phase 7: Final cleanup - Remove deprecated booking/appointment code
Deleted deprecated files:
- backend/routes/booking.py
- frontend/app/admin/appointments/, booking/, appointments/, sum/, audit/
- frontend/app/utils/appointment.ts
- frontend/e2e/booking.spec.ts, appointments.spec.ts

Updated references:
- exchange/page.tsx: Use /api/exchange/slots instead of /api/booking/slots
- useRequireAuth.ts: Redirect to /admin/trades and /exchange
- profile.tsx, invites.tsx: Update fallback redirect
- E2E tests: Update all /audit references to /admin/trades
- profile.test.tsx: Update admin redirect test
2025-12-22 20:18:33 +01:00
9e8d0af435
Phase 4.2: Add Exchange E2E tests
New exchange.spec.ts with comprehensive E2E coverage:
- Exchange page access and UI elements (price, buy/sell, slider)
- Slot selection with availability
- Confirmation form with trade details
- Access control (regular user vs admin)
- My Trades page
- Admin Trades page with tabs
- Exchange API permission tests
2025-12-22 20:12:19 +01:00
ab908c172e
Phase 4.1: Update E2E permissions tests for exchange
Update permissions.spec.ts to test new exchange routes:
- Regular user: /exchange, /trades, /api/exchange/price
- Admin user: /admin/trades, /api/admin/trades/upcoming
- Updated all redirects and navigation tests
- Updated API permission boundary tests
2025-12-22 20:10:57 +01:00
d6002b0cfc
Phase 3.3: Add Admin Trades page
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
2025-12-22 20:06:16 +01:00
3785d6242d
Phase 3.2: Add My Trades page
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.
2025-12-22 20:02:00 +01:00
361dc8764d
Phase 3.1: Add Exchange page UI
New /exchange page for Bitcoin trading:
- Buy/Sell direction toggle with visual feedback
- Amount slider (€100-€3000 in €20 increments)
- Live price display with auto-refresh every 60s
- Direction-specific pricing (buy +5%, sell -5%)
- Sats amount displayed in BTC format (0.XX XXX XXX)
- Date selection with availability indicators
- Time slot selection grid
- Confirmation panel with trade summary

Regenerate frontend types from updated OpenAPI schema.
2025-12-22 19:59:42 +01:00
d88d69cf9f
Phase 1.4: Update frontend types
Regenerate API types from OpenAPI schema with new:
- ExchangeStatus enum
- TradeDirection enum
- ExchangeConfigResponse schema
- PriceResponse schema
- ExchangePriceResponse schema
- GET /api/exchange/price endpoint
2025-12-22 18:23:52 +01:00
c89e0312fa
Phase 0.3: Update E2E tests for cleanup
- Delete counter.spec.ts and random-jobs.spec.ts
- Rewrite permissions.spec.ts for new permission structure
- Update scripts/e2e.sh: remove worker.py execution
- Update generated api.ts types
2025-12-22 18:13:24 +01:00
a5c1eccb4b
Phase 0.2: Remove frontend deprecated code
- Delete pages: sum, audit, admin/random-jobs
- Delete old homepage (counter) and create redirect page
- Update Header.tsx: remove Counter, Sum, Audit, Random Jobs nav items
- Update auth-context.tsx: remove VIEW_COUNTER, INCREMENT_COUNTER, USE_SUM permissions
- Update profile/page.test.tsx: fix nav link assertions
2025-12-22 18:09:09 +01:00
ea85198171
updated generated 2025-12-22 17:29:44 +01:00
3806361fac
feat: add FETCH_PRICE permission for manual price fetch endpoint
The POST /api/audit/price-history/fetch endpoint now requires
FETCH_PRICE permission instead of VIEW_AUDIT, which is more
semantically correct since it's a write operation.
2025-12-22 16:22:54 +01:00
dd7bec6091
test: add E2E tests for price history feature 2025-12-22 15:56:12 +01:00
c2dd7b5b91
feat: add price history admin page with fetch button 2025-12-22 15:49:41 +01:00
20f7af7ffd
generated ts 2025-12-22 09:31:19 +01:00
976038c806
no parallel running to avoid flaky tests 2025-12-22 09:31:00 +01:00
fdab4a5dac
refactor(frontend): extract validation utilities to shared module
Issue #7: Profile validation logic was embedded in page component.

Changes:
- Create utils/validation.ts with shared validation functions:
  - validateEmail: email format validation
  - validateTelegram: handle format with @ prefix
  - validateSignal: username length validation
  - validateNostrNpub: bech32 format validation
  - validateProfileFields: combined validation
- Update profile/page.tsx to use shared validation
- Both frontend and backend now read validation rules from
  shared/constants.json for consistency
2025-12-22 09:13:03 +01:00
09560296aa
refactor: derive Permission type from generated OpenAPI schema
Issue #3: The frontend Permission enum was manually duplicated from
the backend. While full generation isn't practical, this change
ties the frontend constants to the generated OpenAPI types for
compile-time validation.

Changes:
- Update ConstantsResponse schema to use actual Permission/InviteStatus
  enums (enables OpenAPI to include enum values)
- Import enums in schemas.py (no circular dependency issue)
- Update auth-context.tsx to derive PermissionType from generated schema
- Update meta route to return enum instances instead of string values
- Permission values are now type-checked against the OpenAPI schema

If a permission is added to the backend but not to the frontend's
Permission object, TypeScript will fail to compile. This provides
a safety net without requiring a complex build-time generation step.
2025-12-21 23:55:47 +01:00
21698203fe
refactor(auth): unify authorization patterns with MANAGE_OWN_PROFILE permission
Issue #2: The profile route used a custom role-based check instead
of the permission-based pattern used everywhere else.

Changes:
- Add MANAGE_OWN_PROFILE permission to backend Permission enum
- Add permission to ROLE_REGULAR role definition
- Update profile routes to use require_permission(MANAGE_OWN_PROFILE)
- Remove custom require_regular_user dependency
- Update frontend Permission constant and profile page
- Update invites page to use permission instead of role check
- Update profile tests with proper permission mocking

This ensures consistent authorization patterns across all routes.
2025-12-21 23:50:06 +01:00
81cd34b0e7
refactor(frontend): consolidate shared styles into centralized style system
- Create comprehensive shared.ts with design tokens and categorized styles:
  - layoutStyles: main, loader, content variants
  - cardStyles: card, tableCard, cardHeader
  - tableStyles: complete table styling
  - paginationStyles: pagination controls
  - formStyles: inputs, labels, errors
  - buttonStyles: primary, secondary, accent, danger variants
  - badgeStyles: status badges with color variants
  - bannerStyles: error/success banners
  - modalStyles: modal overlay and content
  - toastStyles: toast notifications
  - utilityStyles: divider, emptyState, etc.

- Refactor all page components to use shared styles:
  - page.tsx (counter)
  - audit/page.tsx
  - booking/page.tsx
  - appointments/page.tsx
  - profile/page.tsx
  - invites/page.tsx
  - admin/invites/page.tsx
  - admin/availability/page.tsx

- Reduce code duplication significantly (each page now has only
  truly page-specific styles)
- Maintain backwards compatibility with sharedStyles export
2025-12-21 23:45:47 +01:00
405dfd526e
Replace fixed timeout with polling in random-jobs E2E test
- Removed brittle 1-second waitForTimeout
- Use toPass() with polling to wait for job outcome
- Check for specific user's email instead of exact row count
- More robust under slow worker conditions or CI load
2025-12-21 23:14:59 +01:00
7ec987c78d
Phase 6: E2E Test
- Update scripts/e2e.sh to start worker alongside backend
- Create frontend/e2e/random-jobs.spec.ts with 3 tests:
  - Counter increment creates random job outcome visible to admin
  - Admin can view empty random jobs list
  - Regular user cannot access random jobs page
2025-12-21 23:00:54 +01:00
b8470b77a7
Phase 5: Frontend Admin Page
- Create /admin/random-jobs/page.tsx with outcomes table
- Add 'admin-random-jobs' to PageId type in Header
- Add 'Random Jobs' nav item to ADMIN_NAV_ITEMS
- Display: ID, Job ID, Triggered By, Value, Duration, Status, Created At
- Uses VIEW_AUDIT permission
2025-12-21 22:55:56 +01:00
607f872c71
fix pre-commit hook and code quality fixes 2025-12-21 22:14:48 +01:00
521848217d
Add Vitest coverage for frontend tests
- Install @vitest/coverage-v8
- Configure coverage in vitest.config.ts
- Add npm script: test:coverage
- Add coverage/ to gitignore
2025-12-21 22:00:47 +01:00
37de6f70e0
Add Prettier for TypeScript formatting
- Install prettier
- Configure .prettierrc.json and .prettierignore
- Add npm scripts: format, format:check
- Add Makefile target: format-frontend
- Format all frontend files
2025-12-21 21:59:26 +01:00
4b394b0698
Add ESLint for TypeScript/React linting
- Install eslint, typescript-eslint, eslint-plugin-react-hooks
- Configure eslint.config.js with flat config format
- Add type: module to package.json
- Fix unused variable issues (prefix with underscore)
- Add Makefile targets: lint-frontend, fix-frontend
2025-12-21 21:58:41 +01:00
69bc8413e0
remove 2025-12-21 21:39:48 +01:00
621e12cdb5
fix tests 2025-12-21 21:35:35 +01:00
bf1e42a498
fixes 2025-12-21 19:04:38 +01:00
f81e7a88bd
Fix React CSS property conflict in availability page
- Replaced borderColor with full border property in dayCardActive
- Replaced borderColor with full border property in dayCardSource
- Replaced borderColor with full border property in dayCardTarget
- Prevents React warning about mixing shorthand and non-shorthand properties
- Fixes console error when using 'Clear all' button on availability page
2025-12-21 18:23:31 +01:00
74ed6f0c11
Revert to local timezone display for user-facing times
- Changed formatTime back to use toLocaleTimeString (local time)
- Changed formatDateTime back to use toLocaleString (local time)
- App now displays all times in user's local timezone
- Backend still stores times in UTC, frontend converts for display
2025-12-21 18:20:22 +01:00
a5b941e748
Fix timezone issue in formatDateTime for appointments page
- Changed formatDateTime to use UTC methods instead of toLocaleString
- Prevents timezone conversion when displaying appointment times
- Now booking at 11:45 shows as 11:45 in appointments page, not 12:45
- Consistent with formatTime which already uses UTC
- Manual formatting to match previous format: 'Mon, Jan 15, 11:45'
2025-12-21 18:18:40 +01:00
b900b52b3c
Fix infinite loop in booking page availability fetching
- Memoized dates array using useMemo to prevent recreation on every render
- Removed dates from useEffect dependency array since it's now stable
- Prevents cascade of API requests when opening booking page
- Dates only recalculate when minAdvanceDays or maxAdvanceDays change
2025-12-21 18:15:57 +01:00
63f40433cc
Disable dates with no availability on booking page
- Fetch availability for all dates on page load
- Track which dates have available slots in state
- Disable date buttons that have no availability
- Add visual styling for disabled dates (reduced opacity, not-allowed cursor)
- Prevent clicking on dates with no availability
- Improves UX by showing which dates are bookable at a glance
2025-12-21 18:13:12 +01:00
7926e3ae4c
Fix timezone issue: display booking slots in UTC
- Changed formatTime() to use UTC methods instead of toLocaleTimeString()
- Prevents timezone conversion when displaying booking slots
- Now admin sets 9-17 and user sees 9-17, regardless of timezone
- Fixes 1-hour offset issue when user timezone differs from UTC
2025-12-21 18:10:15 +01:00