Requires Node.js 20.19+ and the TMDB API key supplied with the assignment.
- Run
npm install. - Copy
.env.exampleto.env. - Replace the placeholder value in
.envwith the supplied TMDB key. - Run
npm run dev.
The key is used by the browser client and must never be committed. .env is
gitignored; .env.example is the safe template.
Simple Cinema is a one-page TMDB browser. It fetches the first page of discover results, lets the user filter by genre and sort by rating or release date, and renders the results as a responsive poster grid.
Filtering and sorting happen in the TMDB request, not over the 20 movies already returned. Every request also requires at least 500 ratings so changing the sort order rearranges a meaningful, consistent result set.
- Genre options fetched from TMDB and sorted alphabetically.
- Server-side genre filtering and rating or release-date sorting.
- Responsive movie grid with poster, title, rating, and release year.
- Overview reveal available through pointer hover and keyboard focus.
- Previous results remain visible and dimmed while a new query loads.
- Concise loading, empty, and error messages.
- Safe fallbacks for missing posters, release dates, overviews, and result arrays.
- Request cancellation that prevents stale responses from replacing newer results.
| Path | Purpose |
|---|---|
src/App.jsx |
Page shell and heading. |
src/lib/http.js |
Generic JSON request handling with no TMDB knowledge. |
src/styles/tokens.css |
Semantic colors, spacing, radius, motion, and global resets. |
src/features/movies/constants.js |
TMDB endpoints, vote floor, sort options, and default query. |
src/features/movies/api/tmdb.js |
Discover URL construction, authenticated requests, genres, and poster URLs. |
src/features/movies/hooks/useMovies.js |
Movie request lifecycle, cancellation, stale-result retention, and derived pending state. |
src/features/movies/hooks/useGenres.js |
One-time genre reference-data request. |
src/features/movies/components/MoviesPage.jsx |
Query ownership and loading, empty, error, and result rendering. |
src/features/movies/components/QueryControls.jsx |
Accessible genre and sort controls. |
src/features/movies/components/MovieGrid.jsx |
Responsive result list and stale state. |
src/features/movies/components/MovieCard.jsx |
Nullable-field guards and the hover/focus overview interaction. |
The movies feature exposes only MoviesPage through src/features/movies/index.js.
API, hooks, and components remain private to the feature.
| Decision | Reason |
|---|---|
| Vite instead of Next.js | This is one client-rendered page with no routing or server-rendering need. |
| Plain JavaScript instead of TypeScript | It keeps the take-home focused on product behavior and limits one-night setup overhead. A production version would use TypeScript. |
| Native fetch hook instead of a data-fetching library | One movie endpoint does not justify another dependency. The custom hook makes cancellation and stale-response protection explicit. |
| CSS Modules and custom properties instead of a CSS framework | The responsive grid, interaction states, and design tokens remain visible and locally scoped. |
| TMDB-side filtering and sorting | Reordering one returned page would not produce the true top 20 across TMDB's full catalogue. |
| A 500-rating floor on every request | It prevents barely rated movies from dominating “Top rated” and keeps result membership consistent across sort orders. |
| Query state stays in React | Refreshing resets two controls, an acceptable tradeoff for this assignment. A router, URL synchronization, or storage would add lifecycle and validation code the brief does not require. |
| Text loading, empty, and error states | They prevent blank screens without adding skeleton components, automatic retries, retry controls, or a dedicated API-key screen. Setup remains in this README. |
| No alternate layout or rating-based card sizing | A single consistent grid is easier to scan and keeps optional display preferences out of scope. |
| No justfile | The assignment explicitly requires the standard npm workflow, and the scripts in package.json cover every project command. |
| Command | Purpose |
|---|---|
npm run dev |
Start the Vite development server. |
npm run test |
Run the Vitest and Testing Library suite once. |
npm run lint |
Run ESLint. |
npm run format:check |
Verify Prettier formatting. |
npm run build |
Create the production build. |
- Put shareable filter state in the URL once preserving and linking views matters.
- Move the API key behind a server endpoint in a production application.
- Adopt TypeScript and a data-fetching library as the API surface grows.