A modern streaming platform interface built with Next.js, featuring movies and TV series browsing, search functionality, and personal watchlist management.
- Framework: Next.js 15 with App Router
- Styling: SCSS with CSS Modules
- Testing: Jest + React Testing Library
- API: TMDB API
- State Management: React Hooks
- Type Safety: TypeScript
app/
├── (pages)/ # Page routes
│ ├── page.tsx # Home page
│ ├── explore/ # Search and explore page
│ ├── movie/[id]/ # Movie detail page
│ ├── tv/[id]/ # TV series detail page
│ └── watchlist/ # Watchlist page
├── api/ # API routes
│ ├── search/ # Search API endpoints
│ └── watchlist/ # Watchlist API endpoints
├── common/ # Shared components and utilities
│ ├── components/ # Reusable UI components
│ │ ├── Carousel/ # Carousel component
│ │ ├── MediaCard/ # Media card component
│ │ └── layouts/ # Layout components
│ ├── lib/ # Utility functions
│ │ ├── api-client.ts # API client utility
│ │ ├── utils.ts # Common utilities
│ │ └── watchlist.ts # Watchlist management
│ └── types/ # Shared TypeScript types
└── features/ # Feature-based modules
├── home/ # Home page features
├── explore/ # Search and explore features
├── movie/ # Movie-related features
├── tv/ # TV series features
└── watchlist/ # Watchlist management
The application follows a feature-based architecture with the following key principles:
-
Feature Isolation: Each feature (home, explore, movie, tv, watchlist) is self-contained with its own:
- Components
- Services
- Types
- Styles
- Tests
-
Common Layer: Shared functionality is organized in the common directory:
- Reusable UI components
- Utility functions
- Type definitions
- API client
-
API Layer:
- Server-side API routes in
app/api
- Client-side API services in feature directories
- Centralized API client for TMDB integration
- Server-side API routes in
The application uses a functional programming pattern with the pipe
function to create clean and composable data transformations, especially in API services. Here's how it works in the TV series service:
// Example from app/features/tv/services/tv.ts
export const getTVSeriesDetail = pipe(
async (id: string) => await apiClient(`/tv/${id}`),
getEpisodesBySeasons,
transformTVSeriesDetail
);
This creates a pipeline that:
- Fetches the base TV series data
- Enriches it with episode data
- Transforms the response into our application model
The pipe function enables:
- Clean composition of async operations
- Separation of concerns
- Readable data transformation flow
- Maintainable and testable code
Example flow:
Input: TV Series ID
↓
Step 1: Fetch base data from TMDB API
↓
Step 2: Fetch episodes for each season
↓
Step 3: Transform data to application model
↓
Output: TVSeriesDetail
Each step in the pipeline:
// 1. Initial API call
(id: string) => await apiClient(`/tv/${id}`)
// 2. Enrich with episodes
const getEpisodesBySeasons = async (response: TVSeriesDetailResponse) => {
const batch = response.seasons.map((season) =>
getEpisodes(response.id, season.season_number)
);
const seasons = await Promise.all(batch);
return { ...response, seasons };
}
// 3. Transform to application model
const transformTVSeriesDetail = (data: TVSeriesDetailResponse): TVSeriesDetail => ({
id: data.id,
title: data.name,
// ... transform other fields
});
This pattern is used throughout the application for handling API responses and data transformations in a clean and maintainable way.
-
Local State:
- React hooks for component-level state
- Context for theme management
- URL state for navigation
-
Persistence:
- Local storage for watchlist
- Server-side caching for API responses
-
Core Components:
MediaCard
: Reusable card for movies/TV showsCarousel
: Horizontal scrolling listSearchBar
: Debounced search inputActionButton
: Watchlist management
-
Layout Components:
SideBar
: Navigation sidebarBanner
: Hero sectionGrid
: Responsive grid layout
-
API Integration:
Client Request → Next.js API Route → TMDB API → Response Transform → Client
-
Watchlist Flow:
User Action → Local Storage Update → UI Update
-
Search Flow:
User Input → Debounce → API Request → Results Transform → UI Update
-
Unit Tests:
- Component testing with React Testing Library
- Utility function testing
- Mock API responses
-
Integration Tests:
- Feature-level testing
- API route testing
- State management testing
- Clone the repository
- Install dependencies:
yarn install
- Set up environment variables:
ACCESS_TOKEN=your_tmdb_access_token
BASE_URL=https://api.themoviedb.org/3
IMAGE_BASE_URL=https://image.tmdb.org/t/p
- Run development server:
yarn dev
- Run tests:
yarn test
- Fork the repository
- Create your feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request
MIT License
To learn more about Next.js, take a look at the following resources:
- Next.js Documentation - learn about Next.js features and API.
- Learn Next.js - an interactive Next.js tutorial.
You can check out the Next.js GitHub repository - your feedback and contributions are welcome!
The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.
Check out our Next.js deployment documentation for more details.