All Stories
7-6-3-cash-out-uiReadyEpic 7.6
Story 7.6.3: Cash Out UI
Status: ready-for-dev
Tasks
- **Task 1: Create CashOutButton Component** (AC: #1, #2, #3)
- 1.1: Create `/client/src/components/betting/cash-out-button.tsx` file
- 1.2: Define TypeScript interfaces (CashOutOffer, CashOutButtonProps)
- 1.3: Implement useEffect polling hook for 5-second updates
- 1.4: Add GET `/api/v1/betting/cash-out/{betId}/offer` API call
- 1.5: Implement conditional rendering (only show if available)
- 1.6: Add profit/loss calculation and color logic (green/red)
- 1.7: Style button with yellow background, proper spacing, mobile touch targets
- 1.8: Add click handler to open confirmation modal
- 1.9: Add loading state indicator for value updates
- 1.10: Handle polling cleanup on unmount and when modal opens
- **Task 2: Create CashOutConfirmModal Component** (AC: #4, #5)
- 2.1: Create `/client/src/components/betting/cash-out-confirm-modal.tsx` file
- 2.2: Use shadcn/ui Dialog component as base
- 2.3: Add props interface (value, stake, profitLoss, onConfirm, onCancel, isLoading)
- 2.4: Display original stake in modal body
- 2.5: Display cash out value prominently (large, bold font)
- 2.6: Display profit/loss with green/red coloring and border separator
- 2.7: Add Cancel button (outline variant, disabled during loading)
- 2.8: Add Confirm button with loading spinner (Loader2 icon)
- 2.9: Prevent modal close during execution (disable onOpenChange when loading)
- 2.10: Ensure responsive layout for mobile devices
- **Task 3: Implement Cash Out Execution Logic** (AC: #5, #6)
- 3.1: Create executeCashOut async function in CashOutButton
- 3.2: Add POST `/api/v1/betting/cash-out/{betId}/execute` API call
- 3.3: Send accepted_value and offer_timestamp in request body
- 3.4: Add isExecuting state to manage button/modal loading
- 3.5: Handle success response (show toast, refresh bet list)
- 3.6: Handle error responses (show specific error messages)
- 3.7: Handle odds_changed scenario (update offer with new_value)
- 3.8: Close modal only after success or cancellation
- 3.9: Add timeout handling for long-running requests
- 3.10: Cleanup polling interval after successful cash out
- **Task 4: Add Toast Notifications** (AC: #6)
- 4.1: Import toast utility from shadcn/ui or react-hot-toast
- 4.2: Implement success toast with formatted cash out amount
- 4.3: Show updated balance in success toast (e.g., "New balance: $123.45")
- 4.4: Implement error toast for failed cash outs
- 4.5: Add specific error messages for each CashOutResult type:
- 4.5.1: EXPIRED - "Cash out offer expired. Refreshing..."
- 4.5.2: ODDS_CHANGED - "Odds have changed. New value: $X.XX"
- 4.5.3: ALREADY_SETTLED - "This bet has already been settled"
- 4.5.4: ERROR - Generic error message with retry suggestion
- 4.6: Add toast auto-dismiss timeout (3-5 seconds)
- 4.7: Ensure toast positioning doesn't interfere with bet list
- **Task 5: Integrate with Bet List** (AC: #1, #3, #6)
- 5.1: Locate existing bet list component (e.g., `/client/src/components/betting/bet-history.tsx`)
- 5.2: Import CashOutButton component
- 5.3: Add CashOutButton to each active bet row/card
- 5.4: Pass betId and stake props to CashOutButton
- 5.5: Ensure button placement doesn't disrupt bet card layout
- 5.6: Add callback to refresh bet list after successful cash out
- 5.7: Test bet status update after cash out (PENDING → CASHED_OUT)
- 5.8: Verify button disappears after bet is cashed out
- 5.9: Test responsive layout on mobile (stacked vs. inline)
- 5.10: Add loading skeleton while bet list fetches
- **Task 6: Error Handling & Edge Cases** (AC: #3, #6)
- 6.1: Handle network failures during offer fetch (show last known value)
- 6.2: Handle 401 Unauthorized (redirect to login)
- 6.3: Handle 404 Not Found (bet doesn't exist)
- 6.4: Handle 400 Bad Request (validation error)
- 6.5: Handle 500 Server Error (generic error message)
- 6.6: Add retry logic for transient failures (exponential backoff)
- 6.7: Handle race condition (bet settled while modal open)
- 6.8: Validate offer hasn't expired before showing modal
- 6.9: Handle market suspension (show "Cash Out Unavailable" message)
- 6.10: Test with slow network (3G throttling)
- **Task 7: Mobile Optimization** (AC: #1, #4)
- 7.1: Test button touch targets (minimum 44px × 44px)
- 7.2: Test modal on small screens (320px width)
- 7.3: Ensure modal doesn't overflow viewport
- 7.4: Add proper viewport meta tag if missing
- 7.5: Test scroll behavior when modal is open (prevent body scroll)
- 7.6: Test button wrapping on narrow screens
- 7.7: Optimize font sizes for mobile readability
- 7.8: Test with iOS Safari and Android Chrome
- 7.9: Add touch-friendly spacing between buttons
- 7.10: Test landscape orientation on mobile devices
- **Task 8: Testing & Validation** (AC: All)
- 8.1: Test cash out button appears only on eligible bets
- 8.2: Test 5-second polling updates cash out value
- 8.3: Test profit/loss colors (green for positive, red for negative)
- 8.4: Test confirmation modal displays correct values
- 8.5: Test successful cash out updates balance and bet status
- 8.6: Test error scenarios (expired, odds changed, already settled)
- 8.7: Test modal cannot be closed during execution
- 8.8: Test polling stops when modal is open
- 8.9: Test responsive design on mobile and desktop
- 8.10: Verify accessibility (keyboard navigation, screen reader)
Progress
Tasks0/8
Acceptance Criteria0
Total Tasks8