Commit graph

249 commits

Author SHA1 Message Date
43b250e157
small fixes 2025-12-27 12:52:43 +01:00
86c92a7c65
small details 2025-12-26 23:27:33 +01:00
61ae2807de
Fix profile e2e test flakiness by waiting for API response
- Wait for PUT /api/profile response before reloading page
- Wait for network idle after save completes
- Reuse existing saveButton variable instead of redeclaring
- All 40 e2e tests passing
2025-12-26 22:44:30 +01:00
4cd2872d6a
Merge related e2e tests to reduce redundancy
- Merge 'admin can access pricing page and UI elements are correct' with 'can view current pricing configuration' into single test
- Merge 'can update pricing configuration' with 'form fields update correctly when values change' into single test
- Reduced from 9 tests to 7 tests while maintaining same coverage
- All 40 e2e tests still passing
2025-12-26 22:39:18 +01:00
728aec2bf6
Fix e2e test flakiness by using networkidle instead of response listeners
- Remove response listener promises that were timing out in full suite
- Use waitForLoadState('networkidle') after confirm click
- Add small delay before reading updated value to ensure state refresh
- All 42 e2e tests now passing consistently
2025-12-26 21:15:34 +01:00
1ef5ebe493
Fix ConfirmationButton usage in pricing page and e2e tests
- Update pricing page to use ConfirmationButton API correctly (isConfirming, onConfirm, onCancel, onActionClick)
- Fix e2e tests to set up response listeners before navigation
- Fix validation error selector to use .first() for multiple matches
- All 9 e2e tests now passing
2025-12-26 21:07:56 +01:00
1874c3a057
Fix e2e tests to wait for API calls and form rendering
- Wait for GET /api/admin/pricing response before checking elements
- Wait for heading to be visible before interacting with form
- Wait for inputs to be visible before reading values
- This ensures the page has finished loading before tests run
2025-12-26 21:02:45 +01:00
c9efcf79ff
Fix duplicate variable declarations in e2e tests 2025-12-26 21:00:29 +01:00
7f547d667d
Fix e2e tests for pricing page
- Update selectors to use input indices instead of labels (labels not associated)
- Fix validation error status expectation (400 instead of 422)
- Update exchange.spec.ts to check new config fields (eur_min_buy, etc.)
2025-12-26 20:59:10 +01:00
2ee27cf5b2
Add e2e tests for admin pricing page
- Test admin can access pricing page and view current configuration
- Test admin can update pricing configuration with confirmation
- Test form validation prevents invalid values
- Test regular users cannot access pricing page
- Test API permissions (admin can access, regular user cannot)
- Test API validation works correctly
2025-12-26 20:57:32 +01:00
549fbf4975
Step 8: Cleanup old constants
- Remove EUR_TRADE_MIN, EUR_TRADE_MAX, PREMIUM_PERCENTAGE from shared_constants.py
- Remove eurTradeMin, eurTradeMax, premiumPercentage from shared/constants.json
- Update validate_constants.py to not require removed fields
- Update seed.py and seed_e2e.py to use defaults if fields don't exist
- Update tests to handle missing constants gracefully
2025-12-26 20:27:03 +01:00
41e158376c
Step 6: Update exchange creation logic to use new pricing config
- Update ExchangeService to load pricing config from database
- Update validate_eur_amount to use direction-specific limits
- Update apply_premium_for_direction to calculate base + extra premium
- Update create_exchange to use new premium calculation
- Add tests for premium calculation (small trade extra, large trade base only, direction-specific)
- Update existing tests to account for new premium calculation
2025-12-26 20:24:13 +01:00
d317939ad0
Step 5: Update exchange price endpoint to use new pricing config
- Update ExchangeConfigResponse schema with direction-specific fields
- Remove premium_percentage from PriceResponse (now in config)
- Update price endpoint to load pricing config from database
- Update frontend to use direction-specific min/max and calculate premium
- Update tests to seed pricing config
- Add logic to clamp amount when direction changes
2025-12-26 20:20:23 +01:00
d838d1be96
Step 4: Add admin UI page for pricing configuration
- Add pricing API functions to admin.ts
- Create admin pricing page with form and validation
- Add MANAGE_PRICING permission to auth context
- Add pricing to admin navigation
- Add translations for pricing page (en, ca, es)
- Update PageLayout and Header types for new page
2025-12-26 20:17:48 +01:00
4d0dad8e2b
Step 3: Add admin API endpoints for pricing configuration
- Add PricingConfigResponse and PricingConfigUpdate schemas
- Create PricingService with validation logic
- Add GET and PUT endpoints in routes/pricing.py
- Add MANAGE_PRICING permission to admin role
- Register pricing router in main.py
- Add comprehensive API tests for permissions and validation
2025-12-26 20:13:24 +01:00
74b934135a
Step 2: Add seeding logic for pricing config
- Add seed_pricing_config() function to seed.py
- Seed initial values from shared/constants.json
- Add seeding to seed_e2e.py for E2E tests
- Add tests for seeding functionality
2025-12-26 20:11:00 +01:00
32ce27180d
Step 1: Add PricingConfig model and PricingRepository
- Create PricingConfig model with all required fields (premium settings, trade limits)
- Implement PricingRepository with singleton pattern (get_current, create_or_update)
- Add comprehensive tests for repository functionality
- Export model and repository in __init__.py files
2025-12-26 20:08:35 +01:00
82c4d0168e
refactors 2025-12-26 20:04:46 +01:00
4e1a339432
working 2025-12-26 19:21:34 +01:00
c0999370c6
fix capitalisation 2025-12-26 19:06:57 +01:00
8503c760dc
a few small fixes 2025-12-26 19:00:56 +01:00
f6c552cefd
pretty decent state 2025-12-26 18:49:00 +01:00
63a4b0f8a2
Add translation validation git hook
- Create validate-translations.js script to check all translation keys exist in all locales
- Add translation validation to pre-commit hook
- Validates that es, en, ca translation files have matching keys
- Blocks commits if translations are missing or inconsistent
- Prevents incomplete translations from being committed
2025-12-26 11:58:09 +01:00
2fdcbbdfe8
Fix e2e availability tests: Update to match translated strings
- Update modal heading from 'Edit Availability' to 'Edit Time Slots'
- Update button text from 'Clear All' to 'Clear'
- Update button text from '+ Add Time Range' to '+ Add Slot'
- Update button text from 'Cancel' to 'Close'
- All 33 e2e tests now passing
2025-12-26 11:56:56 +01:00
e2376855ce
Translate admin pages - Create admin.json files and translate all admin pages
- Create admin.json translation files for es, en, ca with all admin strings
- Update IntlProvider to include admin namespace
- Translate admin/invites/page.tsx - all strings now use translations
- Translate admin/trades/page.tsx - all strings now use translations
- Translate admin/price-history/page.tsx - all strings now use translations
- Translate admin/availability/page.tsx - all strings now use translations
- Add 'saving' key to common.json for all languages
- Fix linting errors: add t to useCallback dependencies
- All admin pages now fully multilingual
2025-12-26 11:49:50 +01:00
b8b3e8b9f6
Fix e2e test: Update date button selector to use data-testid
- Replace text-based selector that expected English weekdays with data-testid selector
- Dates now use Spanish locale (es-ES) formatting, so weekday text changed
- Using data-testid is more reliable and language-agnostic
- Fixes failing test: 'regular user can access exchange page, all UI elements work, and buy/sell toggle functions'
2025-12-26 11:44:08 +01:00
eff0698acb
Add timeZone configuration to next-intl
- Add timeZone='Europe/Madrid' to NextIntlClientProvider
- Fixes ENVIRONMENT_FALLBACK warning about missing timeZone configuration
- Ensures consistent timezone handling across SSR and client rendering
2025-12-26 11:38:48 +01:00
0378a8edd7
Make HTML lang attribute dynamic based on selected language
- Create HtmlLang client component that updates document.documentElement.lang
- Add HtmlLang component to layout.tsx to sync HTML lang attribute with locale
- HTML lang now updates automatically when user changes language
2025-12-26 11:38:38 +01:00
e35e79e84d
Fix date/time formatting to use es-ES locale
- Update all date/time formatting functions to use 'es-ES' locale instead of 'en-US' or 'de-DE'
- Update utility functions in utils/date.ts and utils/exchange.ts
- Update all component files that use date formatting
- Update e2e test helper to match new Spanish date format
- All formatting now uses Spanish locale regardless of selected language as per PR requirements
2025-12-26 11:38:17 +01:00
d2fc7d8850
Fix e2e tests: Set English language before navigation
- Add context.addInitScript in beforeEach hooks to set English locale before page navigation
- Remove debugging code from useLanguage hook
- Remove unused setup file imports
- Fix exchange test to check for English text correctly
- All frontend tests passing
2025-12-25 22:35:27 +01:00
246553c402
Phase 6: Translate User Pages - exchange, trades, invites, profile
- Expand exchange.json with all exchange page strings (page, steps, detailsStep, bookingStep, confirmationStep, priceDisplay)
- Create trades.json translation files for es, en, ca
- Create invites.json translation files for es, en, ca
- Create profile.json translation files for es, en, ca
- Translate exchange page and all components (ExchangeDetailsStep, BookingStep, ConfirmationStep, StepIndicator, PriceDisplay)
- Translate trades page (titles, sections, buttons, status labels)
- Translate invites page (titles, sections, status badges, copy button)
- Translate profile page (form labels, hints, placeholders, messages)
- Update IntlProvider to load all new namespaces
- All frontend tests passing
2025-12-25 22:19:13 +01:00
7dd13292a0
Phase 5: Translate Auth Pages - login and signup
- Create auth.json translation files for es, en, ca
- Translate login page: title, subtitle, form labels, buttons, footer
- Translate signup page: invite code step and account creation step
- Translate signup/[code] redirect page
- Update IntlProvider to load auth namespace
- Update test expectations to match Spanish translations (default language)
- All frontend and e2e tests passing
2025-12-25 22:14:04 +01:00
a5a1a2c1ad
Phase 4: Translate Shared Components - common, navigation, status labels
- Translate LoadingState and EmptyState components (common namespace)
- Translate Header navigation labels (navigation namespace)
- Translate StatusBadge trade status labels (exchange namespace)
- Create navigation.json translation files for es, en, ca
- Create exchange.json translation files for status/direction/transfer labels
- Update IntlProvider to load navigation and exchange namespaces
- Update frontend tests to expect Spanish translations (default language)
- Configure Playwright to use English language for e2e tests via storageState
- Fix test expectations to match translated strings

