Content
An infinite scroll component for displaying content sections with multiple card styles and customizable layouts
π¦ Installation
β Prerequisites
π Before you start, ensure you have:
- Installed
@zezosoft/zezo-ott-api-clientpackage - Installed
react-infinite-scroll-componentpackage - Installed
swiperpackage (for card components) - Installed
framer-motionpackage (for slider animations) - Configured your API client with proper authentication
π Quick Start
The Content component displays sections of content with infinite scroll. Each section can have different styles (cards, sliders, top 10, etc.) based on the type field in your section data.
π‘ Basic Usage Example
import Content from "@/components/zezo/Content/Content";
import type { ISection, IContentData, IWhoamiData } from "@zezosoft/zezo-ott-api-client";
// 1. Prepare your sections data
const sections: ISection[] = [
{
data: [
{
_id: "section-1",
name: "Trending Now",
type: "normal", // Section type (see supported types below)
category: { _id: "1", name: "Movies", slug: "movies" },
content: {
data: contentArray, // IContentData[] - your actual content items
meta: {
pagination: {
page: 1,
limit: 20,
length: 20,
total: 100,
hasNextPage: true,
nextPage: 2,
},
},
},
},
],
meta: {
pagination: {
page: 1,
limit: 10,
length: 1,
total: 10,
hasNextPage: false,
nextPage: null,
},
},
},
];
// 2. Use the component
function ContentPage() {
const [sectionsData, setSectionsData] = React.useState<ISection[]>(sections);
const [isLoading, setIsLoading] = React.useState(false);
const [hasNext, setHasNext] = React.useState(true);
const loadMore = async () => {
setIsLoading(true);
try {
const nextPage = sectionsData[0]?.meta?.pagination?.nextPage || 2;
// Fetch next page from your API
const response = await fetch(`/api/sections?page=${nextPage}`);
const newData: ISection = await response.json();
// Append new sections
setSectionsData(prev => [...prev, newData]);
setHasNext(newData.meta.pagination.hasNextPage);
} catch (error) {
console.error("Failed to load more:", error);
} finally {
setIsLoading(false);
}
};
return (
<Content
data={sectionsData}
isLoading={isLoading}
hasNextPage={hasNext}
next={loadMore}
onClick={(item: IContentData) => {
// Navigate to content details
router.push(`/details/${item.type}/${item.slug}`);
}}
userSession={userData} // Optional: For continue watching
/>
);
}π Complete Data Example
Here's a complete example of how your IContentData should be structured:
// Example IContentData object
const exampleContent: IContentData = {
_id: "content-123",
name: "The Dark Knight",
slug: "the-dark-knight",
u_age: "18+",
description: "When the menace known as the Joker wreaks havoc...",
duration: "152",
rating: 9.0,
source_link: "https://example.com/video.m3u8",
source_type: "HLS",
trailer_source_link: "https://example.com/trailer.m3u8",
trailer_source_type: "HLS",
language: [
{ _id: "lang-1", name: "English" },
{ _id: "lang-2", name: "Hindi" }
],
cast: [
{
_id: "cast-1",
name: "Christian Bale",
type: "actor",
avatar: "https://example.com/avatar.jpg",
castType: "lead"
}
],
poster: "https://example.com/poster.jpg",
thumbnail: "https://example.com/thumbnail.jpg",
views: 1000000,
tags: ["action", "crime", "drama"],
job_id: null,
seasons: null, // For movies, this is null
status: "PUBLIC",
trash: false,
type: "movie", // "movie" | "series" | "live_stream"
content_offering_type: "PREMIUM", // "FREE" | "PREMIUM" | "BUY_OR_RENT"
updated_by: "user-123",
created_by: "user-123",
createdAt: "2024-01-01T00:00:00.000Z",
updatedAt: "2024-01-01T00:00:00.000Z",
category: [
{ _id: "cat-1", name: "Action" },
{ _id: "cat-2", name: "Crime" }
],
genres: [
{ _id: "genre-1", name: "Action" },
{ _id: "genre-2", name: "Drama" }
],
subtitles: [
{
title: "English",
language: "en",
type: "application/x-subrip",
url: "https://example.com/subtitle.srt"
}
]
};π Props
| Prop | Type | Required | Description |
|---|---|---|---|
| data | ISection[] | Yes | Array of section objects containing content data and pagination metadata |
| isLoading | boolean | Optional | Loading state indicator (default: false) |
| next | () => void | Optional | Callback function called when user scrolls to load more content |
| hasNextPage | boolean | Optional | Whether more pages are available for infinite scroll |
| customComponents | ICustomComponentsForSections[] | Optional | Array of custom components to override default section renderers |
| href | string | Optional | Base URL path for content links |
| onClick | (item: IContentData) => void | Optional | Callback function called when user clicks on a content item |
| userSession | IWhoamiData | null | Optional | User session data for personalized content (e.g., continue watching) |
π¨ Supported Section Types
The component supports various section types defined in the type field:
normal
Standard grid layout with BasicCard
card_style_2 - card_style_6
Alternative card style variants
slider
Horizontal scrolling slider with SliderV2
slider_style_2
Alternative slider style variant
card_series_featured_style_1
Featured series card layout
new_releases
New releases section layout
top_10
Top 10 ranked content with Top10 card
continue_watching
Continue watching section (requires userSession)
π§© Key Interfaces
The component uses interfaces from @zezosoft/zezo-ott-api-client:
// ISection structure
interface ISection {
data: ISectionData[]; // Array of section data
meta: { // Pagination metadata
pagination: {
page: number;
limit: number;
length: number;
total: number;
hasNextPage: boolean;
nextPage: number | null;
};
};
}
// ISectionData structure
interface ISectionData {
_id: string;
name: string; // Section title
type: string; // Section type (see supported types above)
category: {
_id: string;
name: string;
slug: string;
};
content: {
data: IContentData[]; // Array of content items
meta: {
pagination: {
page: number;
limit: number;
length: number;
total: number;
hasNextPage: boolean;
nextPage: number | null;
};
};
};
}
// ICustomComponentsForSections
interface ICustomComponentsForSections {
type: string; // Section type to override
component: React.ReactElement; // Custom component to render
}π¦ Required Packages
Install these packages before using Content:
npm install @zezosoft/zezo-ott-api-client react-infinite-scroll-component swiper framer-motion react-intersection-observer
# Or with pnpm
pnpm add @zezosoft/zezo-ott-api-client react-infinite-scroll-component swiper framer-motion react-intersection-observer
# Or with yarn
yarn add @zezosoft/zezo-ott-api-client react-infinite-scroll-component swiper framer-motion react-intersection-observerβ οΈ Important Notes:
- Make sure
swiper/cssis imported in your global CSS or component - For SliderV2, ensure
@zezosoft/react-playeris installed if using video trailers - Theme colors must be configured via
getThemeColors()from@/config/theme
β¨ Features
βΎοΈ Infinite Scroll
Automatically loads more sections as user scrolls down
π¨ Multiple Card Styles
Supports various card styles: normal, slider, top_10, continue_watching, etc.
π§ Custom Components
Override default section renderers with custom components
π€ User Session Support
Personalize content based on user session (e.g., continue watching)
π±οΈ Click Handlers
Optional onClick callback for content items
β³ Loading States
Built-in loading state support
π Custom Links
Customizable href base path for content links
π± Responsive
Mobile-first responsive design
π Dark Mode
Automatic theme support
π§© Modular
Sections component handles individual section rendering
π Component Structure
Main import path: @/components/zezo/Content/Content
components/zezo/Content/
βββ Content.tsx // Main component with infinite scroll
βββ Sections.tsx // Section renderer (handles different types)
βββ Styles/
β βββ Cards/
β β βββ BasicCard/ // Standard card layout
β β βββ Top10/ // Top 10 ranked cards
β β βββ ContinueWatching/ // Continue watching cards
β βββ Slider/
β βββ SliderV2.tsx // Slider component
βββ _components/
βββ Loader.tsx // Loading component
βββ Error.tsx // Error componentπ§© All Components (34 Total)
The Content module includes 34 components organized into different categories:
1οΈβ£ Main Components (2)
Content.tsxMain component with infinite scroll wrapper
Sections.tsxSection renderer that handles different section types
2οΈβ£ Card Components (4)
BasicCard.tsxStandard horizontal scrolling card layout with Swiper, hover effects, and play/favorite buttons
Top10.tsxTop 10 ranked content with numbered badges (1-10)
ContinueWatching.tsxContinue watching section with progress bars and episode info (requires userSession)
InteractiveCard.tsxInteractive card with scale animations on hover and expanded details
3οΈβ£ Slider Components (3)
See live previews at Slider Preview
Slider.tsxBasic slider with framer-motion animations and auto-play
SliderV1.tsxHero slider with thumbnail strip, promo text, and MainHomeTabAndMobileSlider
SliderV2.tsxAdvanced slider with trailer auto-play, mute controls, and video player integration
4οΈβ£ ContentDetails Component (19)
Main content details page component with all subcomponents:
ContentDetails.tsxMain content details component with video player integration
Subcomponents:
DetailsOverlayV2.tsx- Content overlay with banners, buttons, and metadataTabSwitcher.tsx- Tab navigation component (Episodes, Related, Details)DetailsTab.tsx- Content details tab with cast, genres, languagesEpisodesTab.tsx- Episodes list tab for series contentRelatedTab.tsx- Related content recommendations tabPlayButton.tsx- Play button componentTrailerButton.tsx- Trailer play buttonShareButton.tsx- Share content buttonShareModal.tsx- Share modal dialogfavoriteButton.tsx- Favorite/Bookmark buttonSeasonSelectorDropdown.tsx- Season selector dropdown for seriesReadMoreText.tsx- Expandable read more text componentRecContent.tsx- Recommended content componentRentOrBuyIcon.tsx- Rent/Buy icon indicatorRentTypeWithInfo.tsx- Rent type information displayGradientOverlay.tsx- Gradient overlay componentDropdown.tsx- Dropdown componentVideoPlayerProvider.tsx- Video player context provider
5οΈβ£ Skeleton/Loading Components (4)
SkeletonLoader.tsxMain skeleton loader component
BasicCardSkeleton.tsxSkeleton for card layouts
SliderSkeleton.tsxSkeleton for slider layouts
LazyImage.tsxLazy loading image component with intersection observer
6οΈβ£ Helper Components (2)
Loader.tsxLoading spinner component
Error.tsxError display component
7οΈβ£ Hooks (1)
buildPlaylist.tsHook to build video player playlist from content data
π» Component Usage Examples
ContentDetails Component
import ContentDetails from "@/components/zezo/Content/_components/ContentDetails/ContentDetails";
import type { IContentData, IWhoamiData, IContentSeasons } from "@zezosoft/zezo-ott-api-client";
<ContentDetails
content={contentData} // IContentData
userSession={userSession} // IWhoamiData | null
seasons={seasonsData} // IContentSeasons[] | null
seasonsData={seasonsData} // IContentSeasons[] | null
isBuyOrRent={false} // boolean
isTabSwitcher={true} // boolean
buttons={[
{
type: "play",
label: "Play",
icon: <PlayIcon />,
onClick: ({ value }) => handlePlay(value)
},
{
type: "favorite",
label: "Add to Favorites",
icon: <HeartIcon />,
onClick: ({ value }) => handleFavorite(value),
isLoadingFavorite: false
}
]}
moreData={{
relatedContent: relatedSection,
moreDetails: {
description: contentData.description,
cast: contentData.cast,
genres: contentData.genres
},
episodeTab: {
onClick: (episode) => handleEpisodeClick(episode)
}
}}
/>BasicCard Component
import BasicCard from "@/components/zezo/Content/Styles/Cards/BasicCard/BasicCard";
<BasicCard
title="Trending Now"
data={contentArray} // IContentData[]
href="/details" // Optional: base URL
userSession={userSession} // Optional: IWhoami | null
/>Slider Component
import Slider from "@/components/zezo/Content/Styles/Slider/Slider";
<Slider
data={contentArray} // IContentData[]
onWatchNow={(item) => { // Optional callback
console.log("Watch:", item.name);
}}
/>SliderV1 Component
import SliderV1 from "@/components/zezo/Content/Styles/Slider/SliderV1";
<SliderV1
data={contentArray} // IContentData[]
forceDesktopForPreview // Optional: true to always show desktop layout
/>SliderV2 Component
import SliderV2 from "@/components/zezo/Content/Styles/Slider/SliderV2";
<SliderV2
data={featuredContent} // IContentData[]
onWatchNow={(item) => { // Optional callback
console.log("Watch:", item.name);
}}
/>π§ Common Issues & Solutions
β Issue: Sections not rendering
Cause: Data structure doesn't match expected format
Solution: Ensure your data follows the ISection interface exactly. Check that:
datais an array ofISectionDataobjects- Each section has
content.dataarray withIContentData[] - Pagination metadata is correctly structured
β Issue: Infinite scroll not working
Cause: Missing next callback or incorrect hasNextPage
Solution:
- Provide the
nextcallback function - Set
hasNextPagetotruewhen more data is available - Update
hasNextPagetofalseafter loading all pages
β Issue: Continue watching not showing
Cause: Missing userSession prop
Solution: Pass the userSession prop with user data containing watch history sessions
β Issue: Cards not scrolling horizontally
Cause: Swiper CSS not imported or missing dependencies
Solution:
// Add this to your global CSS or component file
import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/free-mode";β Issue: Type errors with IContentData
Cause: Type mismatch or missing type definitions
Solution: Ensure you're importing types from the correct package:
import type {
IContentData,
ISection,
ISectionData,
IWhoamiData,
IContentSeasons
} from "@zezosoft/zezo-ott-api-client";β¨ Best Practices
β Performance Tips
- Use
React.memo()for custom components passed viacustomComponents - Implement proper pagination to avoid loading too much data at once
- Use
LazyImagecomponent for better image loading performance - Consider using virtual scrolling for large datasets
π‘ Code Organization
- Create a separate data fetching hook (e.g.,
useContentSections) - Handle loading and error states properly
- Use TypeScript for type safety
- Group custom components by section type for better maintainability
π¨ Customization Tips
- Override default section renderers using
customComponentsprop - Customize card styles by importing individual card components
- Use theme colors via
getThemeColors()for consistent styling - Modify
hrefprop to customize navigation paths
π Import Paths Reference
Quick reference for importing all Content module components:
// Main Components
import Content from "@/components/zezo/Content/Content";
import Sections from "@/components/zezo/Content/Sections";
// Card Components
import BasicCard from "@/components/zezo/Content/Styles/Cards/BasicCard/BasicCard";
import Top10 from "@/components/zezo/Content/Styles/Cards/Top10/Top10";
import ContinueWatching from "@/components/zezo/Content/Styles/Cards/ContinueWatching/ContinueWatching";
import InteractiveCard from "@/components/zezo/Content/Styles/Cards/BasicCard/InteractiveCard";
// Slider Components
import Slider from "@/components/zezo/Content/Styles/Slider/Slider";
import SliderV1 from "@/components/zezo/Content/Styles/Slider/SliderV1";
import SliderV2 from "@/components/zezo/Content/Styles/Slider/SliderV2";
// ContentDetails
import ContentDetails from "@/components/zezo/Content/_components/ContentDetails/ContentDetails";
// Subcomponents (if needed individually)
import DetailsOverlayV2 from "@/components/zezo/Content/_components/ContentDetails/_components/DetailsOverlayV2";
import TabSwitcher from "@/components/zezo/Content/_components/ContentDetails/_components/Tabs/TabSwitcher";
import PlayButton from "@/components/zezo/Content/_components/ContentDetails/_components/PlayButton";
// ... and more
// Skeleton Components
import SkeletonLoader from "@/components/zezo/Content/Skeleton-components/SkeletonLoader";
import LazyImage from "@/components/zezo/Content/Skeleton-components/LazyImage";
// Helper Components
import Loader from "@/components/zezo/Content/_components/Loader";
import Error from "@/components/zezo/Content/_components/Error";
// Hooks
import { buildPlaylist } from "@/components/zezo/Content/hooks/buildPlaylist";π Additional Resources
π API Client Documentation
Refer to @zezosoft/zezo-ott-api-client package documentation for complete interface definitions
π¨ Theming
Configure dynamic theme colors via NEXT_PUBLIC_THEME_COLORS environment variable
π± Responsive Design
All components are mobile-first and responsive. Cards adapt to screen size automatically
π Dark Mode
Automatic dark mode support via Tailwind CSS classes. No additional configuration needed
