Skip to main content

Movie Swiping MVP: In-Depth Integration Guide

This document details the integration of the robust, scalable movie swiping MVP (Tinder-like interface) for React Native and web, focusing on backend filtering, cache invalidation, authentication, optimistic UI/UX, and error recovery.


1. Core Concepts

  • Optimistic UI: Cards are removed from the stack immediately on swipe, before the API call completes. If the API call fails, the card is restored.
  • Error Recovery: Errors are surfaced via a Snackbar with a retry button. The UI is never blocked by API latency.
  • Backend Filtering: The backend ensures already-swiped movies are never shown again, using a scalable Postgres RPC.
  • Pagination: Movies are fetched in batches. When the stack is low, the next page is fetched automatically.
  • Authentication: All API calls include the user's access token. CORS/cookie issues are handled for both web and React Native.
  • Cache Invalidation: React Query invalidates all relevant movie and swipe queries after a successful swipe.

2. Key Files & Components

  • SwipeStack.tsx: Main UI component for the swipe stack, optimistic updates, error handling, and pagination.
  • useSwipeMutation.ts: Custom React Query mutation hook for swipes, supporting optimistic UI, rollback, and retry.
  • Backend: /api/movies/random and /api/swipes endpoints, with scalable filtering and robust error handling.

3. Optimistic UI & Error Recovery

useSwipeMutation.ts

  • Accepts onMutate, onError, and onSuccess for full optimistic UI support.
  • Exposes mutation state (isPending, error, etc.) for UI feedback.
  • Supports retry and rollback via React Query context.

Example Usage:

const swipeMutation = useSwipeMutation({
onMutate: async (swipeData) => {
// Optimistically remove card
const swipedMovie = cardStack[cardStack.length - 1]
setCardStack((prev) => prev.slice(0, -1))
return { swipedMovie }
},
onError: (err, _variables, context) => {
setSnackbarError(err.message)
if (context?.swipedMovie) setCardStack((prev) => [...prev, context.swipedMovie])
},
onSuccess: () => setSnackbarError(null),
})

SwipeStack.tsx

  • Handles swipe gestures, optimistic updates, and error display.
  • Shows a Snackbar for errors, with a retry button that re-attempts the last swipe.
  • Only shows a loading overlay when fetching more movies (not during each swipe).

Key Integration Points:

  • handleSwipe(direction): Triggers the mutation and updates local state.
  • retryLastSwipe(): Retries the last failed swipe and clears errors.
  • Snackbar: Appears at the bottom for errors, auto-hides after 4s, and supports manual retry.

4. Backend Filtering & Pagination

  • /api/movies/random uses a Postgres RPC to fetch only unswiped movies for the user, supporting efficient pagination and filtering.
  • /api/swipes records swipes, with robust error handling and user context.
  • The frontend never shows already-swiped movies, even across sessions.

5. Authentication

  • All API calls include the user's access token in the Authorization header.
  • Handles CORS/cookie issues for both web and React Native.
  • Uses a custom useAuthQuery hook to access the current session.

6. Cache Invalidation

  • After a successful swipe, React Query invalidates all random-movies queries to ensure the next fetch is up-to-date.
  • This ensures that the user never sees the same movie twice, even if they navigate away and return.

7. Best Practices

  • Optimistic UI: Always update the UI first, then sync with the backend. Use React Query's onMutate/context for rollback.
  • Error Recovery: Surface errors in a non-blocking way (snackbar, not modal). Allow retrying failed actions.
  • Pagination: Pre-fetch the next page before the stack is empty for a seamless experience.
  • Authentication: Always include the access token, and handle session expiration gracefully.
  • Debugging: Use detailed debug logs on both frontend and backend to trace user actions and API responses.

8. Example Integration Flow

  1. User swipes a card.
  2. Card is immediately removed from the stack (optimistic update).
  3. API call is made to record the swipe.
  4. If the call succeeds, cache is invalidated and the UI remains unchanged.
  5. If the call fails, the card is restored and a snackbar appears with the error and a retry button.
  6. When the stack is low, the next page of movies is fetched automatically.

9. Further Improvements

  • Add more unit/integration tests for swipe logic and API integration.
  • Expand accessibility and responsiveness.
  • Add more advanced UX patterns (e.g., undo, swipe animations, etc.).
  • Expand documentation with more React Native/web-specific tips.

For more details, see the code in SwipeStack.tsx and useSwipeMutation.ts, and the backend API routes.