All frontend and e2e tests passing.
2025-12-25 22:06:39 +01:00
f86ec8b62d
Phase 2: Language Context & Selector - Add language dropdown to Header and auth pages
- Create LanguageSelector component with dropdown (shows flag + name)
- Add LanguageSelector to Header (right side, near user email/logout)
- Add LanguageSelector to login, signup, and signup/[code] pages
- Create test-utils.tsx with renderWithProviders helper
- Add vitest.setup.ts to mock localStorage
- Update all test files to use renderWithProviders
- Language selector persists choice in localStorage
- HTML lang attribute updates dynamically based on selected language

All frontend and e2e tests passing.
2025-12-25 21:54:19 +01:00
f7553df05d
Phase 1: Infrastructure setup - Install next-intl and create basic i18n structure
- Install next-intl package
- Create LanguageProvider hook with localStorage persistence
- Create IntlProvider component for next-intl integration
- Create Providers wrapper component
- Update layout.tsx to include providers and set default lang to 'es'
- Create initial translation files (common.json) for es, en, ca
- Fix pre-existing TypeScript errors in various pages

All tests passing, build successful.
2025-12-25 21:50:34 +01:00
1a47b3643f
Extract reusable UI components to reduce DRY violations
- Created StatusBadge component: Standardizes status badge display
  - Supports tradeStatus prop for trade-specific styling
  - Supports variant prop for simple badges (success/error/ready)
  - Eliminates repetitive badge style combinations

