Skip to Content
WebComponentCommonContent Details

🎬 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-kitContentDetails, 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

PropTypeDescription
contentIContentDataMain movie/series object with metadata
userSessionISession | nullCurrent authenticated user session
isBuyOrRentbooleanIndicates if the content is TVOD (buy/rent) and already purchased
seasonsISeasonData[]Season data for series content
selectedSeasonISeasonDataCurrently active season (usually seasons[0])
seasonsDataISeasonData[]Optional – Pass complete season info separately
isTabSwitcherbooleanEnable/disable season tab switching
buttonsActionButton[]List of UI actions like play, trailer, favorite, share
moreDataMoreDetailsConfigNested data like description, crew, language, genres, etc.

🧠 Feature Summary

FeatureBehavior
⭐ FavoriteOptimistically updates UI using React Query mutations
▶️ PlayTrigger onClick() from button prop
🎞️ TrailerSame as above — hook into trailer modal or overlay
📺 SeasonsIf content.type === "series", show episodes tab
🔁 RecommendationsUses backend section ID for similar or trending titles
🔄 TVODIf BUY_OR_RENT, verify entitlement before allowing playback
🔗 ShareCustom 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

FeatureBehavior
Favorite ToggleUses React Query for optimistic updates and sync
Season SelectorAuto-selects first season if content is a series
Trailer / PlayCustomizable onClick handlers passed as props
RecommendationsDynamically fetched from “recommended-movies” section
Share ButtonYou can integrate navigator.share() or a custom modal
TVOD SupportChecks 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 the buttons 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 in DetailsContent.

💡 Best Practice: Use Suspense, error boundaries, and conditional rendering to ensure graceful fallback if content or userSession is not available.

⚠️ Required Packages

Ensure these packages are installed to use DetailsContent and supporting components:

Terminal
pnpm add @zezosoft/zezo-ott-api-client @zezosoft/zezo-ott-react-ui-kit
Last updated on