Skip to main content

Challenge — Movie Dashboard

Objective

Build a React SPA that consumes the TMDB API to display and search movies.

Requirements

Core Features (60 points)

  • Home page: trending movies grid (poster, title, rating)
  • Search: search movies by title with debounced input
  • Movie detail page: full info, cast, similar movies
  • Favorites: save/remove movies with localStorage persistence
  • Pagination or infinite scroll

Technical Requirements (40 points)

  • React Router with at least 3 routes: /, /movie/:id, /favorites
  • TanStack Query for all data fetching (no raw fetch in components)
  • Loading skeletons on all data-dependent views
  • Error boundaries / error states
  • TypeScript — no any, all API responses typed
  • Tailwind CSS for styling

Routes

/              — Trending movies + search
/movie/:id — Movie detail
/favorites — Saved favorites

API Client

// src/lib/tmdb.ts
const BASE_URL = 'https://api.themoviedb.org/3';
const TOKEN = import.meta.env.VITE_TMDB_TOKEN;

async function tmdbFetch<T>(path: string, params?: Record<string, string>): Promise<T> {
const url = new URL(`${BASE_URL}${path}`);
if (params) {
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
}

const res = await fetch(url.toString(), {
headers: { Authorization: `Bearer ${TOKEN}` },
});

if (!res.ok) throw new Error(`TMDB error: ${res.status}`);
return res.json();
}

export const tmdb = {
trending: () => tmdbFetch<MoviesResponse>('/trending/movie/week'),
search: (query: string, page = 1) =>
tmdbFetch<MoviesResponse>('/search/movie', { query, page: String(page) }),
movie: (id: number) => tmdbFetch<MovieDetail>(`/movie/${id}`),
credits: (id: number) => tmdbFetch<CreditsResponse>(`/movie/${id}/credits`),
};

Grading

CriteriaPoints
Trending movies displayed10
Search with debounce15
Movie detail page15
Favorites with localStorage10
React Router navigation10
TanStack Query usage10
Loading and error states10
TypeScript types for API10
Responsive layout5
Polished UI5
Total100

Bonus

  • Dark mode toggle
  • Genre filter on home page
  • Watch trailer button (embed YouTube)
  • Share button that copies the movie URL
  • A11y: keyboard navigation, proper ARIA labels