- Created EmptyState component: Standardizes empty state display
  - Handles loading and empty states consistently
  - Supports message, hint, and action props
  - Used across trades, invites, admin pages

- Created ConfirmationButton component: Standardizes confirmation flows
  - Two-step confirmation pattern (action -> confirm/cancel)
  - Supports different variants (danger/success/primary)
  - Handles loading states automatically
  - Used for cancel, complete, no-show actions

- Migrated pages to use new components:
  - trades/page.tsx: StatusBadge, EmptyState, ConfirmationButton
  - trades/[id]/page.tsx: StatusBadge
  - invites/page.tsx: StatusBadge, EmptyState
  - admin/trades/page.tsx: StatusBadge, EmptyState, ConfirmationButton
  - admin/invites/page.tsx: StatusBadge

Benefits:
- Eliminated ~50+ lines of repetitive badge styling code
- Consistent UI patterns across all pages
- Easier to maintain and update styling
- Better type safety

All tests passing (32 frontend, 33 e2e)
2025-12-25 21:40:07 +01:00
b86b506d72
Refactor frontend: Add reusable hooks and components
- 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)
2025-12-25 21:30:35 +01:00
a6fa6a8012
Refactor API layer into structured domain-specific modules
- 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
2025-12-25 20:32:11 +01:00
6d0f125536
refactor(frontend): break down large Exchange page component
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.
2025-12-25 19:11:23 +01:00
3beb23a765
refactor(frontend): improve code quality and maintainability
- Extract API error handling utility (utils/error-handling.ts)
  - Centralize error message extraction logic
  - Add type guards for API errors
  - Replace duplicated error handling across components

