🎬 Content Details
The Content Details
page displays rich metadata, trailers, watch actions, seasons, and recommended content for a movie or series. It is implemented using the DetailsContent
component, backed by powerful React Query hooks and dynamic SSR logic.
Built using:
- ✅
@zezosoft/react-ui-kit
→ContentDetails
,SkeletonLoader
, etc. - ✅ React Query → For favorites, seasons, recommendations
- ✅ App Router →
app/detail/[...slug]/page.tsx
with server functions
🗂️ Folder Structure
app/
├── detail/
│ └── [...slug]/
│ └── page.tsx # SSR route for fetching content by slug
├── components/
│ └── content/
│ ├── Content.tsx # Lists homepage sections
│ └── DetailsContent.tsx # Main detailed view component
📋 Props
Prop | Type | Description |
---|---|---|
content | IContentData | Main movie/series object with metadata |
userSession | ISession | null | Current authenticated user session |
isBuyOrRent | boolean | Indicates if the content is TVOD (buy/rent) and already purchased |
seasons | ISeasonData[] | Season data for series content |
selectedSeason | ISeasonData | Currently active season (usually seasons[0] ) |
seasonsData | ISeasonData[] | Optional – Pass complete season info separately |
isTabSwitcher | boolean | Enable/disable season tab switching |
buttons | ActionButton[] | List of UI actions like play, trailer, favorite, share |
moreData | MoreDetailsConfig | Nested data like description, crew, language, genres, etc. |
🧠 Feature Summary
Feature | Behavior |
---|---|
⭐ Favorite | Optimistically updates UI using React Query mutations |
▶️ Play | Trigger onClick() from button prop |
🎞️ Trailer | Same as above — hook into trailer modal or overlay |
📺 Seasons | If content.type === "series" , show episodes tab |
🔁 Recommendations | Uses backend section ID for similar or trending titles |
🔄 TVOD | If BUY_OR_RENT , verify entitlement before allowing playback |
🔗 Share | Custom button, supports navigator.share() or custom dialog |
⚠️ Please make sure
zezoClient
is properly configured — otherwise, the Content Details page won’t be able to load the required data.
🧩 Component: DetailsContent.tsx
This component renders a complete content detail page using the following key props:
<ZezoOttContentDetails
content={content} // Full content data object
userSession={userSession} // Current logged-in session
isBuyOrRent={isBuyOrRent} // Indicates if TVOD (buy/rent) is active
seasons={seasons} // Array of seasons (for series)
selectedSeason={seasons?.[0]} // Initially selected season
seasonsData={seasons} // Redundant but required for tab switcher
isTabSwitcher={true} // Show season/episode tabs if true
buttons={[
// List of action buttons to show
{
type: "play",
label: "Watch Now",
icon: <Play />,
onClick: () => {},
},
{
type: "trailer",
label: "Watch Trailer",
icon: <TbMovie size={36} />,
onClick: () => {},
},
{
type: "faverite",
label: isFavorite ? "Added to Watchlist" : "Add to Watchlist",
icon: isFavoriting ? (
<LucideLoader className="animate-spin" />
) : isFavorite ? (
<LucideCheck />
) : (
<LucidePlus />
),
onClick: () => handleAddToFavorite(),
isLoadingFavorite: isFavoriting,
},
{
type: "share",
label: "Share",
icon: <Share />,
onClick: () => {},
},
]}
moreData={{
relatedContent: recommendedContent, // More like this
moreDetails: {
description: content.description,
cast: content.cast,
crew: content.crew,
genres: content.genres,
language: content.language,
},
episodeTab: {
onClick: (season) => season, // Handle episode tab switch
},
}}
/>
🔁 Favorite Logic with React Query
const { data: isFavorite = false } = useQuery({
queryKey: ["favorites", content._id],
queryFn: () => zezoClient().favorites.getIsFavorite(content._id),
enabled: !!content?._id,
});
const { mutate: handleAddToFavorite, isPending: isFavoriting } = useMutation({
mutationFn: () => zezoClient().favorites.addToFavorites(content),
onMutate: () => queryClient.setQueryData(["favorites", content._id], true),
onSuccess: () => queryClient.invalidateQueries(["favorites", content._id]),
onError: () => queryClient.setQueryData(["favorites", content._id], false),
});
📦 Server-side Data: page.tsx
const slug = (await params).slug?.[1] ?? (await params).slug?.[0] ?? "";
const content = await getContent(slug); // fetch by slug
const contentRecommended = await recommendedContent(); // recommended section
const seasons = content?.type === "series" ? await getSeasons(query) : null;
const isBuyOrRent =
content?.content_offering_type === "BUY_OR_RENT"
? await getIsTvodContentPurchased(content._id)
: false;
return (
<DetailsContent
content={content}
seasons={seasons}
userSession={session}
recommendedContent={contentRecommended}
isBuyOrRent={isBuyOrRent}
/>
);
🧠 Behavior Summary
Feature | Behavior |
---|---|
Favorite Toggle | Uses React Query for optimistic updates and sync |
Season Selector | Auto-selects first season if content is a series |
Trailer / Play | Customizable onClick handlers passed as props |
Recommendations | Dynamically fetched from “recommended-movies” section |
Share Button | You can integrate navigator.share() or a custom modal |
TVOD Support | Checks if content is already purchased/rented before showing buy prompt |
✅ Final Notes
DetailsContent
is the main UI wrapper for your content detail page.- It supports series, movies, TVOD content, and integrates favorite logic using React Query.
- You can fully customize action buttons (
play
,trailer
,favorite
,share
) via thebuttons
prop. - Series data (seasons, episodes) is shown only if the content type is
"series"
. - Recommendations are fetched using the “recommended-movies” section — but you can plug any section ID.
- Skeletons and fallbacks are handled in
page.tsx
, not inDetailsContent
.
💡 Best Practice: Use
Suspense
,error boundaries
, and conditional rendering to ensure graceful fallback ifcontent
oruserSession
is not available.
⚠️ Required Packages
Ensure these packages are installed to use DetailsContent and supporting components:
pnpm
Terminal
pnpm add @zezosoft/zezo-ott-api-client @zezosoft/zezo-ott-react-ui-kit
Last updated on