- Create reusable Toast component (components/Toast.tsx)
  - Extract toast notification logic from profile page
  - Support auto-dismiss functionality
  - Consistent styling with shared styles

- Extract form validation debouncing hook (hooks/useDebouncedValidation.ts)
  - Reusable debounced validation logic
  - Clean timeout management
  - Used in profile page for form validation

- Consolidate duplicate styles (styles/auth-form.ts)
  - Use shared style tokens instead of duplicating values
  - Reduce code duplication between auth-form and shared styles

- Extract loading state component (components/LoadingState.tsx)
  - Standardize loading UI across pages
  - Replace duplicated loading JSX patterns
  - Used in profile, exchange, and trades pages

- Fix useRequireAuth dependency array
  - Remove unnecessary hasPermission from dependencies
  - Add eslint-disable comment with explanation
  - Improve hook stability and performance

All frontend tests pass. Linting passes.
2025-12-25 19:04:45 +01:00
db181b338c
Complete repository delegation - remove remaining direct db operations
- 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
2025-12-25 18:57:55 +01:00
33aa8ad13b
Delegate exchange persistence to ExchangeRepository
- 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
2025-12-25 18:54:29 +01:00
c4594a3f73
Delegate invite persistence to InviteRepository
- Add create(), update(), and reload_with_relationships() methods to InviteRepository
- Update InviteService to use repository methods instead of direct db operations
2025-12-25 18:52:52 +01:00
04333d210b
Delegate user persistence to UserRepository
- Add create() and update() methods to UserRepository
- Update ProfileService to use repository.update()
- Update AuthService to use repository.create()
2025-12-25 18:52:23 +01:00
17aead2e21
Delegate availability persistence to AvailabilityRepository
- Add create() and create_multiple() methods to AvailabilityRepository
- Update AvailabilityService to use repository methods instead of direct db operations
2025-12-25 18:51:55 +01:00
4cb561d54f
Delegate price persistence to PriceRepository
- Add create() method to PriceRepository
- Update PriceService to use repository.create() instead of direct db operations
2025-12-25 18:51:24 +01:00
280c1e5687
Move slot expansion logic to ExchangeService
- 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
2025-12-25 18:42:46 +01:00
c3a501e3b2
Extract availability logic to AvailabilityService
- 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
2025-12-25 18:31:13 +01:00
badb45da59
Extract price logic to PriceService
- 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
2025-12-25 18:30:26 +01:00
168b67acee
refactors 2025-12-25 18:27:59 +01:00