Files
mtdb_movie/bootstrap/ssr/assets/site-routes-cce2e301.mjs
maher 703f50a09d
Some checks failed
Build / run (push) Has been cancelled
first commit
2025-10-29 11:42:25 +01:00

5753 lines
214 KiB
JavaScript
Executable File

import { jsxs, jsx } from "react/jsx-runtime";
import { useSearchParams, Link, useParams, useLocation, Outlet, useRoutes } from "react-router-dom";
import { m as message, ah as MenuTrigger, I as IconButton, B as Button, T as Trans, ai as Menu, h as Item, b2 as useCookie, ae as SiteConfigContext, c as createSvgIcon, i as useTrans, t as toast, b3 as FacebookIcon, b4 as TwitterIcon, aF as FormattedRelativeTime, b5 as LockIcon, o as opacityAnimation, R as FormattedDate, K as KeyboardArrowLeftIcon, ad as LinkStyle, w as IllustratedMessage, x as SvgImage, af as getBootstrapData, b as apiClient, aa as useNavigate, aO as ComboBoxForwardRef, k as SearchIcon, N as Navbar, V as Tooltip, aW as lazyLoader, u as useSettings, b6 as useAuth, b1 as Footer, aP as PageMetaTags, aD as PageStatus, e as useIsMobileMediaQuery, D as DialogTrigger, X as ButtonBase, b7 as useImageSrc, J as Form, L as FormTextField, n as showHttpErrorToast, r as ConfirmationDialog, a2 as Skeleton, d as useLocalStorage, Q as Chip, q as queryClient, M as CheckIcon, b8 as FormattedCurrency, j as TextField, b9 as useDarkThemeVariables, aN as PageErrorMessage, p as useDialogContext, l as StaticPageTitle, O as CloseIcon, G as onFormQueryError, _ as useValueLists, y as Dialog, z as DialogHeader, A as DialogBody, a7 as FileUploadProvider, Z as FormImageSelector, a4 as FormSelect, F as DialogFooter, az as isAbsoluteUrl, aX as AuthRoute, b0 as NotFoundPage } from "../server-entry.mjs";
import { b9 as useChannelQueryParams, aN as useInfiniteData, ba as channelQueryKey, bb as channelEndpoint, X as channelContentConfig, bc as Sort, aM as SortIcon, K as KeyboardArrowRightIcon, bd as GridViewIcon, ab as UserAvatar, be as BaseMediaLink, bf as getBaseMediaLink, u as useBackendFilterUrlParams, av as useTitleIndexFilters, A as AddFilterButton, w as TuneIcon, c as FilterListSkeleton, e as FilterList, _ as TITLE_MODEL, $ as MOVIE_MODEL, a0 as SERIES_MODEL, a$ as FormattedDateTimeRange, a8 as NewsArticleImage, a9 as NewsArticleLink, ae as BulletSeparatedItems, ai as TitlePoster, at as TitleLink, ad as TitleRating, aK as TitleBackdrop, bg as NEWS_ARTICLE_MODEL, aX as PERSON_MODEL, aT as PersonPoster, aV as PersonLink, aF as InfiniteScrollSentinel, bh as useChannelContent, bi as PaginationControls, R as ChevronLeftIcon, aO as MediaPlayIcon, aj as getWatchLink, aW as KnownForCompact, bj as FormattedDuration, bk as InteractableRating, bl as CHANNEL_MODEL, a_ as todoImage, bm as getPersonLink, az as getTitleLink, aA as useScrollToTop, W as useChannel, O as ImageZoomDialog, bn as ArrowForwardIcon, aH as useTitleSeasons, aI as SeasonPoster, aJ as SeasonLink, bo as useCreateReview, Q as Avatar, af as StarSelector, bp as useAuthClickCapture, ac as useDeleteReviews, M as MoreVertIcon, bq as useReviews, ah as ReviewListSortButton, br as getEpisodeLink, bs as VideoGrid, aD as useSeasonEpisodes, ak as CompactSeasonEpisode, b3 as EpisodePoster, o as ChipList, g as AddIcon, aw as useTitle, aB as useSeason, aE as EpisodeListItem, bt as getSeasonLink, aS as useEpisode, al as FormattedNumber, aa as useDeleteComments, b5 as EpisodeLink, bu as VideoGridItemSkeleton, bv as VideoGridItem, bw as EpisodeSelector, bx as MediaEpisodesIcon, ar as SiteVideoPlayer, aq as VideoPlayerSkeleton, aP as VideoThumbnail, q as Accordion, r as AccordionItem, aY as usePerson, aZ as useNewsArticle, H as Tabs, I as TabList, J as Tab, b6 as TitleLinkWithEpisodeNumber, by as StarIcon, b4 as UserProfileLink, b7 as CreateUserListPage, b8 as EditUserListPage } from "./user-profile-link-0bca566c.mjs";
import { useContext, useMemo, Fragment, memo, useRef, useState, useCallback, useEffect, useId, forwardRef, useImperativeHandle, Children } from "react";
import clsx from "clsx";
import { AnimatePresence, m } from "framer-motion";
import { L as LockOpenIcon, S as ShareIcon, E as ExpandMoreIcon, T as ThumbUpIcon, a as ThumbDownIcon, R as ReplyIcon, C as CommentIcon, F as FlagIcon, b as ListAltIcon, c as RateReviewIcon, B as BookmarkBorderIcon } from "./BookmarkBorder-2c120ae6.mjs";
import useClipboard from "react-use-clipboard";
import debounce from "just-debounce-it";
import { useLayoutEffect, getScrollParent, useObjectRef } from "@react-aria/utils";
import { C as ChevronRightIcon, O as OpenInNewIcon, E as EditIcon, B as Breadcrumb, a as BreadcrumbItem } from "./OpenInNew-3b47a656.mjs";
import { useQuery, keepPreviousData, useMutation, useQueryClient } from "@tanstack/react-query";
import dot from "dot-object";
import linkifyStr from "linkify-string";
import { useForm, useFieldArray } from "react-hook-form";
import memoize from "nano-memoize";
import "react-dom/server";
import "process";
import "http";
import "axios";
import "react-router-dom/server.mjs";
import "slugify";
import "deepmerge";
import "@internationalized/date";
import "zustand";
import "zustand/middleware/immer";
import "nanoid";
import "@react-aria/focus";
import "@floating-ui/react-dom";
import "react-merge-refs";
import "react-dom";
import "@internationalized/number";
import "@react-stately/utils";
import "@react-aria/ssr";
import "immer";
import "axios-retry";
import "tus-js-client";
import "react-use-cookie";
import "mime-match";
import "fscreen";
import "zustand/middleware";
import "zustand/traditional";
import "@react-aria/interactions";
function useInfiniteChannelContent(channel) {
const queryParams = useChannelQueryParams(channel);
return useInfiniteData({
willSortOrFilter: true,
initialPage: channel.content,
queryKey: channelQueryKey(channel.id),
endpoint: channelEndpoint(channel.id),
queryParams: {
returnContentOnly: "true",
...queryParams
}
});
}
function ChannelSortButton({
channel
}) {
var _a;
const config = channelContentConfig.models[channel.config.contentModel];
const sortMethods = (config == null ? void 0 : config.sortMethods.map((method) => ({
key: method,
label: channelContentConfig.sortingMethods[method].label
}))) || [];
if (channel.config.contentType === "manual") {
sortMethods.unshift({
key: Sort.curated,
label: message("Default order")
});
}
const [searchParams, setSearchParams] = useSearchParams();
const selectedValue = searchParams.get("order") || channel.config.contentOrder;
if ((sortMethods == null ? void 0 : sortMethods.length) < 2) {
return null;
}
const label = (_a = sortMethods == null ? void 0 : sortMethods.find(
(method) => method.key === selectedValue
)) == null ? void 0 : _a.label;
return /* @__PURE__ */ jsxs(
MenuTrigger,
{
selectionMode: "single",
showCheckmark: true,
selectedValue,
onSelectionChange: (newValue) => {
if (newValue === Sort.recent && channel.config.contentType === "manual") {
newValue = "channelables.created_at:desc";
}
setSearchParams(
(prev) => {
prev.set("order", newValue);
return prev;
},
{
replace: true
}
);
},
children: [
/* @__PURE__ */ jsxs("span", { role: "button", "aria-label": "Toggle menu", children: [
/* @__PURE__ */ jsx(IconButton, { className: "md:hidden", role: "presentation", children: /* @__PURE__ */ jsx(SortIcon, {}) }),
/* @__PURE__ */ jsx(
Button,
{
startIcon: /* @__PURE__ */ jsx(SortIcon, {}),
className: "max-md:hidden",
role: "presentation",
children: label ? /* @__PURE__ */ jsx(Trans, { ...label }) : /* @__PURE__ */ jsx(Trans, { message: "Popularity" })
}
)
] }),
/* @__PURE__ */ jsx(Menu, { children: sortMethods == null ? void 0 : sortMethods.map((method) => /* @__PURE__ */ jsx(Item, { value: method.key, children: /* @__PURE__ */ jsx(Trans, { ...method.label }) }, method.key)) })
]
}
);
}
function SiteSectionHeading({
children,
titleAppend,
link,
fontSize = "text-2xl md:text-3xl",
fontWeight = "font-bold",
margin = "mb-20",
className: className2,
headingType: HeadingType = "h2",
description,
descriptionFontSize = "text-base",
actions,
hideBorder
}) {
const title = link ? /* @__PURE__ */ jsx(
Link,
{
to: link,
className: "rounded outline-none transition-colors hover:underline focus-visible:ring-2 focus-visible:ring-offset-2",
children
}
) : children;
return /* @__PURE__ */ jsxs("section", { className: clsx(className2, margin), children: [
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-44 max-md:overflow-x-auto", children: [
/* @__PURE__ */ jsx("div", { className: "flex-auto", children: /* @__PURE__ */ jsxs(
"div",
{
className: clsx(
"relative flex items-center gap-4",
!hideBorder && "pl-14 before:absolute before:left-0 before:h-5/6 before:w-4 before:rounded before:bg-primary"
),
children: [
/* @__PURE__ */ jsx(HeadingType, { className: clsx(fontSize, fontWeight), children: title }),
titleAppend && /* @__PURE__ */ jsx("span", { className: "pt-4 text-base text-muted", children: titleAppend }),
link && /* @__PURE__ */ jsx(
IconButton,
{
elementType: Link,
to: link,
size: "sm",
iconSize: "lg",
className: "mt-4 max-md:hidden",
children: /* @__PURE__ */ jsx(KeyboardArrowRightIcon, {})
}
)
]
}
) }),
actions && /* @__PURE__ */ jsx("div", { className: "flex flex-shrink-0 items-center gap-4", children: actions })
] }),
description && /* @__PURE__ */ jsx("div", { className: clsx("mt-6", descriptionFontSize), children: description })
] });
}
function useChannelLayouts(channel) {
const config = channelContentConfig.models[channel.config.contentModel];
const availableLayouts = config == null ? void 0 : config.layoutMethods.filter((m2) => channelContentConfig.userSelectableLayouts.includes(m2)).map((method) => ({
key: method,
label: channelContentConfig.layoutMethods[method].label,
icon: channelContentConfig.layoutMethods[method].icon
}));
const [selectedLayout, setSelectedLayout] = useCookie(
`channel-layout-${channel.config.contentModel}`,
channel.config.selectedLayout || channel.config.layout
);
return { selectedLayout, setSelectedLayout, availableLayouts };
}
function ChannelLayoutButton({ channel }) {
const { selectedLayout, setSelectedLayout, availableLayouts } = useChannelLayouts(channel);
if ((availableLayouts == null ? void 0 : availableLayouts.length) < 2) {
return null;
}
const layoutConfig = availableLayouts == null ? void 0 : availableLayouts.find(
(method) => method.key === selectedLayout
);
return /* @__PURE__ */ jsxs(
MenuTrigger,
{
selectionMode: "single",
showCheckmark: true,
selectedValue: selectedLayout,
onSelectionChange: (newValue) => setSelectedLayout(newValue),
children: [
/* @__PURE__ */ jsxs("span", { role: "button", "aria-label": "Toggle menu", children: [
/* @__PURE__ */ jsx(IconButton, { className: "md:hidden", role: "presentation", children: (layoutConfig == null ? void 0 : layoutConfig.icon) || /* @__PURE__ */ jsx(GridViewIcon, {}) }),
/* @__PURE__ */ jsx(
Button,
{
role: "presentation",
className: "max-md:hidden",
startIcon: (layoutConfig == null ? void 0 : layoutConfig.icon) || /* @__PURE__ */ jsx(GridViewIcon, {}),
children: (layoutConfig == null ? void 0 : layoutConfig.label) ? /* @__PURE__ */ jsx(Trans, { ...layoutConfig.label }) : /* @__PURE__ */ jsx(Trans, { message: "Popularity" })
}
)
] }),
/* @__PURE__ */ jsx(Menu, { children: availableLayouts == null ? void 0 : availableLayouts.map((method) => /* @__PURE__ */ jsx(Item, { value: method.key, children: /* @__PURE__ */ jsx(Trans, { ...method.label }) }, method.key)) })
]
}
);
}
function UserListByline({ user }) {
const { auth } = useContext(SiteConfigContext);
return /* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 flex items-center gap-8 mr-24", children: [
/* @__PURE__ */ jsx(UserAvatar, { user, circle: true, size: "sm" }),
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
Trans,
{
message: "List by <a>:name</a>",
values: {
a: () => /* @__PURE__ */ jsx(
Link,
{
to: auth.getUserProfileLink(user),
className: "font-bold hover:underline",
children: user.display_name
}
)
}
}
) })
] });
}
function shareLinkSocially(network, link, name, image) {
const url = generateShareUrl(network, link, name, image);
if (network === "mail") {
window.location.href = url;
} else {
openNewWindow(url);
}
}
function openNewWindow(url) {
const width = 575, height = 400, left = (window.innerWidth - width) / 2, top = (window.innerHeight - height) / 2, opts = "status=1, scrollbars=1,width=" + width + ",height=" + height + ",top=" + top + ",left=" + left;
window.open(url, "share", opts);
}
function generateShareUrl(type, link, name, image) {
switch (type) {
case "facebook":
return "https://www.facebook.com/sharer/sharer.php?u=" + link;
case "twitter":
return `https://twitter.com/intent/tweet?text=${name}&url=${link}`;
case "pinterest":
return "https://pinterest.com/pin/create/button/?url=" + link + "&media=" + image;
case "tumblr":
const base = "https://www.tumblr.com/widgets/share/tool?shareSource=legacy&canonicalUrl=&posttype=photo&title=&caption=";
return base + name + "&content=" + image + "&url=" + link;
case "blogger":
return "https://www.blogger.com/blog_this.pyra?t&u=" + link + "&n=" + name;
case "mail":
return `mailto:?subject=Check out this link.&body=${link}`;
}
}
const CopyLinkIcon = createSvgIcon(
/* @__PURE__ */ jsx("path", { d: "M 4 2 C 2.895 2 2 2.895 2 4 L 2 18 L 4 18 L 4 4 L 18 4 L 18 2 L 4 2 z M 8 6 C 6.895 6 6 6.895 6 8 L 6 20 C 6 21.105 6.895 22 8 22 L 20 22 C 21.105 22 22 21.105 22 20 L 22 8 C 22 6.895 21.105 6 20 6 L 8 6 z M 8 8 L 20 8 L 20 20 L 8 20 L 8 8 z M 16 9.0058594 C 15.230215 9.0058594 14.460443 9.2973698 13.878906 9.8789062 L 12.607422 11.150391 L 14.021484 12.564453 L 12.556641 14.029297 L 11.142578 12.615234 L 9.8789062 13.878906 C 8.7158332 15.041979 8.7158332 16.958021 9.8789062 18.121094 C 10.460397 18.702585 11.234094 19 12 19 C 12.765906 19 13.539603 18.702585 14.121094 18.121094 L 15.384766 16.857422 L 13.970703 15.443359 L 15.457031 13.957031 L 14.042969 12.542969 L 15.292969 11.292969 C 15.691896 10.894042 16.308104 10.894042 16.707031 11.292969 C 17.105958 11.691896 17.105958 12.308104 16.707031 12.707031 L 15.464844 13.949219 L 16.878906 15.363281 L 18.121094 14.121094 C 19.284167 12.958021 19.284167 11.041979 18.121094 9.8789062 C 17.539557 9.2973698 16.769785 9.0058594 16 9.0058594 z M 12.542969 14.042969 L 13.957031 15.457031 L 12.707031 16.707031 C 12.506522 16.90754 12.258094 17 12 17 C 11.741906 17 11.493478 16.90754 11.292969 16.707031 C 10.894042 16.308104 10.894042 15.691896 11.292969 15.292969 L 12.542969 14.042969 z" })
);
function ShareMenuTrigger({ link, children }) {
const { trans } = useTrans();
const [, setUrlCopied] = useClipboard(link);
return /* @__PURE__ */ jsxs(MenuTrigger, { children: [
children,
/* @__PURE__ */ jsxs(Menu, { children: [
/* @__PURE__ */ jsx(
Item,
{
value: "clipboard",
startIcon: /* @__PURE__ */ jsx(CopyLinkIcon, {}),
onSelected: () => {
setUrlCopied();
toast.positive(message("Copied link to clipboard"));
},
children: /* @__PURE__ */ jsx(Trans, { message: "Copy to clipboard" })
}
),
/* @__PURE__ */ jsx(
Item,
{
value: "facebook",
startIcon: /* @__PURE__ */ jsx(FacebookIcon, {}),
onClick: () => {
shareLinkSocially(
"facebook",
link,
trans(message("Check out this link"))
);
},
children: /* @__PURE__ */ jsx(Trans, { message: "Share to facebook" })
}
),
/* @__PURE__ */ jsx(
Item,
{
value: "twitter",
startIcon: /* @__PURE__ */ jsx(TwitterIcon, {}),
onClick: () => {
shareLinkSocially(
"twitter",
link,
trans(message("Check out this link"))
);
},
children: /* @__PURE__ */ jsx(Trans, { message: "Share to twitter" })
}
)
] })
] });
}
function UserListLink({ list, children, ...linkProps }) {
const link = useMemo(() => {
return getUserListLink(list);
}, [list]);
let content2;
if (children) {
content2 = children;
} else if (list.internal && list.name === "watchlist") {
return /* @__PURE__ */ jsx(Trans, { message: "Watchlist" });
} else {
content2 = list.name;
}
return /* @__PURE__ */ jsx(BaseMediaLink, { ...linkProps, link, children: content2 });
}
function getUserListLink(list, { absolute } = {}) {
return getBaseMediaLink(`/lists/${list.id}`, {
absolute
});
}
function UserListDetails({
list,
className: className2,
showShareButton,
showVisibility = true
}) {
return /* @__PURE__ */ jsxs(
"div",
{
className: clsx(
"flex flex-shrink-0 items-center gap-4 whitespace-nowrap text-muted",
className2
),
children: [
showShareButton && /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(ShareButton$4, { list }),
/* @__PURE__ */ jsx(Divider, { marginLeft: "ml-2" })
] }),
list.items_count ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(Trans, { message: ":count items", values: { count: list.items_count } }),
/* @__PURE__ */ jsx(Divider, {})
] }) : null,
/* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(
Trans,
{
message: "Updated :date",
values: {
date: /* @__PURE__ */ jsx(FormattedRelativeTime, { date: list.updated_at })
}
}
) }),
showVisibility && /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(Divider, {}),
list.public ? /* @__PURE__ */ jsx(LockOpenIcon, { size: "sm" }) : /* @__PURE__ */ jsx(LockIcon, { size: "sm" }),
/* @__PURE__ */ jsx("div", { children: list.public ? /* @__PURE__ */ jsx(Trans, { message: "Public" }) : /* @__PURE__ */ jsx(Trans, { message: "Private" }) })
] })
]
}
);
}
function ShareButton$4({ list }) {
const link = getUserListLink(list, { absolute: true });
return /* @__PURE__ */ jsx(ShareMenuTrigger, { link, children: /* @__PURE__ */ jsx(Button, { startIcon: /* @__PURE__ */ jsx(ShareIcon, {}), sizeClassName: "px-10 py-6", children: /* @__PURE__ */ jsx(Trans, { message: "Share" }) }) });
}
function Divider({ marginLeft = "ml-12" }) {
return /* @__PURE__ */ jsx("div", { className: clsx("mr-10 h-20 w-1 bg-divider", marginLeft) });
}
const FilterModelTypes = [TITLE_MODEL, MOVIE_MODEL, SERIES_MODEL];
function ChannelHeader({
channel,
isNested,
actions,
margin = isNested ? "mb-16 md:mb-30" : "mb-20 md:mb-40"
}) {
const shouldShowFilterButton = !isNested && FilterModelTypes.includes(channel.config.contentModel) && channel.config.contentType === "listAll";
const { encodedFilters } = useBackendFilterUrlParams();
const { filters, filtersLoading } = useTitleIndexFilters({
disabled: !shouldShowFilterButton
});
if (channel.config.hideTitle) {
return null;
}
return /* @__PURE__ */ jsxs("section", { className: clsx(margin), children: [
/* @__PURE__ */ jsx(
ChannelTitle,
{
channel,
isNested,
actions: /* @__PURE__ */ jsxs(Fragment, { children: [
actions,
!isNested && /* @__PURE__ */ jsx(ChannelSortButton, { channel }),
shouldShowFilterButton && /* @__PURE__ */ jsx(
AddFilterButton,
{
icon: /* @__PURE__ */ jsx(TuneIcon, {}),
color: null,
variant: "text",
disabled: filtersLoading,
filters
}
),
!isNested && /* @__PURE__ */ jsx(ChannelLayoutButton, { channel })
] })
}
),
shouldShowFilterButton && /* @__PURE__ */ jsx("div", { className: "mt-14", children: /* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: filtersLoading && encodedFilters ? /* @__PURE__ */ jsx(FilterListSkeleton, {}) : /* @__PURE__ */ jsx(m.div, { ...opacityAnimation, children: /* @__PURE__ */ jsx(FilterList, { filters }) }, "filter-list") }) })
] });
}
function ChannelTitle({ channel, isNested, actions }) {
const { restriction: urlParam } = useParams();
if (channel.config.hideTitle) {
return null;
}
const link = channel.config.restriction && urlParam ? `/${channel.slug}/${urlParam}` : `/${channel.slug}`;
return /* @__PURE__ */ jsx(
SiteSectionHeading,
{
className: "flex-auto",
margin: "m-0",
description: /* @__PURE__ */ jsx(ChannelDescription, { channel }),
actions,
headingType: isNested ? "h2" : "h1",
descriptionFontSize: isNested ? "text-sm" : void 0,
fontWeight: isNested ? "font-normal" : void 0,
link: isNested ? link : void 0,
children: /* @__PURE__ */ jsx(Trans, { message: channel.name })
}
);
}
function ChannelDescription({ channel }) {
if (channel.type === "channel") {
return /* @__PURE__ */ jsx(Fragment, { children: channel.description });
}
return /* @__PURE__ */ jsxs("div", { className: "mt-18 items-center text-sm md:flex", children: [
channel.user && /* @__PURE__ */ jsx(UserListByline, { user: channel.user }),
/* @__PURE__ */ jsx(
UserListDetails,
{
list: channel,
className: "ml-auto max-md:mt-14",
showShareButton: true
}
)
] });
}
function ContentGridLayout({
children,
className: className2,
variant,
gridCols = "grid-cols-[repeat(var(--nVisibleItems),minmax(0,1fr))]"
}) {
return /* @__PURE__ */ jsx(
"div",
{
className: clsx(
"grid gap-24",
gridCols,
className2,
variant === "landscape" ? "content-grid-landscape" : "content-grid-portrait"
),
children
}
);
}
const PersonAge = memo(({ person, showRange }) => {
if (showRange && person.birth_date && person.death_date) {
return /* @__PURE__ */ jsx(
FormattedDateTimeRange,
{
start: person.birth_date,
end: person.death_date,
options: { year: "numeric" }
}
);
}
if (person.birth_date) {
return /* @__PURE__ */ jsx(Fragment, { children: calculateAgeFromBirthDate(person.birth_date, person.death_date) });
}
return null;
});
function calculateAgeFromBirthDate(_birthDate, _deathDate) {
const until = _deathDate ? new Date(_deathDate) : /* @__PURE__ */ new Date();
const birthDate = new Date(_birthDate);
let age = until.getFullYear() - birthDate.getFullYear();
const m2 = until.getMonth() - birthDate.getMonth();
if (m2 < 0 || m2 === 0 && until.getDate() < birthDate.getDate()) {
age--;
}
return age;
}
function NewsArticleGridItem({ article }) {
return /* @__PURE__ */ jsxs("div", { className: "items-start gap-14 lg:flex", children: [
/* @__PURE__ */ jsx(
NewsArticleImage,
{
article,
className: "aspect-poster max-w-90 max-md:hidden"
}
),
/* @__PURE__ */ jsxs("div", { className: "min-w-0 overflow-hidden overflow-ellipsis text-base md:mt-24 lg:mt-6", children: [
/* @__PURE__ */ jsx(NewsArticleLink, { article, className: "font-medium" }),
/* @__PURE__ */ jsxs(BulletSeparatedItems, { className: "mt-10 min-w-0 overflow-hidden overflow-ellipsis text-xs", children: [
/* @__PURE__ */ jsx(FormattedDate, { date: article.created_at }),
/* @__PURE__ */ jsx("div", { className: "overflow-hidden overflow-ellipsis whitespace-nowrap", children: article.source })
] })
] })
] });
}
function TitlePortraitGridItem({
item,
rating,
description
}) {
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(TitlePoster, { title: item, srcSize: "md", showPlayButton: true }) }),
/* @__PURE__ */ jsxs("div", { className: "mt-10 text-sm", children: [
/* @__PURE__ */ jsx(RatingOrReleaseDate, { title: item, rating, className: "mb-4" }),
/* @__PURE__ */ jsx(TitleLink, { title: item, className: "block text-base font-medium" }),
description ? /* @__PURE__ */ jsx("div", { className: "mt-4", children: description }) : null
] })
] });
}
function TitleLandscapeGridItem({ item }) {
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(
TitleBackdrop,
{
title: item,
srcSize: "lg",
size: "w-full",
className: "rounded",
wrapWithLink: true,
showPlayButton: true
}
),
/* @__PURE__ */ jsxs("div", { className: "mt-10 text-sm", children: [
/* @__PURE__ */ jsx(
TitleLink,
{
title: item,
className: "mb-4 block text-base font-semibold"
}
),
/* @__PURE__ */ jsxs(BulletSeparatedItems, { className: "mb-4", children: [
item.release_date && /* @__PURE__ */ jsx(FormattedDate, { date: item.release_date }),
item.certification && /* @__PURE__ */ jsx("div", { className: "uppercase", children: item.certification })
] }),
/* @__PURE__ */ jsx(TitleRating, { score: item.rating, className: "mb-4" })
] })
] });
}
function RatingOrReleaseDate({
title,
rating,
className: className2
}) {
if (!rating) {
rating = title.rating;
}
if (rating) {
return /* @__PURE__ */ jsx(TitleRating, { score: rating, className: className2 });
}
if (title.release_date) {
return /* @__PURE__ */ jsx("div", { className: className2, children: /* @__PURE__ */ jsx(FormattedDate, { date: title.release_date }) });
}
return null;
}
function ChannelContentGridItem({ item, variant }) {
switch (item.model_type) {
case TITLE_MODEL:
return variant === "landscape" ? /* @__PURE__ */ jsx(TitleLandscapeGridItem, { item }) : /* @__PURE__ */ jsx(TitlePortraitGridItem, { item });
case PERSON_MODEL:
return /* @__PURE__ */ jsx(PersonGridItem, { item });
case NEWS_ARTICLE_MODEL:
return /* @__PURE__ */ jsx(NewsArticleGridItem, { article: item });
default:
return null;
}
}
function PersonGridItem({ item }) {
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(PersonPoster, { person: item, srcSize: "md", size: "w-full", rounded: true }),
/* @__PURE__ */ jsxs("div", { className: "mt-10 text-center text-sm", children: [
/* @__PURE__ */ jsx(PersonLink, { person: item, className: "block text-base font-medium" }),
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(PersonAge, { person: item, showRange: true }) })
] })
] });
}
function ChannelContentGrid(props) {
const isInfiniteScroll = !props.isNested && (!props.channel.config.paginationType || props.channel.config.paginationType === "infiniteScroll");
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(ChannelHeader, { ...props }),
isInfiniteScroll ? /* @__PURE__ */ jsx(InfiniteScrollGrid, { ...props }) : /* @__PURE__ */ jsx(PaginatedGrid, { ...props })
] });
}
function InfiniteScrollGrid({ channel, variant }) {
const query = useInfiniteChannelContent(channel);
return /* @__PURE__ */ jsxs(
"div",
{
className: clsx("transition-opacity", query.isReloading && "opacity-70"),
children: [
/* @__PURE__ */ jsx(ContentGrid, { content: query.items, variant }),
/* @__PURE__ */ jsx(InfiniteScrollSentinel, { query })
]
}
);
}
function PaginatedGrid({ channel, variant, isNested }) {
var _a;
const shouldPaginate = !isNested;
const query = useChannelContent(channel, null, { paginate: shouldPaginate });
return /* @__PURE__ */ jsxs(
"div",
{
className: clsx(
"transition-opacity",
query.isPlaceholderData && "opacity-70"
),
children: [
shouldPaginate && /* @__PURE__ */ jsx(
PaginationControls,
{
pagination: query.data,
type: channel.config.paginationType,
className: "mb-24"
}
),
/* @__PURE__ */ jsx(ContentGrid, { content: (_a = query.data) == null ? void 0 : _a.data, variant }),
shouldPaginate && /* @__PURE__ */ jsx(
PaginationControls,
{
pagination: query.data,
type: channel.config.paginationType,
className: "mt-24",
scrollToTop: true
}
)
]
}
);
}
function ContentGrid({ content: content2 = [], variant }) {
return /* @__PURE__ */ jsx(ContentGridLayout, { variant, children: content2.map((item) => /* @__PURE__ */ jsx(
ChannelContentGridItem,
{
item,
variant
},
`${item.id}-${item.model_type}`
)) });
}
const containerClassName = "content-carousel content-grid relative w-full grid grid-flow-col grid-rows-[auto] overflow-x-auto overflow-y-hidden gap-24 snap-always snap-x snap-mandatory hidden-scrollbar scroll-smooth";
const itemClassName = "snap-start snap-normal";
function useCarousel({ rotate = false } = {}) {
const scrollContainerRef = useRef(null);
const itemWidth = useRef(0);
const perPage = useRef(5);
const [canScrollBackward, setCanScrollBackward] = useState(rotate);
const [canScrollForward, setCanScrollForward] = useState(true);
const [activePage, setActivePage] = useState(0);
const updateNavStatus = useCallback(() => {
const el = scrollContainerRef.current;
if (el && itemWidth.current) {
if (!rotate) {
setCanScrollForward(
el.scrollWidth - 1 > el.scrollLeft + el.clientWidth
);
setCanScrollBackward(el.scrollLeft > 0);
}
const pageWidth = el.clientWidth;
const activePage2 = Math.round(el.scrollLeft / pageWidth);
setActivePage(activePage2);
}
}, [rotate]);
useEffect(() => {
const el = scrollContainerRef.current;
const handleScroll = debounce(() => updateNavStatus(), 100);
if (el) {
el.addEventListener("scroll", handleScroll);
}
return () => el == null ? void 0 : el.removeEventListener("scroll", handleScroll);
}, [updateNavStatus]);
useLayoutEffect(() => {
const el = scrollContainerRef.current;
if (el) {
perPage.current = Number(
getComputedStyle(el).getPropertyValue("--nVisibleItems")
);
const firstGridItem = el.children.item(0);
const observer = new ResizeObserver((entries) => {
itemWidth.current = entries[0].contentRect.width;
updateNavStatus();
});
if (firstGridItem) {
observer.observe(firstGridItem);
}
return () => observer.unobserve(el);
}
}, [updateNavStatus]);
const scrollToIndex = useCallback((index) => {
if (scrollContainerRef.current) {
setActivePage(index);
const amount = itemWidth.current * index;
scrollContainerRef.current.scrollTo({ left: amount });
}
}, []);
const scrollToPreviousPage = useCallback(() => {
if (scrollContainerRef.current) {
const pageWidth = scrollContainerRef.current.clientWidth;
const currentScroll = scrollContainerRef.current.scrollLeft;
const scrollLeft = !currentScroll && rotate ? scrollContainerRef.current.scrollWidth - pageWidth : currentScroll - pageWidth;
scrollContainerRef.current.scrollTo({
left: scrollLeft
});
}
}, [rotate]);
const scrollToNextPage = useCallback(() => {
if (scrollContainerRef.current) {
const pageWidth = scrollContainerRef.current.clientWidth;
const currentScroll = scrollContainerRef.current.scrollLeft;
const scrollLeft = rotate && currentScroll + pageWidth >= scrollContainerRef.current.scrollWidth ? 0 : (activePage + 1) * pageWidth;
scrollContainerRef.current.scrollTo({ left: scrollLeft });
}
}, [activePage, rotate]);
return {
scrollContainerRef,
scrollToIndex,
scrollToPreviousPage,
scrollToNextPage,
canScrollForward,
canScrollBackward,
activePage,
containerClassName,
itemClassName
};
}
function ChannelContentCarousel(props) {
var _a;
const { channel, variant } = props;
const {
scrollContainerRef,
canScrollForward,
canScrollBackward,
scrollToPreviousPage,
scrollToNextPage,
containerClassName: containerClassName2,
itemClassName: itemClassName2
} = useCarousel();
const gridClassName = variant === "landscape" ? "content-grid-landscape" : "content-grid-portrait";
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(
ChannelHeader,
{
...props,
actions: /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
IconButton,
{
disabled: !canScrollBackward,
onClick: () => scrollToPreviousPage(),
"aria-label": "Previous page",
children: /* @__PURE__ */ jsx(KeyboardArrowLeftIcon, {})
}
),
/* @__PURE__ */ jsx(
IconButton,
{
disabled: !canScrollForward,
onClick: () => scrollToNextPage(),
"aria-label": "Next page",
children: /* @__PURE__ */ jsx(KeyboardArrowRightIcon, {})
}
)
] })
}
),
/* @__PURE__ */ jsx(
"div",
{
ref: scrollContainerRef,
className: clsx(containerClassName2, gridClassName),
children: (_a = channel.content) == null ? void 0 : _a.data.map((item) => /* @__PURE__ */ jsx("div", { className: itemClassName2, children: /* @__PURE__ */ jsx(ChannelContentGridItem, { item, variant }) }, `${item.id}-${item.model_type}`))
}
)
] });
}
function ChannelContentSlider({
channel,
isNested
}) {
const {
scrollContainerRef,
activePage,
canScrollBackward,
canScrollForward,
scrollToNextPage,
scrollToPreviousPage
} = useCarousel({ rotate: true });
const { data: pagination } = useChannelContent(channel);
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
ChannelHeader,
{
channel,
isNested,
margin: "mb-18"
}
),
/* @__PURE__ */ jsxs("div", { className: "gap-24 md:flex", children: [
/* @__PURE__ */ jsxs("div", { className: "relative flex-auto", children: [
/* @__PURE__ */ jsx(
"div",
{
ref: scrollContainerRef,
className: "hidden-scrollbar flex h-full select-none snap-x snap-mandatory snap-always items-center overflow-x-auto",
children: pagination == null ? void 0 : pagination.data.map((item, index) => /* @__PURE__ */ jsx(Slide, { item, index }, item.id))
}
),
/* @__PURE__ */ jsxs("div", { className: "absolute top-10 z-20 w-full md:top-[170px]", children: [
/* @__PURE__ */ jsx("div", { className: "absolute left-8 hidden md:left-14 md:block", children: /* @__PURE__ */ jsx(
IconButton,
{
variant: "outline",
size: "lg",
color: "white",
disabled: !canScrollBackward,
onClick: () => scrollToPreviousPage(),
children: /* @__PURE__ */ jsx(ChevronLeftIcon, {})
}
) }),
/* @__PURE__ */ jsx("div", { className: "absolute right-8 hidden md:right-14 md:block", children: /* @__PURE__ */ jsx(
IconButton,
{
variant: "outline",
size: "lg",
color: "white",
disabled: !canScrollForward,
onClick: () => scrollToNextPage(),
children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
}
) })
] })
] }),
/* @__PURE__ */ jsx(UpNext, { titles: (pagination == null ? void 0 : pagination.data) ?? [], activePage })
] })
] });
}
function Slide({ item, index }) {
return /* @__PURE__ */ jsxs("div", { className: "relative h-full w-full flex-shrink-0 snap-start snap-normal overflow-hidden rounded", children: [
/* @__PURE__ */ jsx(
TitleBackdrop,
{
title: item,
lazy: index > 0,
className: "min-h-240 md:min-h-0",
wrapperClassName: "h-full"
}
),
/* @__PURE__ */ jsxs("div", { className: "absolute inset-0 isolate flex h-full w-full items-center justify-start gap-24 rounded p-30 text-white md:items-end", children: [
/* @__PURE__ */ jsx("div", { className: "absolute left-0 h-full w-full bg-gradient-to-b from-black/40 max-md:top-0 md:bottom-0 md:h-3/4 md:bg-gradient-to-t md:from-black/100" }),
/* @__PURE__ */ jsx(
TitlePoster,
{
title: item,
size: "max-h-320",
srcSize: "md",
className: "z-10 shadow-md max-md:hidden"
}
),
/* @__PURE__ */ jsxs("div", { className: "z-10 text-lg md:max-w-620", children: [
/* @__PURE__ */ jsx(TitleRating, { score: item.rating }),
/* @__PURE__ */ jsx("div", { className: "my-8 text-2xl md:text-5xl", children: /* @__PURE__ */ jsx(TitleLink, { title: item }) }),
item.description && /* @__PURE__ */ jsx("p", { className: "max-md:hidden", children: item.description }),
item.primary_video && /* @__PURE__ */ jsx(
Button,
{
variant: "flat",
color: "primary",
startIcon: /* @__PURE__ */ jsx(MediaPlayIcon, {}),
radius: "rounded-full",
className: "mt-24 md:min-h-42 md:min-w-144",
elementType: Link,
to: getWatchLink(item.primary_video),
children: item.primary_video.category === "full" ? /* @__PURE__ */ jsx(Trans, { message: "Watch now" }) : /* @__PURE__ */ jsx(Trans, { message: "Play trailer" })
}
)
] })
] })
] });
}
function UpNext({ titles, activePage }) {
const itemCount = titles.length;
const start = activePage + 1;
const end = start + 3;
const items = titles.slice(start, end);
if (end > itemCount) {
items.push(...titles.slice(0, end - itemCount));
}
return /* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: /* @__PURE__ */ jsxs("div", { className: "w-1/4 max-w-200 flex-shrink-0 max-md:hidden", children: [
/* @__PURE__ */ jsx("div", { className: "mb-12 text-lg font-semibold", children: /* @__PURE__ */ jsx(Trans, { message: "Up next" }) }),
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-24", children: items.map((item) => /* @__PURE__ */ jsxs(
m.div,
{
className: "relative flex-auto",
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 },
transition: { duration: 0.2 },
children: [
/* @__PURE__ */ jsx(
TitleBackdrop,
{
title: item,
className: "mb-6 rounded",
size: "w-full",
srcSize: "md",
wrapWithLink: true,
showPlayButton: true
}
),
/* @__PURE__ */ jsx("div", { className: "mb-2 overflow-hidden overflow-ellipsis whitespace-nowrap text-sm", children: /* @__PURE__ */ jsx(TitleLink, { title: item, className: "text-base font-medium" }) }),
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(TitleRating, { score: item.rating, className: "text-sm" }) })
]
},
item.id
)) })
] }) });
}
function NewsArticleSourceLink({ article, className: className2 }) {
return /* @__PURE__ */ jsxs("div", { className: clsx("flex items-center gap-4 text-primary", className2), children: [
/* @__PURE__ */ jsx(OpenInNewIcon, { size: "xs", className: "flex-shrink-0" }),
/* @__PURE__ */ jsx(
"a",
{
href: article.source_url,
target: "_blank",
rel: "noreferrer",
className: clsx(
LinkStyle,
"whitespace-nowrap overflow-hidden overflow-ellipsis"
),
children: article.source
}
)
] });
}
function NewsArticleByline({ article }) {
return article.byline ? /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap", children: /* @__PURE__ */ jsx(Trans, { message: "By :name", values: { name: article.byline } }) }) : null;
}
function ChannelContentNews({
channel,
isNested
}) {
var _a, _b;
const shouldPaginate = !isNested;
const query = useChannelContent(
channel,
null,
{
paginate: shouldPaginate
}
);
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(ChannelHeader, { channel, isNested }),
shouldPaginate && /* @__PURE__ */ jsx(
PaginationControls,
{
pagination: query.data,
type: channel.config.paginationType,
className: "mb-34"
}
),
/* @__PURE__ */ jsxs("div", { className: "flex gap-34", children: [
/* @__PURE__ */ jsx("div", { className: "w-240 flex-shrink-0", children: (_a = query.data) == null ? void 0 : _a.data.slice(0, 3).map((article) => /* @__PURE__ */ jsx(
LeftColArticle,
{
article,
className: "mb-14"
},
article.id
)) }),
/* @__PURE__ */ jsx("div", { className: "flex-auto", children: (_b = query.data) == null ? void 0 : _b.data.slice(3, 12).map((article) => /* @__PURE__ */ jsxs("div", { className: "mb-12 flex items-center gap-14", children: [
/* @__PURE__ */ jsx(NewsArticleImage, { article, size: "w-84 h-84" }),
/* @__PURE__ */ jsxs("div", { className: "flex-auto", children: [
/* @__PURE__ */ jsx(NewsArticleLink, { article, className: "font-semibold" }),
/* @__PURE__ */ jsxs(BulletSeparatedItems, { className: "text-sm", children: [
/* @__PURE__ */ jsx(FormattedDate, { date: article.created_at }),
/* @__PURE__ */ jsx(NewsArticleByline, { article }),
/* @__PURE__ */ jsx(NewsArticleSourceLink, { article })
] })
] })
] }, article.id)) })
] }),
shouldPaginate && /* @__PURE__ */ jsx(
PaginationControls,
{
pagination: query.data,
type: channel.config.paginationType,
className: "mt-34",
scrollToTop: true
}
)
] });
}
function LeftColArticle({ article, className: className2 }) {
return /* @__PURE__ */ jsxs("div", { className: className2, children: [
/* @__PURE__ */ jsx(NewsArticleImage, { article, size: "aspect-video w-full" }),
/* @__PURE__ */ jsx(
NewsArticleLink,
{
article,
className: "mt-10 block text-sm font-semibold"
}
),
/* @__PURE__ */ jsxs("div", { className: "mt-8 text-xs text-muted", children: [
/* @__PURE__ */ jsx(NewsArticleByline, { article }),
/* @__PURE__ */ jsx(NewsArticleSourceLink, { article, className: "mt-4" })
] })
] });
}
function ChannelContentListItem({ item }) {
switch (item.model_type) {
case TITLE_MODEL:
return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-24 mb-24", children: [
/* @__PURE__ */ jsx(TitlePoster, { title: item, srcSize: "md", size: "w-128", showPlayButton: true }),
/* @__PURE__ */ jsxs("div", { className: "flex-auto min-w-0 pt-12", children: [
/* @__PURE__ */ jsx(TitleLink, { title: item, className: "font-medium" }),
/* @__PURE__ */ jsxs(BulletSeparatedItems, { className: "text-sm mt-4", children: [
item.runtime ? /* @__PURE__ */ jsx(FormattedDuration, { minutes: item.runtime, verbose: true }) : null,
item.certification && /* @__PURE__ */ jsx("span", { className: "uppercase", children: item.certification })
] }),
item.rating && item.status !== "upcoming" ? /* @__PURE__ */ jsx(InteractableRating, { size: "md", title: item, className: "my-12" }) : /* @__PURE__ */ jsx("div", { className: "my-12", children: /* @__PURE__ */ jsx(FormattedDate, { date: item.release_date }) }),
item.description ? /* @__PURE__ */ jsx("p", { className: "text-sm", children: item.description }) : null
] })
] });
case PERSON_MODEL:
return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-24 mb-24", children: [
/* @__PURE__ */ jsx(PersonPoster, { person: item, srcSize: "md", size: "w-128" }),
/* @__PURE__ */ jsxs("div", { className: "flex-auto min-w-0 pt-12", children: [
/* @__PURE__ */ jsx(PersonLink, { person: item, className: "block font-medium text-lg" }),
item.primary_credit ? /* @__PURE__ */ jsx("div", { className: "text-sm mt-4", children: /* @__PURE__ */ jsx(KnownForCompact, { person: item }) }) : null,
/* @__PURE__ */ jsx("p", { className: "text-sm mt-12", children: item.description })
] })
] });
case NEWS_ARTICLE_MODEL:
return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-14 mb-44", children: [
/* @__PURE__ */ jsx(NewsArticleImage, { article: item, className: "aspect-poster max-w-90" }),
/* @__PURE__ */ jsxs("div", { className: "mt-6 text-base", children: [
/* @__PURE__ */ jsx(NewsArticleLink, { article: item, className: "font-medium" }),
/* @__PURE__ */ jsx("p", { className: "text-sm mt-10", children: item.body }),
/* @__PURE__ */ jsxs(BulletSeparatedItems, { className: "text-xs mt-10", children: [
/* @__PURE__ */ jsx(FormattedDate, { date: item.created_at }),
/* @__PURE__ */ jsx(NewsArticleSourceLink, { article: item })
] })
] })
] });
default:
return null;
}
}
function ChannelContentList(props) {
const isInfiniteScroll = !props.isNested && (!props.channel.config.paginationType || props.channel.config.paginationType === "infiniteScroll");
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(ChannelHeader, { ...props }),
isInfiniteScroll ? /* @__PURE__ */ jsx(InfiniteScrollList, { ...props }) : /* @__PURE__ */ jsx(PaginatedList, { ...props })
] });
}
function InfiniteScrollList({ channel }) {
const query = useInfiniteChannelContent(channel);
return /* @__PURE__ */ jsx(
Content$1,
{
content: query.items,
className: clsx("transition-opacity", query.isReloading && "opacity-70"),
children: /* @__PURE__ */ jsx(InfiniteScrollSentinel, { query })
}
);
}
function PaginatedList({ channel, isNested }) {
var _a;
const shouldPaginate = !isNested;
const query = useChannelContent(channel, null, { paginate: shouldPaginate });
return /* @__PURE__ */ jsxs(
"div",
{
className: clsx(
"transition-opacity",
query.isPlaceholderData && "opacity-70"
),
children: [
shouldPaginate && /* @__PURE__ */ jsx(
PaginationControls,
{
pagination: query.data,
type: channel.config.paginationType,
className: "mb-24"
}
),
/* @__PURE__ */ jsx(Content$1, { content: (_a = query.data) == null ? void 0 : _a.data }),
shouldPaginate && /* @__PURE__ */ jsx(
PaginationControls,
{
pagination: query.data,
type: channel.config.paginationType,
className: "mt-24",
scrollToTop: true
}
)
]
}
);
}
function Content$1({ content: content2 = [], children, className: className2 }) {
return /* @__PURE__ */ jsxs("div", { className: className2, children: [
content2.map((item) => /* @__PURE__ */ jsx(
ChannelContentListItem,
{
item
},
`${item.id}-${item.model_type}`
)),
children
] });
}
function ChannelContent(props) {
var _a;
if (props.isNested && !((_a = props.channel.content) == null ? void 0 : _a.data.length)) {
return null;
}
if (props.channel.config.contentModel === CHANNEL_MODEL) {
return /* @__PURE__ */ jsx(NestedChannels, { ...props });
} else {
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(ChannelLayout, { ...props }),
/* @__PURE__ */ jsx(NoResultsMessage, { channel: props.channel })
] });
}
}
function NoResultsMessage({ channel }) {
var _a;
if (((_a = channel.content) == null ? void 0 : _a.data.length) === 0) {
return /* @__PURE__ */ jsx(
IllustratedMessage,
{
className: "mt-60",
image: /* @__PURE__ */ jsx(SvgImage, { src: todoImage }),
title: channel.type === "list" ? /* @__PURE__ */ jsx(Trans, { message: "This list does not have any content yet." }) : /* @__PURE__ */ jsx(Trans, { message: "This channel does not have any content yet." })
}
);
}
return null;
}
function ChannelLayout(props) {
const { channel, isNested } = props;
const { selectedLayout } = useChannelLayouts(channel);
const layout = isNested ? channel.config.nestedLayout : selectedLayout;
switch (layout) {
case "grid":
return /* @__PURE__ */ jsx(ChannelContentGrid, { ...props, variant: "portrait" });
case "landscapeGrid":
return /* @__PURE__ */ jsx(ChannelContentGrid, { ...props, variant: "landscape" });
case "list":
return /* @__PURE__ */ jsx(ChannelContentList, { ...props });
case "carousel":
return /* @__PURE__ */ jsx(ChannelContentCarousel, { ...props, variant: "portrait" });
case "landscapeCarousel":
return /* @__PURE__ */ jsx(ChannelContentCarousel, { ...props, variant: "landscape" });
case "slider":
return /* @__PURE__ */ jsx(ChannelContentSlider, { ...props });
case "news":
return /* @__PURE__ */ jsx(ChannelContentNews, { ...props });
default:
return null;
}
}
function NestedChannels({ channel, isNested }) {
var _a;
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(ChannelHeader, { channel, isNested }),
(_a = channel.content) == null ? void 0 : _a.data.map((nestedChannel) => /* @__PURE__ */ jsx("div", { className: "mb-40 md:mb-50", children: /* @__PURE__ */ jsx(
ChannelContent,
{
channel: nestedChannel,
isNested: true
}
) }, nestedChannel.id))
] });
}
function useSearchResults(loader, query = "") {
query = query.trim();
if (query === ".") {
query = "";
}
return useQuery({
queryKey: ["search", query, "loader"],
queryFn: ({ signal }) => search(loader, query, signal),
enabled: !!query,
placeholderData: !!query ? keepPreviousData : void 0,
initialData: () => {
var _a;
const data = (_a = getBootstrapData().loaders) == null ? void 0 : _a[loader];
if (query && (data == null ? void 0 : data.query) == query) {
return data;
}
}
});
}
async function search(loader, query, signal) {
await new Promise((resolve) => setTimeout(resolve, 300));
return apiClient.get(`search/${encodeURIComponent(query)}`, {
params: { loader },
signal
}).then((response) => response.data);
}
function SearchAutocomplete({ className: className2 }) {
const { searchQuery } = useParams();
const { trans } = useTrans();
const navigate = useNavigate();
const [query, setQuery] = useState(searchQuery || "");
const [isOpen, setIsOpen] = useState(false);
const { isFetching, data } = useSearchResults("searchAutocomplete", query);
return /* @__PURE__ */ jsx(
"form",
{
onSubmit: (e) => {
e.preventDefault();
if (query.trim().length) {
setIsOpen(false);
navigate(`/search/${encodeURIComponent(query.trim())}`);
}
},
className: clsx(
"flex max-w-580 flex-auto items-center rounded bg-chip/40 text",
className2
),
children: /* @__PURE__ */ jsx(
ComboBoxForwardRef,
{
size: "sm",
startAdornment: /* @__PURE__ */ jsx("button", { type: "submit", "aria-label": trans(message("Search")), children: /* @__PURE__ */ jsx(SearchIcon, { className: "flex-shrink-0 text-muted" }) }),
className: "w-full",
offset: 6,
inputClassName: "w-full outline-none text-sm placeholder:text-muted",
isAsync: true,
hideEndAdornment: true,
placeholder: trans(
message("Search for movies, tv shows and people...")
),
isLoading: isFetching,
inputValue: query,
onInputValueChange: setQuery,
clearInputOnItemSelection: true,
blurReferenceOnItemSelection: true,
selectionMode: "none",
openMenuOnFocus: true,
floatingMaxHeight: 670,
isOpen,
onOpenChange: setIsOpen,
autoFocusFirstItem: false,
children: data == null ? void 0 : data.results.map((result) => {
switch (result.model_type) {
case TITLE_MODEL:
return /* @__PURE__ */ jsx(
Item,
{
value: result.id,
onSelected: () => {
navigate(getTitleLink(result));
},
startIcon: /* @__PURE__ */ jsx(TitlePoster, { title: result, srcSize: "sm", size: "w-46" }),
description: /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx("div", { className: "mb-4", children: result.year }),
/* @__PURE__ */ jsx("div", { children: result.is_series ? /* @__PURE__ */ jsx(Trans, { message: "Tv series" }) : /* @__PURE__ */ jsx(Trans, { message: "Movie" }) })
] }),
textLabel: result.name,
children: result.name
},
result.id
);
case PERSON_MODEL:
return /* @__PURE__ */ jsx(
Item,
{
value: result.id,
onSelected: () => {
navigate(getPersonLink(result));
},
startIcon: /* @__PURE__ */ jsx(
PersonPoster,
{
person: result,
srcSize: "sm",
className: "w-56"
}
),
description: /* @__PURE__ */ jsx(KnownForCompact, { person: result }),
textLabel: result.name,
children: result.name
},
result.id
);
}
})
}
)
}
);
}
function MainNavbar({ position = "relative" }) {
return /* @__PURE__ */ jsxs(
Navbar,
{
size: "md",
menuPosition: "primary",
className: clsx(position, "z-40 w-full flex-shrink-0"),
border: "border-none",
alwaysDarkMode: true,
children: [
/* @__PURE__ */ jsx(Tooltip, { label: /* @__PURE__ */ jsx(Trans, { message: "Search" }), children: /* @__PURE__ */ jsx(IconButton, { elementType: Link, to: "/search", className: "md:hidden", children: /* @__PURE__ */ jsx(SearchIcon, {}) }) }),
/* @__PURE__ */ jsx(SearchAutocomplete, { className: "max-md:hidden" })
]
}
);
}
function AdHost({ slot, className: className2 }) {
var _a;
const settings = useSettings();
const { isSubscribed } = useAuth();
const adCode2 = useMemo(() => {
return dot.pick(`ads.${slot}`, settings);
}, [slot, settings]);
if (((_a = settings.ads) == null ? void 0 : _a.disable) || isSubscribed || !adCode2)
return null;
return /* @__PURE__ */ jsx(InvariantAd, { className: className2, slot, adCode: adCode2 });
}
const InvariantAd = memo(
({ slot, adCode: adCode2, className: className2 }) => {
const ref = useRef(null);
const id2 = useId();
useEffect(() => {
if (ref.current) {
loadAdScripts(adCode2, ref.current).then(() => {
executeAdJavascript(adCode2, id2);
});
}
return () => {
delete window["google_ad_modifications"];
};
}, [adCode2, id2]);
useEffect(() => {
if (ref.current) {
const scrollParent = getScrollParent(ref.current);
if (scrollParent) {
const observer = new MutationObserver(function() {
scrollParent.style.height = "";
scrollParent.style.minHeight = "";
});
observer.observe(scrollParent, {
attributes: true,
attributeFilter: ["style"]
});
return () => observer.disconnect();
}
}
}, []);
return /* @__PURE__ */ jsx(
"div",
{
ref,
id: id2,
className: clsx(
"ad-host flex max-h-[600px] min-h-90 w-full max-w-full items-center justify-center overflow-hidden",
`${slot.replace(/\./g, "-")}-host`,
className2
),
dangerouslySetInnerHTML: { __html: getAdHtml(adCode2) }
}
);
},
() => {
return false;
}
);
function getAdHtml(adCode2) {
return adCode2 == null ? void 0 : adCode2.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "").trim();
}
function loadAdScripts(adCode2, parentEl) {
const promises = [];
const pattern2 = /<script.*?src=['"](.*?)['"]/g;
let match;
while (match = pattern2.exec(adCode2)) {
if (match[1]) {
promises.push(lazyLoader.loadAsset(match[1], { type: "js", parentEl }));
}
}
return Promise.all(promises);
}
function executeAdJavascript(adCode, id) {
const pattern = /<script\b[^>]*>([\s\S]*?)<\/script>/g;
let content;
while (content = pattern.exec(adCode)) {
if (content[1]) {
const r = `var d = document.createElement('div'); d.innerHTML = $1; document.getElementById('${id}').appendChild(d.firstChild);`;
const toEval = content[1].replace(/document.write\((.+?)\);/, r);
eval(toEval);
}
}
}
function SitePageLayout({ children }) {
useScrollToTop();
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
/* @__PURE__ */ jsx(MainNavbar, {}),
/* @__PURE__ */ jsxs("div", { className: "flex-auto", children: [
/* @__PURE__ */ jsx(AdHost, { slot: "general_top", className: "py-24" }),
/* @__PURE__ */ jsx("div", { className: "relative min-h-[1000px] overflow-hidden", children }),
/* @__PURE__ */ jsx(AdHost, { slot: "general_bottom", className: "py-24" })
] }),
/* @__PURE__ */ jsx(Footer, { className: "container mx-auto mt-48 flex-shrink-0 px-24" })
] });
}
function ChannelPage({ slugOrId, type = "channel" }) {
const query = useChannel(slugOrId, "channelPage", { channelType: type });
let content2 = null;
if (query.data) {
content2 = /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx("div", { className: "pb-24", children: /* @__PURE__ */ jsx("div", { className: "container mx-auto p-14 @container md:p-24", children: /* @__PURE__ */ jsx(
ChannelContent,
{
channel: query.data.channel,
isNested: false
},
query.data.channel.id
) }) })
] });
} else {
content2 = /* @__PURE__ */ jsx(
PageStatus,
{
query,
loaderClassName: "absolute inset-0 m-auto",
loaderIsScreen: false
}
);
}
return /* @__PURE__ */ jsx(SitePageLayout, { children: content2 });
}
function TitlePageImageGrid({ images, count, heading, srcSize }) {
const isMobile = useIsMobileMediaQuery();
const { trans } = useTrans();
if (!(images == null ? void 0 : images.length))
return null;
if (!count) {
count = isMobile ? 6 : 5;
}
return /* @__PURE__ */ jsxs("div", { className: "mt-48", children: [
heading,
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-12 md:grid-cols-5 md:gap-24", children: images.slice(0, count).map((image, index) => /* @__PURE__ */ jsxs(DialogTrigger, { type: "modal", children: [
/* @__PURE__ */ jsx(
ButtonBase,
{
"aria-label": trans(message("Image :index", { values: { index } })),
children: /* @__PURE__ */ jsx(ImageItem, { image, srcSize })
}
),
/* @__PURE__ */ jsx(
ImageZoomDialog,
{
images: images.map((img) => img.url),
defaultActiveIndex: index
}
)
] }, image.id)) })
] });
}
function ImageItem({ image, srcSize = "md" }) {
const src = useImageSrc(image.url, { size: srcSize });
return /* @__PURE__ */ jsx(
"img",
{
className: "aspect-square w-full cursor-pointer rounded object-cover",
src,
alt: ""
}
);
}
function TitleCreditsGrid({ credits, className: className2 }) {
if (!credits.length) {
return /* @__PURE__ */ jsx("div", { className: "text-muted italic", children: /* @__PURE__ */ jsx(Trans, { message: "We've no cast information for this title yet." }) });
}
return /* @__PURE__ */ jsx(
"div",
{
className: clsx("grid gap-14 md:gap-20 title-credits-grid", className2),
children: credits.map((credit) => /* @__PURE__ */ jsxs(
"div",
{
className: "flex items-center gap-14 md:gap-20",
children: [
/* @__PURE__ */ jsx(
PersonPoster,
{
rounded: true,
person: credit,
size: "w-70 md:w-96",
srcSize: "md"
}
),
/* @__PURE__ */ jsxs("div", { className: "max-md:text-sm", children: [
/* @__PURE__ */ jsx(PersonLink, { className: "block font-bold", person: credit }),
/* @__PURE__ */ jsx("div", { className: "text-muted", children: /* @__PURE__ */ jsx(Description, { credit }) })
] })
]
},
credit.pivot.id
))
}
);
}
function Description({ credit }) {
if (credit.pivot.department === "actors") {
return /* @__PURE__ */ jsx(Fragment, { children: credit.pivot.character });
}
return /* @__PURE__ */ jsx("span", { className: "capitalize", children: /* @__PURE__ */ jsx(Trans, { message: credit.pivot.job }) });
}
function TitlePageCast({ credits = [] }) {
const cast = credits.filter((credit) => credit.pivot.department === "actors");
return /* @__PURE__ */ jsxs("div", { className: "mt-48", children: [
/* @__PURE__ */ jsx(SiteSectionHeading, { children: /* @__PURE__ */ jsx(Trans, { message: "Cast" }) }),
/* @__PURE__ */ jsx(TitleCreditsGrid, { credits: cast }),
/* @__PURE__ */ jsx(
Button,
{
className: "mt-24",
variant: "outline",
color: "primary",
elementType: Link,
to: "full-credits",
endIcon: /* @__PURE__ */ jsx(ArrowForwardIcon, {}),
children: /* @__PURE__ */ jsx(Trans, { message: "All cast and crew" })
}
)
] });
}
function useRelatedTitles(titleId) {
return useQuery({
queryKey: ["titles", titleId, "related"],
queryFn: () => fetchRelatedTitles(titleId)
});
}
function fetchRelatedTitles(titleId) {
return apiClient.get(`titles/${titleId}/related`).then((response) => response.data);
}
function RelatedTitlesPanel({ title }) {
const { data } = useRelatedTitles(title.id);
if (!data || data.titles.length === 0) {
return null;
}
return /* @__PURE__ */ jsx(RelatedTitlesCarousel, { titles: data.titles });
}
function RelatedTitlesCarousel({ titles }) {
const {
scrollContainerRef,
canScrollForward,
canScrollBackward,
scrollToPreviousPage,
scrollToNextPage,
containerClassName: containerClassName2,
itemClassName: itemClassName2
} = useCarousel();
return /* @__PURE__ */ jsxs("div", { className: "mt-48", children: [
/* @__PURE__ */ jsx(
SiteSectionHeading,
{
actions: /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
IconButton,
{
disabled: !canScrollBackward,
onClick: () => scrollToPreviousPage(),
"aria-label": "Scroll left",
children: /* @__PURE__ */ jsx(KeyboardArrowLeftIcon, {})
}
),
/* @__PURE__ */ jsx(
IconButton,
{
disabled: !canScrollForward,
onClick: () => scrollToNextPage(),
"aria-label": "Scroll right",
children: /* @__PURE__ */ jsx(KeyboardArrowRightIcon, {})
}
)
] }),
children: /* @__PURE__ */ jsx(Trans, { message: "More like this" })
}
),
/* @__PURE__ */ jsx(
"div",
{
ref: scrollContainerRef,
className: clsx(containerClassName2, "content-grid-portrait"),
children: titles.map((item) => /* @__PURE__ */ jsx("div", { className: itemClassName2, children: /* @__PURE__ */ jsx(TitlePortraitGridItem, { item }) }, item.id))
}
)
] });
}
function TitlePageSeasonGrid({ data: { title, seasons } }) {
const query = useTitleSeasons(title.id, seasons);
return /* @__PURE__ */ jsxs("div", { className: "mt-48", children: [
/* @__PURE__ */ jsx(
SiteSectionHeading,
{
titleAppend: (seasons == null ? void 0 : seasons.total) ? `(${seasons.total})` : void 0,
children: /* @__PURE__ */ jsx(Trans, { message: "Seasons" })
}
),
/* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 gap-14 sm:grid-cols-6 lg:grid-cols-8", children: query.items.map((season) => /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(
SeasonPoster,
{
title,
season,
srcSize: "sm",
className: "aspect-poster flex-shrink-0"
}
),
/* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
/* @__PURE__ */ jsx(
SeasonLink,
{
className: "text-sm",
title,
seasonNumber: season.number,
color: "primary"
}
),
/* @__PURE__ */ jsx("div", { className: "text-xs text-muted", children: /* @__PURE__ */ jsx(
FormattedDate,
{
date: season.release_date,
options: { year: "numeric" }
}
) })
] })
] }, season.id)) }),
/* @__PURE__ */ jsx(
InfiniteScrollSentinel,
{
query,
variant: "loadMore",
loaderMarginTop: "mt-14",
size: "sm"
}
)
] })
] });
}
const CompactCredits = memo(({ credits = {} }) => {
var _a, _b, _c, _d;
return /* @__PURE__ */ jsxs("div", { className: "mt-16 flex flex-col gap-14 border-t pt-16", children: [
((_a = credits.creators) == null ? void 0 : _a.length) ? /* @__PURE__ */ jsx(PeopleDetail, { label: /* @__PURE__ */ jsx(Trans, { message: "Created by" }), children: /* @__PURE__ */ jsx(BulletSeparatedItems, { className: "hidden-scrollbar overflow-x-auto", children: credits.creators.slice(0, 3).map((creator) => /* @__PURE__ */ jsx(
PersonLink,
{
person: creator,
color: "primary",
className: "whitespace-nowrap"
},
creator.id
)) }) }) : null,
((_b = credits.directing) == null ? void 0 : _b.length) ? /* @__PURE__ */ jsx(
PeopleDetail,
{
label: /* @__PURE__ */ jsx(
Trans,
{
message: "[one Director|other Directors]",
values: { count: credits.directing.length }
}
),
children: /* @__PURE__ */ jsx(BulletSeparatedItems, { className: "hidden-scrollbar overflow-x-auto", children: credits.directing.slice(0, 3).map((director) => /* @__PURE__ */ jsx(
PersonLink,
{
person: director,
color: "primary",
className: "whitespace-nowrap"
},
director.id
)) })
}
) : null,
((_c = credits.writing) == null ? void 0 : _c.length) ? /* @__PURE__ */ jsx(
PeopleDetail,
{
label: /* @__PURE__ */ jsx(
Trans,
{
message: "[one Writer|other Writers]",
values: { count: credits.writing.length }
}
),
children: /* @__PURE__ */ jsx(BulletSeparatedItems, { className: "hidden-scrollbar overflow-x-auto", children: credits.writing.slice(0, 3).map((writer) => /* @__PURE__ */ jsx(
PersonLink,
{
person: writer,
color: "primary",
className: "whitespace-nowrap"
},
writer.id
)) })
}
) : null,
((_d = credits.actors) == null ? void 0 : _d.length) ? /* @__PURE__ */ jsx(PeopleDetail, { label: /* @__PURE__ */ jsx(Trans, { message: "Stars" }), children: /* @__PURE__ */ jsx(BulletSeparatedItems, { className: "hidden-scrollbar overflow-x-auto", children: credits.actors.slice(0, 3).map((actor) => /* @__PURE__ */ jsx(
PersonLink,
{
person: actor,
color: "primary",
className: "whitespace-nowrap"
},
actor.id
)) }) }) : null
] });
});
function PeopleDetail({ label, children }) {
return /* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 gap-24 md:flex", children: [
/* @__PURE__ */ jsx("div", { className: "min-w-84 font-bold", children: label }),
/* @__PURE__ */ jsx("div", { children })
] });
}
function getGenreLink(genre, { absolute } = {}) {
return getBaseMediaLink(`/genre/${genre.name}`, { absolute });
}
function useTitleNews(titleId) {
return useQuery({
queryKey: ["titles", `${titleId}`, "news"],
queryFn: () => fetchNews(titleId)
});
}
function fetchNews(titleId) {
return apiClient.get(`titles/${titleId}/news`).then((response) => response.data);
}
function TitleNews({ title }) {
const { data, isLoading } = useTitleNews(title.id);
if (!isLoading && !(data == null ? void 0 : data.news_articles.length)) {
return null;
}
return /* @__PURE__ */ jsxs("section", { className: "mt-48", children: [
/* @__PURE__ */ jsx(SiteSectionHeading, { children: /* @__PURE__ */ jsx(Trans, { message: "Related news" }) }),
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-24", children: data == null ? void 0 : data.news_articles.map((article) => /* @__PURE__ */ jsx(NewsArticleGridItem, { article }, article.id)) })
] });
}
function useLinkifiedString(text) {
return useMemo(() => {
if (!text) {
return text;
}
return linkifyStr(text, {
nl2br: true,
attributes: { rel: "nofollow" }
});
}, [text]);
}
function TruncatedDescription({
description,
className: className2
}) {
const linkifiedDescription = useLinkifiedString(description);
const wrapperRef = useRef(null);
const contentRef = useRef(null);
const [isOverflowing, setIsOverflowing] = useState(false);
const [isShowingAll, setIsShowingAll] = useState(false);
useLayoutEffect(() => {
var _a, _b;
const wrapperHeight = ((_a = wrapperRef.current) == null ? void 0 : _a.getBoundingClientRect().height) || 0;
const contentHeight = ((_b = wrapperRef.current) == null ? void 0 : _b.scrollHeight) || 0;
if (contentHeight > wrapperHeight) {
setIsOverflowing(true);
}
}, []);
if (!linkifiedDescription)
return null;
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
"div",
{
ref: wrapperRef,
className: clsx(
"relative",
className2,
!isShowingAll && "max-h-160 overflow-hidden",
!isShowingAll && isOverflowing && "after:absolute after:bottom-0 after:left-0 after:h-20 after:w-full after:bg-gradient-to-b after:from-transparent after:to-background"
),
children: /* @__PURE__ */ jsx(
"div",
{
ref: contentRef,
dangerouslySetInnerHTML: { __html: linkifiedDescription }
}
)
}
),
isOverflowing && /* @__PURE__ */ jsx(
Button,
{
size: "xs",
className: "mt-20",
variant: "outline",
onClick: () => setIsShowingAll(!isShowingAll),
children: isShowingAll ? /* @__PURE__ */ jsx(Trans, { message: "Show less" }) : /* @__PURE__ */ jsx(Trans, { message: "Show more" })
}
)
] });
}
const NewReviewForm = forwardRef(
({ reviewable, currentReview, className: className2, disabled }, ref) => {
const [isExpanded, setIsExpanded] = useState(false);
const { user } = useAuth();
const form = useForm({
defaultValues: {
score: 8
}
});
useEffect(() => {
if (currentReview) {
form.setValue("title", currentReview.title);
form.setValue("body", currentReview.body);
form.setValue("score", currentReview.score);
}
}, [form, currentReview]);
const openReviewPanel = useCallback(() => {
setIsExpanded(true);
}, []);
useImperativeHandle(
ref,
() => ({
openReviewPanel
}),
[openReviewPanel]
);
const createReview = useCreateReview(form);
return /* @__PURE__ */ jsxs(
Form,
{
className: clsx("rounded border bg-alt p-14", className2),
form,
onSubmit: (newValues) => {
if (disabled)
return;
createReview.mutate(
{
...newValues,
reviewable
},
{
onSuccess: () => {
toast(message("Review posted"));
setIsExpanded(false);
}
}
);
},
children: [
/* @__PURE__ */ jsxs("div", { className: "items-center gap-24 lg:flex", children: [
/* @__PURE__ */ jsx(
Avatar,
{
size: "xl",
circle: true,
src: user == null ? void 0 : user.avatar,
label: user == null ? void 0 : user.display_name
}
),
/* @__PURE__ */ jsxs("div", { className: "flex-auto", children: [
/* @__PURE__ */ jsx("div", { className: "mb-4 text-xs text-muted max-md:mt-10", children: /* @__PURE__ */ jsx(
Trans,
{
message: "Review as :name",
values: {
name: /* @__PURE__ */ jsx("span", { className: "font-medium text", children: user == null ? void 0 : user.display_name })
}
}
) }),
/* @__PURE__ */ jsx(
StarSelector,
{
readonly: disabled,
className: "-ml-8 max-lg:mb-12",
count: 10,
value: disabled ? 0 : form.watch("score"),
onValueChange: (newScore) => {
form.setValue("score", newScore);
}
}
)
] }),
!isExpanded && /* @__PURE__ */ jsx(
Button,
{
variant: "flat",
color: "primary",
onClick: () => openReviewPanel(),
disabled: !user || disabled,
children: currentReview ? /* @__PURE__ */ jsx(Trans, { message: "Update review" }) : /* @__PURE__ */ jsx(Trans, { message: "Add review" })
}
)
] }),
isExpanded && /* @__PURE__ */ jsxs("div", { className: "mt-24", children: [
/* @__PURE__ */ jsx(
FormTextField,
{
name: "title",
className: "mb-24",
label: /* @__PURE__ */ jsx(Trans, { message: "Title" }),
labelSuffix: /* @__PURE__ */ jsx(Trans, { message: "10 character minimum" }),
autoFocus: true,
minLength: 10,
required: true
}
),
/* @__PURE__ */ jsx(
FormTextField,
{
name: "body",
label: /* @__PURE__ */ jsx(Trans, { message: "Review" }),
labelSuffix: /* @__PURE__ */ jsx(Trans, { message: "100 character minimum" }),
inputElementType: "textarea",
rows: 5,
minLength: 100,
required: true
}
),
/* @__PURE__ */ jsxs("div", { className: "mt-16 flex items-center justify-end gap-8", children: [
/* @__PURE__ */ jsx(
Button,
{
variant: "outline",
className: "min-w-100",
onClick: () => {
setIsExpanded(false);
form.reset(currentReview);
},
children: /* @__PURE__ */ jsx(Trans, { message: "Cancel" })
}
),
/* @__PURE__ */ jsx(
Button,
{
type: "submit",
variant: "flat",
color: "primary",
className: "min-w-100",
disabled: createReview.isPending,
children: /* @__PURE__ */ jsx(Trans, { message: "Post" })
}
)
] })
] })
]
}
);
}
);
function useSubmitReviewFeedback(review) {
return useMutation({
mutationFn: (payload) => submitFeedback(payload, review),
onSuccess: () => {
toast(message("Feedback submitted"));
},
onError: (r2) => showHttpErrorToast(r2)
});
}
function submitFeedback(payload, review) {
return apiClient.post(`reviews/${review.id}/feedback`, {
is_helpful: payload.isHelpful
}).then((r2) => r2.data);
}
function useSubmitReport(model) {
return useMutation({
mutationFn: (payload) => submitReport(model, payload),
onSuccess: () => {
toast(message("Thanks for reporting. We will review this content."));
},
onError: (err) => showHttpErrorToast(err)
});
}
function submitReport(model, payload) {
return apiClient.post("report", {
reason: payload.reason,
model_id: model.id,
model_type: model.model_type
}).then((r2) => r2.data);
}
function useDeleteReport(model) {
return useMutation({
mutationFn: () => deleteReport(model),
onSuccess: () => {
toast(message("Report removed"));
},
onError: (err) => showHttpErrorToast(err)
});
}
function deleteReport(reportable) {
return apiClient.delete(`report/${reportable.model_type}/${reportable.id}`).then((r2) => r2.data);
}
function ReviewListItem$1({
review,
isShared,
hideShareButton,
avatar
}) {
const isMobile = useIsMobileMediaQuery();
const ref = useRef(null);
const scrolled = useRef(false);
useEffect(() => {
if (isShared && !scrolled.current) {
setTimeout(() => {
var _a;
(_a = ref.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
scrolled.current = true;
}, 50);
}
}, [isShared]);
return /* @__PURE__ */ jsxs("div", { ref, children: [
isShared && /* @__PURE__ */ jsx("div", { className: "mb-8 mt-16 text-sm", children: /* @__PURE__ */ jsx(Trans, { message: "Shared review" }) }),
/* @__PURE__ */ jsxs(
"div",
{
className: clsx(
"group flex min-h-70 items-start gap-24 rounded py-18",
isShared && "mb-34 border bg-alt pl-12"
),
children: [
!isMobile && (avatar || /* @__PURE__ */ jsx(UserAvatar, { user: review.user, size: "xl", circle: true })),
/* @__PURE__ */ jsxs("div", { className: "flex-auto text-sm", children: [
/* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-center gap-8", children: [
review.user && /* @__PURE__ */ jsx(UserDisplayName$1, { user: review.user }),
/* @__PURE__ */ jsx("time", { className: "text-xs text-muted", children: /* @__PURE__ */ jsx(FormattedRelativeTime, { date: review.created_at }) })
] }),
/* @__PURE__ */ jsx(TitleRating, { className: "mb-8 mt-10", score: review.score }),
review.title && /* @__PURE__ */ jsx("div", { className: "mb-8 text-base font-medium", children: review.title }),
/* @__PURE__ */ jsx("div", { className: "whitespace-break-spaces text-sm", children: review.body }),
/* @__PURE__ */ jsxs("div", { className: "mt-16 items-center gap-8 md:flex", children: [
/* @__PURE__ */ jsx(Feedback, { review }),
!hideShareButton && /* @__PURE__ */ jsx(ShareButton$3, { review }),
/* @__PURE__ */ jsx(ReviewOptionsTrigger, { review })
] })
] })
]
}
)
] });
}
function ShareButton$3({ review }) {
const { base_url } = useSettings();
const location = useLocation();
const url = `${base_url}${location.pathname}?reviewId=${review.id}`;
const [, copyLink] = useClipboard(url);
return /* @__PURE__ */ jsx(Tooltip, { label: /* @__PURE__ */ jsx(Trans, { message: "Share" }), children: /* @__PURE__ */ jsx(
IconButton,
{
className: "text-muted",
onClick: () => {
copyLink();
toast(message("Review link copied to clipboard"));
},
children: /* @__PURE__ */ jsx(ShareIcon, {})
}
) });
}
function Feedback({ review }) {
const { user } = useAuth();
const authHandler = useAuthClickCapture();
const submitFeedback2 = useSubmitReviewFeedback(review);
const isDisabled = submitFeedback2.isPending || user != null && user.id === review.user_id;
const [helpfulCount, setHelpfulCount] = useState(review.helpful_count || 1);
const [total, setTotal] = useState(
review.helpful_count + review.not_helpful_count || 1
);
let initialFeedback;
if (review.current_user_feedback != null) {
initialFeedback = review.current_user_feedback ? "helpful" : "not_helpful";
}
const [currentFeedback, setCurrentFeedback] = useState(
initialFeedback
);
return /* @__PURE__ */ jsxs("div", { className: "mr-auto flex flex-wrap items-center gap-6 max-md:mb-12", children: [
/* @__PURE__ */ jsx("div", { className: "text-xs text-muted", children: /* @__PURE__ */ jsx(
Trans,
{
message: ":helpfulCount out of :total people found this helpful. Was this review helpful?",
values: { helpfulCount, total }
}
) }),
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6 pb-2", children: [
/* @__PURE__ */ jsx(
Button,
{
variant: "link",
className: clsx(
"uppercase",
currentFeedback === "helpful" && "pointer-events-none"
),
color: currentFeedback === "helpful" ? "primary" : void 0,
disabled: isDisabled,
onClickCapture: authHandler,
onClick: () => submitFeedback2.mutate(
{ isHelpful: true },
{
onSuccess: () => {
setHelpfulCount((count) => count + 1);
setCurrentFeedback("helpful");
if (!currentFeedback) {
setTotal((count) => count + 1);
}
}
}
),
children: /* @__PURE__ */ jsx(Trans, { message: "Yes" })
}
),
/* @__PURE__ */ jsx("div", { className: "h-14 w-1 bg-divider" }),
/* @__PURE__ */ jsx(
Button,
{
variant: "link",
className: clsx(
"uppercase",
currentFeedback === "not_helpful" && "pointer-events-none"
),
color: currentFeedback === "not_helpful" ? "primary" : void 0,
disabled: isDisabled,
onClickCapture: authHandler,
onClick: () => submitFeedback2.mutate(
{ isHelpful: false },
{
onSuccess: () => {
setHelpfulCount((count) => count - 1);
setCurrentFeedback("not_helpful");
if (!currentFeedback) {
setTotal((count) => count + 1);
}
}
}
),
children: /* @__PURE__ */ jsx(Trans, { message: "No" })
}
)
] })
] });
}
function ReviewOptionsTrigger({ review }) {
const { user, hasPermission } = useAuth();
const report = useSubmitReport(review);
const deleteReport2 = useDeleteReport(review);
const [isReported, setIsReported] = useState(review.current_user_reported);
const handleReport = () => {
if (isReported) {
deleteReport2.mutate(void 0, {
onSuccess: () => setIsReported(false)
});
} else {
report.mutate({}, { onSuccess: () => setIsReported(true) });
}
};
const deleteReview = useDeleteReviews();
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const showDeleteButton = user && review.user_id === user.id || hasPermission("reviews.delete");
const handleDelete = (isConfirmed) => {
setIsDeleteDialogOpen(false);
if (isConfirmed) {
deleteReview.mutate({ reviewIds: [review.id] });
}
};
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsxs(MenuTrigger, { children: [
/* @__PURE__ */ jsx(IconButton, { className: "text-muted", "aria-label": "More options", children: /* @__PURE__ */ jsx(MoreVertIcon, {}) }),
/* @__PURE__ */ jsxs(Menu, { children: [
/* @__PURE__ */ jsx(Item, { value: "report", onSelected: () => handleReport(), children: isReported ? /* @__PURE__ */ jsx(Trans, { message: "Remove report" }) : /* @__PURE__ */ jsx(Trans, { message: "Report review" }) }),
showDeleteButton && /* @__PURE__ */ jsx(
Item,
{
value: "delete",
onSelected: () => setIsDeleteDialogOpen(true),
children: /* @__PURE__ */ jsx(Trans, { message: "Delete" })
}
)
] })
] }),
/* @__PURE__ */ jsx(
DialogTrigger,
{
type: "modal",
isOpen: isDeleteDialogOpen,
onClose: (isConfirmed) => handleDelete(isConfirmed),
children: /* @__PURE__ */ jsx(
ConfirmationDialog,
{
isDanger: true,
title: /* @__PURE__ */ jsx(Trans, { message: "Delete review?" }),
body: /* @__PURE__ */ jsx(Trans, { message: "Are you sure you want to delete this review?" }),
confirm: /* @__PURE__ */ jsx(Trans, { message: "Delete" })
}
)
}
)
] });
}
function UserDisplayName$1({ user }) {
const isMobile = useIsMobileMediaQuery();
const { auth } = useContext(SiteConfigContext);
const sharedClassName = "flex items-center gap-8 text-base font-medium";
if (auth.getUserProfileLink) {
return /* @__PURE__ */ jsxs(Fragment, { children: [
isMobile && /* @__PURE__ */ jsx(UserAvatar, { user, size: "sm", circle: true }),
/* @__PURE__ */ jsx(
Link,
{
to: auth.getUserProfileLink(user),
className: clsx("hover:underline", sharedClassName),
children: user.display_name
}
)
] });
}
return /* @__PURE__ */ jsxs("div", { className: sharedClassName, children: [
isMobile && /* @__PURE__ */ jsx(UserAvatar, { user, size: "sm", circle: true }),
user.display_name
] });
}
function AccountRequiredCard({ message: message2 }) {
const { user } = useAuth();
if (user)
return null;
return /* @__PURE__ */ jsxs("div", { className: "border border-dashed py-30 px-20 my-40 mx-auto text-center max-w-850 rounded", children: [
/* @__PURE__ */ jsx("div", { className: "text-xl font-semibold mb-8", children: /* @__PURE__ */ jsx(Trans, { message: "Account required" }) }),
/* @__PURE__ */ jsx("div", { className: "text-muted text-base", children: /* @__PURE__ */ jsx(
Trans,
{
...message2,
values: {
l: (parts) => /* @__PURE__ */ jsx(Link, { className: LinkStyle, to: "/login", children: parts }),
r: (parts) => /* @__PURE__ */ jsx(Link, { className: LinkStyle, to: "/register", children: parts })
}
}
) })
] });
}
const accountRequiredMessage$1 = message(
"Please <l>login</l> or <r>create account</r> to add a review"
);
function ReviewList({
reviewable,
disabled,
noResultsMessage,
showAccountRequiredMessage
}) {
var _a, _b;
const query = useReviews(reviewable);
const actionsRef = useRef(null);
const { user } = useAuth();
const currentUserReview = (_a = query.data) == null ? void 0 : _a.pages[0].current_user_review;
const sharedReview = (_b = query.data) == null ? void 0 : _b.pages[0].shared_review;
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(
NewReviewForm,
{
className: "mb-14 md:-mx-14",
reviewable,
currentReview: currentUserReview,
ref: actionsRef,
disabled
}
),
/* @__PURE__ */ jsxs("div", { children: [
showAccountRequiredMessage && /* @__PURE__ */ jsx(AccountRequiredCard, { message: accountRequiredMessage$1 }),
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: query.isLoading ? /* @__PURE__ */ jsx(ReviewListSkeletons, { count: 4 }) : /* @__PURE__ */ jsx(
ReviewListItems,
{
reviews: query.items,
sharedReview,
noResultsMessage
}
) }),
/* @__PURE__ */ jsx("div", { className: "ml-84", children: /* @__PURE__ */ jsx(
InfiniteScrollSentinel,
{
query,
variant: "loadMore",
loaderMarginTop: "mt-14",
loadMoreExtraContent: /* @__PURE__ */ jsx(
Button,
{
variant: "flat",
color: "primary",
disabled: !user,
onClick: () => {
var _a2;
(_a2 = actionsRef.current) == null ? void 0 : _a2.openReviewPanel();
},
children: /* @__PURE__ */ jsx(Trans, { message: "Add a review" })
}
)
}
) })
] })
] });
}
function ReviewListItems({
reviews,
sharedReview,
noResultsMessage
}) {
const { user } = useAuth();
let content2;
if (!reviews.length) {
content2 = user ? noResultsMessage || /* @__PURE__ */ jsx(
IllustratedMessage,
{
className: "mt-24",
size: "sm",
title: /* @__PURE__ */ jsx(Trans, { message: "Seems a little quiet over here" }),
description: /* @__PURE__ */ jsx(Trans, { message: "Be the first to leave a review" })
}
) : null;
} else {
content2 = reviews.map((review) => /* @__PURE__ */ jsx(ReviewListItem$1, { review }, review.id));
}
return /* @__PURE__ */ jsxs(m.div, { ...opacityAnimation, children: [
sharedReview && /* @__PURE__ */ jsx(ReviewListItem$1, { review: sharedReview, isShared: true }),
content2
] }, "reviews");
}
function ReviewListSkeletons({ count }) {
return /* @__PURE__ */ jsx(m.div, { ...opacityAnimation, children: [...new Array(count).keys()].map((index) => /* @__PURE__ */ jsxs(
"div",
{
className: "flex items-start gap-24 py-18 min-h-[212px] group",
children: [
/* @__PURE__ */ jsx(Skeleton, { variant: "avatar", radius: "rounded-full", size: "w-60 h-60" }),
/* @__PURE__ */ jsxs("div", { className: "flex-auto text-sm", children: [
/* @__PURE__ */ jsx(
Skeleton,
{
className: "text-base font-medium max-w-200 mb-4",
variant: "text"
}
),
/* @__PURE__ */ jsx(Skeleton, { variant: "text", className: "max-w-60 mb-8 mt-10 text-lg" }),
/* @__PURE__ */ jsx(Skeleton, { variant: "text", className: "mb-8 text-base max-w-240" }),
/* @__PURE__ */ jsx(Skeleton, { className: "text-sm", variant: "text" }),
/* @__PURE__ */ jsx(Skeleton, { className: "text-sm", variant: "text" }),
/* @__PURE__ */ jsx(Skeleton, { className: "text-xs mt-16", variant: "text" })
] })
]
},
index
)) }, "loading-skeleton");
}
function TitlePageReviewList({ title }) {
const [sort, setSort] = useLocalStorage(
`reviewSort.${title.model_type}`,
"created_at:desc"
);
const query = useReviews(title);
return /* @__PURE__ */ jsxs("div", { className: "mt-48", children: [
/* @__PURE__ */ jsx(
SiteSectionHeading,
{
titleAppend: query.totalItems ? /* @__PURE__ */ jsxs("span", { children: [
"(",
query.totalItems,
")"
] }) : null,
actions: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-24", children: [
/* @__PURE__ */ jsx(TitleRating, { score: title.rating, className: "max-md:hidden" }),
/* @__PURE__ */ jsx(
ReviewListSortButton,
{
value: sort,
onValueChange: (newValue) => setSort(newValue)
}
)
] }),
children: /* @__PURE__ */ jsx(Trans, { message: "Reviews" })
}
),
/* @__PURE__ */ jsx(
ReviewList,
{
reviewable: title,
showAccountRequiredMessage: title.status !== "upcoming",
noResultsMessage: title.status === "upcoming" ? /* @__PURE__ */ jsx(
IllustratedMessage,
{
className: "mt-24",
size: "sm",
title: /* @__PURE__ */ jsx(Trans, { message: "This title is not released yet" }),
description: /* @__PURE__ */ jsx(
Trans,
{
message: "Come back after :date to see the reviews",
values: { date: /* @__PURE__ */ jsx(FormattedDate, { date: title.release_date }) }
}
)
}
) : void 0
}
)
] });
}
function TitlePageVideoGrid({ title, episode }) {
const videos = episode ? episode.videos : title.videos;
const link = episode ? `${getEpisodeLink(
title,
episode.season_number,
episode.episode_number
)}/episodes/${episode.id}/videos` : `${getTitleLink(title)}/videos`;
return /* @__PURE__ */ jsx(
VideoGrid,
{
videos,
title,
episode,
heading: /* @__PURE__ */ jsx(SiteSectionHeading, { link, children: /* @__PURE__ */ jsx(Trans, { message: "Videos" }) })
}
);
}
function TitlePageEpisodeGrid({ data, label, showSeasonSelector }) {
const { season } = useParams();
const [selectedSeason, setSelectedSeason] = useState(
season ? parseInt(season) : 1
);
const query = useSeasonEpisodes(
data.episodes,
{
perPage: 21,
excludeDescription: "true"
},
{
season: selectedSeason,
willSortOrFilter: true,
defaultOrderBy: "episode_number",
defaultOrderDir: "asc",
titleId: data.title.id
}
);
const { isInitialLoading, items, sortDescriptor, setSortDescriptor } = query;
return /* @__PURE__ */ jsxs("div", { className: "mt-48", children: [
/* @__PURE__ */ jsx(
SiteSectionHeading,
{
actions: /* @__PURE__ */ jsxs(Fragment, { children: [
showSeasonSelector && /* @__PURE__ */ jsx(
SeasonSelector,
{
selectedSeason,
onSeasonChange: setSelectedSeason,
seasonCount: data.title.seasons_count
}
),
/* @__PURE__ */ jsx(
SortButton,
{
value: `${sortDescriptor.orderBy}:${sortDescriptor == null ? void 0 : sortDescriptor.orderDir}`,
onValueChange: (value) => {
const [orderBy, orderDir] = value.split(":");
setSortDescriptor({
orderBy,
orderDir
});
}
}
)
] }),
children: label || /* @__PURE__ */ jsx(Trans, { message: "Episodes" })
}
),
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: isInitialLoading ? /* @__PURE__ */ jsx(SkeletonGrid, {}) : /* @__PURE__ */ jsx(EpisodeGrid, { episodes: items, title: data.title, query }) })
] });
}
function GridItem({ episode, title }) {
const runtime = episode.runtime || title.runtime;
const name = /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(CompactSeasonEpisode, { className: "uppercase", episode }),
" -",
" ",
episode.name
] });
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
EpisodePoster,
{
episode,
title,
srcSize: "md",
showPlayButton: true,
rightAction: runtime ? /* @__PURE__ */ jsx("span", { className: "rounded bg-black/50 p-4 text-xs font-medium text-white", children: /* @__PURE__ */ jsx(FormattedDuration, { minutes: runtime, verbose: true }) }) : null
}
) }),
/* @__PURE__ */ jsxs("div", { className: "mt-10", children: [
episode.release_date && /* @__PURE__ */ jsx("div", { className: "mb-2 text-sm text-muted", children: /* @__PURE__ */ jsx(FormattedDate, { date: episode.release_date }) }),
/* @__PURE__ */ jsx("div", { className: "overflow-hidden overflow-ellipsis whitespace-nowrap text-base", children: episode.primary_video ? /* @__PURE__ */ jsx(
Link,
{
className: "rounded outline-none hover:underline focus-visible:ring focus-visible:ring-offset-2",
to: getWatchLink(episode.primary_video),
children: name
}
) : name })
] })
] });
}
function EpisodeGrid({ title, episodes, query }) {
return /* @__PURE__ */ jsxs(m.div, { ...opacityAnimation, children: [
/* @__PURE__ */ jsx(ContentGridLayout, { variant: "landscape", children: episodes.map((episode) => /* @__PURE__ */ jsx(GridItem, { episode, title }, episode.id)) }),
/* @__PURE__ */ jsx(
InfiniteScrollSentinel,
{
query,
variant: "loadMore",
size: "sm",
loaderMarginTop: "mt-16"
}
)
] }, "episode-grid");
}
function SkeletonGrid() {
return /* @__PURE__ */ jsx(m.div, { ...opacityAnimation, children: /* @__PURE__ */ jsx(ContentGridLayout, { variant: "landscape", children: [...new Array(6).keys()].map((number) => /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(Skeleton, { variant: "rect", size: "aspect-video", animation: "pulsate" }),
/* @__PURE__ */ jsxs("div", { className: "mt-10 min-h-44", children: [
/* @__PURE__ */ jsx(Skeleton, { variant: "text" }),
/* @__PURE__ */ jsx(Skeleton, { variant: "text" })
] })
] }, number)) }) }, "episode-grid");
}
function SeasonSelector({
selectedSeason,
onSeasonChange,
seasonCount
}) {
return /* @__PURE__ */ jsxs(
MenuTrigger,
{
selectedValue: selectedSeason,
onSelectionChange: (newValue) => onSeasonChange(newValue),
selectionMode: "single",
children: [
/* @__PURE__ */ jsx(Button, { variant: "outline", startIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), className: "mr-4", children: /* @__PURE__ */ jsx(Trans, { message: "Season :number", values: { number: selectedSeason } }) }),
/* @__PURE__ */ jsx(Menu, { children: [...new Array(seasonCount).keys()].map((number) => {
const seasonNumber = number + 1;
return /* @__PURE__ */ jsx(Item, { value: seasonNumber, children: /* @__PURE__ */ jsx(Trans, { message: "Season :number", values: { number: seasonNumber } }) }, seasonNumber);
}) })
]
}
);
}
const SortOptions = [
{
value: "episode_number:desc",
label: message("Newest")
},
{
value: "episode_number:asc",
label: message("Oldest")
}
];
function SortButton({ value, onValueChange }) {
let selectedOption = SortOptions.find((option) => option.value === value);
if (!selectedOption) {
selectedOption = SortOptions[0];
}
return /* @__PURE__ */ jsxs(
MenuTrigger,
{
selectedValue: value,
onSelectionChange: (newValue) => onValueChange(newValue),
selectionMode: "single",
children: [
/* @__PURE__ */ jsx(Button, { variant: "outline", startIcon: /* @__PURE__ */ jsx(SortIcon, {}), children: /* @__PURE__ */ jsx(Trans, { ...selectedOption.label }) }),
/* @__PURE__ */ jsx(Menu, { children: SortOptions.map((option) => /* @__PURE__ */ jsx(Item, { value: option.value, children: /* @__PURE__ */ jsx(Trans, { ...option.label }) }, option.value)) })
]
}
);
}
function TitlePageMainContent({ data, className: className2 }) {
var _a, _b;
const { title, credits } = data;
const { title_page } = useSettings();
return /* @__PURE__ */ jsxs("main", { className: clsx(className2, "@container"), children: [
((_a = title.genres) == null ? void 0 : _a.length) ? /* @__PURE__ */ jsx(ChipList, { children: title.genres.map((genre) => /* @__PURE__ */ jsx(
Chip,
{
className: "capitalize",
elementType: Link,
to: getGenreLink(genre),
children: /* @__PURE__ */ jsx(Trans, { message: genre.display_name || genre.name })
},
genre.id
)) }) : null,
title.tagline && /* @__PURE__ */ jsxs("blockquote", { className: "mt-16", children: [
"“",
title.tagline,
"”"
] }),
/* @__PURE__ */ jsx(TruncatedDescription, { className: "mt-16", description: title.description }),
/* @__PURE__ */ jsx(CompactCredits, { credits }),
/* @__PURE__ */ jsx(AdHost, { slot: "title_top", className: "pt-48" }),
(_b = title_page == null ? void 0 : title_page.sections) == null ? void 0 : _b.map((name) => /* @__PURE__ */ jsx(TitlePageSection, { name, title, data }, name))
] });
}
function TitlePageSection({ name, title, data }) {
var _a;
const { titles } = useSettings();
const { hasPermission } = useAuth();
switch (name) {
case "episodes":
return title.is_series ? /* @__PURE__ */ jsx(TitlePageEpisodeGrid, { data, showSeasonSelector: true }) : null;
case "seasons":
return title.is_series ? /* @__PURE__ */ jsx(TitlePageSeasonGrid, { data }) : null;
case "videos":
return /* @__PURE__ */ jsx(TitlePageVideoGrid, { title });
case "images":
return /* @__PURE__ */ jsx(
TitlePageImageGrid,
{
images: title.images,
heading: /* @__PURE__ */ jsx(SiteSectionHeading, { link: `${getTitleLink(title)}/images`, children: /* @__PURE__ */ jsx(Trans, { message: "Images" }) })
}
);
case "reviews":
return titles.enable_reviews && hasPermission("reviews.view") ? /* @__PURE__ */ jsx(TitlePageReviewList, { title }) : null;
case "cast":
return /* @__PURE__ */ jsx(TitlePageCast, { credits: (_a = data.credits) == null ? void 0 : _a.actors });
case "news":
return /* @__PURE__ */ jsx(TitleNews, { title });
case "related":
return /* @__PURE__ */ jsx(RelatedTitlesPanel, { title });
}
}
function TitlePageHeaderLayout({
name,
description,
children,
right,
poster
}) {
return /* @__PURE__ */ jsxs("div", { className: "mb-24 items-center justify-between gap-24 lg:flex", children: [
poster,
/* @__PURE__ */ jsxs("div", { className: "flex-auto", children: [
children,
/* @__PURE__ */ jsx("h1", { className: "mb-12 text-4xl md:mb-8 md:text-5xl", children: name }),
description && /* @__PURE__ */ jsx("div", { className: "text-base font-normal", children: description })
] }),
right
] });
}
function TitlePageHeader({ title, showPoster = false }) {
return /* @__PURE__ */ jsx(
TitlePageHeaderLayout,
{
name: /* @__PURE__ */ jsx(TitleLink, { title }),
poster: showPoster ? /* @__PURE__ */ jsx(TitlePoster, { title, size: "w-80", srcSize: "sm" }) : null,
description: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(BulletSeparatedItems, { children: [
/* @__PURE__ */ jsx(FormattedDate, { date: title.release_date }),
title.certification && /* @__PURE__ */ jsx("div", { className: "uppercase", children: title.certification }),
title.runtime && /* @__PURE__ */ jsx(FormattedDuration, { minutes: title.runtime, verbose: true })
] }) }),
right: /* @__PURE__ */ jsx(InteractableRating, { title })
}
);
}
function TitlePageHeaderImage({ title, season, episode }) {
const { streaming } = useSettings();
const watchItem = episode || season || title;
const backdropUrl = (episode == null ? void 0 : episode.poster) || title.backdrop;
if (!backdropUrl) {
return null;
}
const backdrop = /* @__PURE__ */ jsx(
TitleBackdrop,
{
title,
episode,
size: "w-full h-full",
className: "object-top",
lazy: false
}
);
return /* @__PURE__ */ jsxs("header", { className: "relative isolate max-h-320 overflow-hidden bg-black md:max-h-400 lg:max-h-450", children: [
/* @__PURE__ */ jsx("div", { className: "container relative left-0 right-0 top-0 z-20 mx-auto h-full w-full px-24", children: backdrop }),
/* @__PURE__ */ jsx("div", { className: "h-[calc(100% + 20px)] absolute left-1/2 top-1/2 z-10 w-[calc(100%+100px)] -translate-x-1/2 -translate-y-1/2 bg-black opacity-50 blur-md", children: backdrop }),
/* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute left-0 top-0 z-30 h-full w-full bg-gradient-to-b from-black/20 md:from-black/40" }),
(streaming == null ? void 0 : streaming.show_header_play) && (watchItem == null ? void 0 : watchItem.primary_video) ? /* @__PURE__ */ jsx(PlayButton, { item: watchItem }) : null
] });
}
function PlayButton({ item }) {
const link = getWatchLink(item.primary_video);
return /* @__PURE__ */ jsx(
IconButton,
{
radius: "rounded-full",
color: "white",
variant: "raised",
size: "lg",
className: "absolute inset-0 z-40 m-auto",
elementType: Link,
to: link,
children: /* @__PURE__ */ jsx(MediaPlayIcon, {})
}
);
}
function useCurrentUserWatchlist() {
const { user } = useAuth();
return useQuery({
queryKey: ["channel", "watchlist", "compact"],
queryFn: () => fetchWatchlist(),
enabled: !!user
});
}
function useIsItemWatchlisted(item) {
var _a, _b, _c;
const query = useCurrentUserWatchlist();
return {
isLoading: query.isLoading && query.fetchStatus !== "idle",
isWatchlisted: !!((_c = (_b = (_a = query.data) == null ? void 0 : _a.watchlist) == null ? void 0 : _b.items[item.model_type]) == null ? void 0 : _c[item.id])
};
}
function fetchWatchlist() {
return apiClient.get(`users/me/watchlist`).then((response) => response.data);
}
function useAddToWatchlist() {
const { data } = useCurrentUserWatchlist();
return useMutation({
mutationFn: (payload) => addToWatchlist(data.watchlist.id, payload),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: ["channel", "watchlist"]
});
toast(message("Added to your watchlist"));
},
onError: (r2) => showHttpErrorToast(r2)
});
}
function addToWatchlist(listId, payload) {
return apiClient.post(`channel/${listId}/add`, {
itemId: payload.id,
itemType: payload.model_type
}).then((r2) => r2.data);
}
function useRemoveFromWatchlist() {
const { data } = useCurrentUserWatchlist();
return useMutation({
mutationFn: (payload) => removeFromWatchlist(data.watchlist.id, payload),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: ["channel", "watchlist"]
});
toast(message("Removed from your watchlist"));
},
onError: (r2) => showHttpErrorToast(r2)
});
}
function removeFromWatchlist(listId, payload) {
return apiClient.post(`channel/${listId}/remove`, {
itemId: payload.id,
itemType: payload.model_type
}).then((r2) => r2.data);
}
function WatchlistButton({
item,
variant = "flat",
color = "primary"
}) {
const { isLoading, isWatchlisted } = useIsItemWatchlisted(item);
const addToWatchlist2 = useAddToWatchlist();
const removeFromWatchlist2 = useRemoveFromWatchlist();
const authHandler = useAuthClickCapture();
return /* @__PURE__ */ jsx(
Button,
{
variant,
color,
startIcon: isWatchlisted ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(AddIcon, {}),
className: "mt-14 min-h-40 w-full",
disabled: addToWatchlist2.isPending || removeFromWatchlist2.isPending || isLoading,
onClickCapture: authHandler,
onClick: () => {
if (isWatchlisted) {
removeFromWatchlist2.mutate(item);
} else {
addToWatchlist2.mutate(item);
}
},
children: isWatchlisted ? /* @__PURE__ */ jsx(Trans, { message: "In watchlist" }) : /* @__PURE__ */ jsx(Trans, { message: "Add to watchlist" })
}
);
}
function TitlePageAsideLayout({ poster, children, className: className2 }) {
return /* @__PURE__ */ jsxs("div", { className: clsx("top-40 flex-shrink-0 md:sticky md:w-1/4", className2), children: [
poster,
/* @__PURE__ */ jsx("div", { className: "flex-auto max-md:ml-16 max-md:text-sm", children })
] });
}
function DetailItem({ label, children }) {
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx("dt", { className: "font-semibold", children: label }),
/* @__PURE__ */ jsx("dl", { className: "mb-12 md:mb-24", children })
] });
}
function KeywordLink({ keyword, children, ...otherProps }) {
const link = useMemo(() => getKeywordLink$1(keyword), [keyword]);
return /* @__PURE__ */ jsx(BaseMediaLink, { ...otherProps, link, children: children ?? /* @__PURE__ */ jsx(Trans, { message: keyword.display_name || keyword.name }) });
}
function getKeywordLink$1(keyword, { absolute } = {}) {
return getBaseMediaLink(`/keyword/${keyword.name}`, { absolute });
}
function ProductionCountryLink({
country,
children,
...otherProps
}) {
const link = useMemo(() => getKeywordLink(country), [country]);
return /* @__PURE__ */ jsx(BaseMediaLink, { ...otherProps, link, children: children ?? (country.display_name || country.name) });
}
function getKeywordLink(country, { absolute } = {}) {
return getBaseMediaLink(`/production-countries/${country.name}`, { absolute });
}
function WatchNowButton({
video,
variant = "outline",
color = "primary",
size = "w-full min-h-40 mt-14",
defaultLabel
}) {
const label = video.episode_num && !defaultLabel ? /* @__PURE__ */ jsxs("span", { className: "inline-flex gap-4", children: [
/* @__PURE__ */ jsx(Trans, { message: "Start watching" }),
/* @__PURE__ */ jsx(
CompactSeasonEpisode,
{
seasonNum: video.season_num,
episodeNum: video.episode_num
}
)
] }) : /* @__PURE__ */ jsx(Trans, { message: "Watch now" });
return /* @__PURE__ */ jsx(
Button,
{
to: getWatchLink(video),
elementType: Link,
startIcon: /* @__PURE__ */ jsx(MediaPlayIcon, {}),
color,
variant,
className: size,
children: label
}
);
}
function useIsStreamingMode() {
const { streaming } = useSettings();
return (streaming == null ? void 0 : streaming.prefer_full) || false;
}
function TitlePageAside({ data: { title, language }, className: className2 }) {
var _a, _b;
const isStreamingMode = useIsStreamingMode();
const { hasPermission } = useAuth();
return /* @__PURE__ */ jsxs(
TitlePageAsideLayout,
{
className: className2,
poster: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
/* @__PURE__ */ jsx(TitlePoster, { title, size: "w-full", srcSize: "lg" }),
hasPermission("titles.update") && /* @__PURE__ */ jsx(
IconButton,
{
elementType: Link,
to: `/admin/titles/${title.id}/edit`,
className: "absolute bottom-6 right-4",
color: "white",
children: /* @__PURE__ */ jsx(EditIcon, {})
}
)
] }),
children: [
isStreamingMode && title.primary_video && /* @__PURE__ */ jsx(WatchNowButton, { video: title.primary_video, variant: "flat" }),
/* @__PURE__ */ jsx(
WatchlistButton,
{
item: title,
variant: isStreamingMode ? "outline" : "flat"
}
),
/* @__PURE__ */ jsx(ShareButton$2, { title }),
/* @__PURE__ */ jsxs("dl", { className: "mt-14", children: [
language && /* @__PURE__ */ jsx(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Original language" }), children: /* @__PURE__ */ jsx(Trans, { message: language }) }),
title.original_title !== title.name && /* @__PURE__ */ jsx(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Original title" }), children: title.original_title }),
title.budget ? /* @__PURE__ */ jsx(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Budget" }), children: /* @__PURE__ */ jsx(FormattedCurrency, { value: title.budget, currency: "usd" }) }) : null,
title.revenue ? /* @__PURE__ */ jsx(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Revenue" }), children: /* @__PURE__ */ jsx(FormattedCurrency, { value: title.revenue, currency: "usd" }) }) : null,
((_a = title.production_countries) == null ? void 0 : _a.length) ? /* @__PURE__ */ jsx(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Production countries" }), children: /* @__PURE__ */ jsx("ul", { className: "mt-12 flex flex-wrap gap-8", children: title.production_countries.map((country) => /* @__PURE__ */ jsx(
"li",
{
className: "w-max rounded-full border px-10 py-4 text-xs",
children: /* @__PURE__ */ jsx(ProductionCountryLink, { country })
},
country.id
)) }) }) : null,
((_b = title.keywords) == null ? void 0 : _b.length) ? /* @__PURE__ */ jsx(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Keywords" }), children: /* @__PURE__ */ jsx("ul", { className: "mt-12 flex flex-wrap gap-8", children: title.keywords.map((keyword) => /* @__PURE__ */ jsx(
"li",
{
className: "w-max rounded-full border px-10 py-4 text-xs",
children: /* @__PURE__ */ jsx(KeywordLink, { keyword })
},
keyword.id
)) }) }) : null
] })
]
}
);
}
function ShareButton$2({ title }) {
const link = getTitleLink(title, { absolute: true });
return /* @__PURE__ */ jsx(ShareMenuTrigger, { link, children: /* @__PURE__ */ jsx(
Button,
{
variant: "outline",
color: "primary",
startIcon: /* @__PURE__ */ jsx(ShareIcon, {}),
className: "mt-14 min-h-40 w-full",
children: /* @__PURE__ */ jsx(Trans, { message: "Share" })
}
) });
}
function TitlePage() {
const query = useTitle("titlePage");
const content2 = query.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(PageContent$b, { data: query.data })
] }) : /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
return /* @__PURE__ */ jsx(SitePageLayout, { children: content2 });
}
function PageContent$b({ data }) {
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(TitlePageHeaderImage, { title: data.title }),
/* @__PURE__ */ jsx("div", { className: "container mx-auto mt-24 px-14 md:mt-40 md:px-24", children: /* @__PURE__ */ jsxs("div", { className: "items-start gap-54 md:flex", children: [
/* @__PURE__ */ jsx(TitlePageAside, { data, className: "max-lg:hidden" }),
/* @__PURE__ */ jsxs("div", { className: "flex-auto", children: [
/* @__PURE__ */ jsx(TitlePageHeader, { title: data.title }),
/* @__PURE__ */ jsx(TitlePageMainContent, { data })
] })
] }) })
] });
}
function SeasonPage() {
const query = useSeason("seasonPage");
const content2 = query.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(PageContent$a, { data: query.data })
] }) : /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
return /* @__PURE__ */ jsx(SitePageLayout, { children: content2 });
}
function PageContent$a({ data }) {
const { title, season } = data;
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(TitlePageHeaderImage, { title, season }),
/* @__PURE__ */ jsxs("div", { className: "container mx-auto mt-24 px-14 md:mt-40 md:px-24", children: [
/* @__PURE__ */ jsxs("div", { className: "mb-24 flex items-center gap-12", children: [
/* @__PURE__ */ jsx(TitlePoster, { size: "w-70", srcSize: "sm", title }),
/* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(TitleLink, { title, color: "primary", className: "text-xl" }),
/* @__PURE__ */ jsx("div", { className: "text-lg", children: /* @__PURE__ */ jsx(Trans, { message: "Episode list" }) })
] })
] }),
/* @__PURE__ */ jsx(SeasonList, { title }),
/* @__PURE__ */ jsx(EpisodeList$1, { data }),
/* @__PURE__ */ jsx(SeasonList, { title })
] })
] });
}
function SeasonList({ title }) {
const { season } = useParams();
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsxs("div", { className: "mb-4 text-base font-semibold", children: [
/* @__PURE__ */ jsx(Trans, { message: "Seasons" }),
":"
] }),
/* @__PURE__ */ jsx("div", { className: "mb-34 flex items-center gap-10", children: [...new Array(title.seasons_count).keys()].map((index) => {
const number = index + 1;
const isActive = season === `${number}`;
return /* @__PURE__ */ jsx(
SeasonLink,
{
title,
seasonNumber: number,
className: clsx(
"flex h-30 w-30 flex-shrink-0 items-center justify-center rounded border text-base",
isActive ? "pointer-events-none bg-primary text-white" : "text-primary"
),
children: number
},
number
);
}) })
] });
}
function EpisodeList$1({ data: { episodes, title } }) {
const query = useSeasonEpisodes(episodes);
return /* @__PURE__ */ jsxs("main", { children: [
query.items.map((episode) => /* @__PURE__ */ jsx(
EpisodeListItem,
{
episode,
title,
allowRating: true,
showPlayButton: true,
className: "mb-34"
},
episode.id
)),
/* @__PURE__ */ jsx(InfiniteScrollSentinel, { query })
] });
}
function EpisodePageHeader({ title, episode, showPoster }) {
const navigate = useNavigate();
const runtime = episode.runtime || title.runtime;
return /* @__PURE__ */ jsx(
TitlePageHeaderLayout,
{
poster: showPoster ? /* @__PURE__ */ jsx(TitlePoster, { title, size: "w-80", srcSize: "sm" }) : void 0,
name: episode.name,
description: /* @__PURE__ */ jsxs(BulletSeparatedItems, { className: "my-10 md:my-0", children: [
/* @__PURE__ */ jsx(
Trans,
{
message: "Aired :date",
values: {
date: /* @__PURE__ */ jsx(FormattedDate, { date: episode.release_date })
}
}
),
/* @__PURE__ */ jsx("span", { className: "uppercase", children: title.certification }),
runtime ? /* @__PURE__ */ jsx(FormattedDuration, { minutes: runtime, verbose: true }) : null
] }),
right: /* @__PURE__ */ jsx(InteractableRating, { title, episode }),
children: /* @__PURE__ */ jsxs(Breadcrumb, { isNavigation: true, children: [
/* @__PURE__ */ jsx(BreadcrumbItem, { onSelected: () => navigate(getTitleLink(title)), children: title.name }),
/* @__PURE__ */ jsx(
BreadcrumbItem,
{
onSelected: () => navigate(getSeasonLink(title, episode.season_number)),
children: /* @__PURE__ */ jsx(
Trans,
{
message: "Season :number",
values: { number: episode.season_number }
}
)
}
),
/* @__PURE__ */ jsx(BreadcrumbItem, { children: /* @__PURE__ */ jsx(
Trans,
{
message: "Episode :number",
values: { number: episode.episode_number }
}
) })
] })
}
);
}
function EpisodePage() {
const query = useEpisode("episodePage");
const content2 = query.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(PageContent$9, { data: query.data })
] }) : /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
return /* @__PURE__ */ jsx(SitePageLayout, { children: content2 });
}
function PageContent$9({ data }) {
const { episode, title } = data;
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(TitlePageHeaderImage, { title, episode }),
/* @__PURE__ */ jsx("div", { className: "container mx-auto mt-12 px-14 md:mt-40 md:px-24", children: /* @__PURE__ */ jsxs("div", { className: "items-start gap-54 md:flex", children: [
/* @__PURE__ */ jsx(Aside, { title, episode }),
/* @__PURE__ */ jsxs("div", { className: "flex-auto", children: [
/* @__PURE__ */ jsx(EpisodePageHeader, { title, episode }),
/* @__PURE__ */ jsx(MainContent, { data })
] })
] }) })
] });
}
function MainContent({ data }) {
var _a;
const { episode, title, credits } = data;
const { title_page } = useSettings();
return /* @__PURE__ */ jsxs("main", { className: "@container", children: [
((_a = title.genres) == null ? void 0 : _a.length) ? /* @__PURE__ */ jsx(ChipList, { children: title.genres.map((genre) => /* @__PURE__ */ jsx(
Chip,
{
className: "capitalize",
elementType: Link,
to: getGenreLink(genre),
children: genre.display_name || genre.name
},
genre.id
)) }) : null,
/* @__PURE__ */ jsx(
TruncatedDescription,
{
className: "mt-16",
description: episode.description
}
),
/* @__PURE__ */ jsx(CompactCredits, { credits }),
title_page == null ? void 0 : title_page.sections.map((name) => /* @__PURE__ */ jsx(EpisodePageSection, { name, data }, name))
] });
}
function EpisodePageSection({ name, data }) {
var _a;
switch (name) {
case "videos":
return /* @__PURE__ */ jsx(TitlePageVideoGrid, { title: data.title, episode: data.episode });
case "cast":
return /* @__PURE__ */ jsx(TitlePageCast, { credits: (_a = data.credits) == null ? void 0 : _a.actors });
case "related":
return /* @__PURE__ */ jsx(RelatedTitlesPanel, { title: data.title });
case "episodes":
return /* @__PURE__ */ jsx(
TitlePageEpisodeGrid,
{
data,
label: /* @__PURE__ */ jsx(Trans, { message: "Other episodes" })
}
);
default:
return null;
}
}
function Aside({ title, episode }) {
const isStreamingMode = useIsStreamingMode();
return /* @__PURE__ */ jsxs(
TitlePageAsideLayout,
{
className: "max-md:hidden",
poster: /* @__PURE__ */ jsx(TitlePoster, { title, size: "w-full", srcSize: "lg" }),
children: [
isStreamingMode && episode.primary_video && /* @__PURE__ */ jsx(
WatchNowButton,
{
video: episode.primary_video,
variant: "flat",
defaultLabel: true
}
),
/* @__PURE__ */ jsx(
WatchlistButton,
{
item: title,
variant: isStreamingMode ? "outline" : "flat"
}
)
]
}
);
}
function useWatchPageVideo() {
const { videoId } = useParams();
return useQuery({
queryKey: ["video", "watch-page", videoId],
queryFn: () => fetchVideo(videoId),
placeholderData: keepPreviousData,
initialData: () => {
var _a;
const data = (_a = getBootstrapData().loaders) == null ? void 0 : _a.watchPage;
if (data && `${data.video.id}` === videoId) {
return data;
}
}
});
}
function fetchVideo(videoId) {
return apiClient.get(`watch/${videoId}`).then((response) => response.data);
}
function commentsQueryKey(commentable, params = {}) {
return ["comment", `${commentable.id}-${commentable.model_type}`, params];
}
function useComments(commentable, params = {}) {
return useInfiniteData({
queryKey: commentsQueryKey(commentable, params),
endpoint: "commentable/comments",
//paginate: 'cursor',
queryParams: {
commentable_type: commentable.model_type,
commentable_id: commentable.id,
...params
}
});
}
function useCreateComment() {
const queryClient2 = useQueryClient();
return useMutation({
mutationFn: (props) => createComment(props),
onSuccess: async (response, props) => {
await queryClient2.invalidateQueries({
queryKey: [
"comment",
`${props.commentable.id}-${props.commentable.model_type}`
]
});
toast(message("Comment posted"));
},
onError: (err) => showHttpErrorToast(err)
});
}
function createComment({
commentable,
content: content2,
inReplyTo,
...other
}) {
const payload = {
commentable_id: commentable.id,
commentable_type: commentable.model_type,
content: content2,
inReplyTo,
...other
};
return apiClient.post("comment", payload).then((r2) => r2.data);
}
function NewCommentForm({
commentable,
inReplyTo,
onSuccess,
className: className2,
autoFocus,
payload,
...props
}) {
const { trans } = useTrans();
const { user } = useAuth();
const createComment2 = useCreateComment();
const inputRef = useObjectRef(props.inputRef);
const [inputIsExpanded, setInputIsExpanded] = useState(false);
const [inputValue, setInputValue] = useState("");
const clearInput = () => {
setInputIsExpanded(false);
if (inputRef.current) {
inputRef.current.blur();
setInputValue("");
}
};
return /* @__PURE__ */ jsxs(
"form",
{
className: clsx("py-6 flex gap-24", className2),
onSubmit: (e) => {
e.preventDefault();
if (inputValue && !createComment2.isPending) {
createComment2.mutate(
{
...payload,
commentable,
content: inputValue,
inReplyTo
},
{
onSuccess: () => {
clearInput();
onSuccess == null ? void 0 : onSuccess();
}
}
);
}
},
children: [
/* @__PURE__ */ jsx(Avatar, { size: "xl", circle: true, src: user == null ? void 0 : user.avatar, label: user == null ? void 0 : user.display_name }),
/* @__PURE__ */ jsxs("div", { className: "flex-auto", children: [
/* @__PURE__ */ jsx("div", { className: "text-xs text-muted mb-10", children: /* @__PURE__ */ jsx(
Trans,
{
message: "Comment as :name",
values: {
name: /* @__PURE__ */ jsx("span", { className: "font-medium text", children: user == null ? void 0 : user.display_name })
}
}
) }),
/* @__PURE__ */ jsx(
TextField,
{
inputRef,
autoFocus,
inputElementType: "textarea",
inputClassName: "resize-none",
value: inputValue,
onChange: (e) => setInputValue(e.target.value),
onFocus: () => setInputIsExpanded(true),
onBlur: () => {
if (!inputValue) {
setInputIsExpanded(false);
}
},
minLength: 3,
rows: inputIsExpanded ? 3 : 1,
placeholder: inReplyTo ? trans(message("Write a reply")) : trans(message("Leave a comment"))
}
),
inputIsExpanded && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-12 justify-end mt-12", children: [
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => clearInput(), children: /* @__PURE__ */ jsx(Trans, { message: "Cancel" }) }),
/* @__PURE__ */ jsx(
Button,
{
variant: "outline",
color: "primary",
type: "submit",
disabled: createComment2.isPending || inputValue.length < 3,
children: /* @__PURE__ */ jsx(Trans, { message: "Comment" })
}
)
] })
] })
]
}
);
}
function useStoreVote(model) {
return useMutation({
mutationFn: (payload) => changeVote(model, payload),
onSuccess: (response) => {
},
onError: (err) => showHttpErrorToast(err)
});
}
function changeVote(model, payload) {
return apiClient.post("vote", {
vote_type: payload.voteType,
model_id: model.id,
model_type: model.model_type
}).then((r2) => r2.data);
}
function ThumbButtons({ model, className: className2, showUpvotesOnly }) {
const changeVote2 = useStoreVote(model);
const [upvotes, setUpvotes] = useState(model.upvotes || 0);
const [downvotes, setDownvotes] = useState(model.downvotes || 0);
const [currentVote, setCurrentVote] = useState(model.current_vote);
const syncLocalState = (model2) => {
setUpvotes(model2.upvotes);
setDownvotes(model2.downvotes);
setCurrentVote(model2.current_vote);
};
return /* @__PURE__ */ jsxs("div", { className: clsx(className2, "whitespace-nowrap"), children: [
/* @__PURE__ */ jsxs(
Button,
{
className: "gap-6",
sizeClassName: "px-8 py-4",
color: currentVote === "upvote" ? "primary" : void 0,
disabled: changeVote2.isPending,
"aria-label": "Upvote",
onClick: () => {
changeVote2.mutate(
{ voteType: "upvote" },
{
onSuccess: (response) => syncLocalState(response.model)
}
);
},
children: [
/* @__PURE__ */ jsx(ThumbUpIcon, {}),
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(FormattedNumber, { value: upvotes }) })
]
}
),
!showUpvotesOnly && /* @__PURE__ */ jsxs(
Button,
{
className: "gap-6",
sizeClassName: "px-8 py-4",
color: currentVote === "downvote" ? "primary" : void 0,
disabled: changeVote2.isPending,
"aria-label": "Downvote",
onClick: () => {
changeVote2.mutate(
{ voteType: "downvote" },
{
onSuccess: (response) => syncLocalState(response.model)
}
);
},
children: [
/* @__PURE__ */ jsx(ThumbDownIcon, {}),
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(FormattedNumber, { value: downvotes }) })
]
}
)
] });
}
function CommentListItem$1({
comment,
commentable,
// user can delete comment if they have created it, or they have relevant permissions on commentable
canDelete
}) {
const isMobile = useIsMobileMediaQuery();
const { user, hasPermission } = useAuth();
const [replyFormVisible, setReplyFormVisible] = useState(false);
const showReplyButton = user != null && !comment.deleted && !isMobile && comment.depth < 5 && hasPermission("comments.create");
return /* @__PURE__ */ jsxs(
"div",
{
style: { paddingLeft: `${comment.depth * 20}px` },
onClick: () => {
if (isMobile) {
setReplyFormVisible(!replyFormVisible);
}
},
children: [
/* @__PURE__ */ jsxs("div", { className: "group flex min-h-70 items-start gap-24 py-18", children: [
/* @__PURE__ */ jsx(UserAvatar, { user: comment.user, size: isMobile ? "lg" : "xl", circle: true }),
/* @__PURE__ */ jsxs("div", { className: "flex-auto text-sm", children: [
/* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-center gap-8", children: [
comment.user && /* @__PURE__ */ jsx(UserDisplayName, { user: comment.user }),
/* @__PURE__ */ jsx("time", { className: "text-xs text-muted", children: /* @__PURE__ */ jsx(FormattedRelativeTime, { date: comment.created_at }) }),
comment.position ? /* @__PURE__ */ jsx(Position, { commentable, position: comment.position }) : null
] }),
/* @__PURE__ */ jsx("div", { className: "whitespace-pre-line", children: comment.deleted ? /* @__PURE__ */ jsx("span", { className: "italic text-muted", children: /* @__PURE__ */ jsx(Trans, { message: "[COMMENT DELETED]" }) }) : comment.content }),
!comment.deleted && /* @__PURE__ */ jsxs("div", { className: "-ml-8 mt-10 flex items-center gap-8", children: [
showReplyButton && /* @__PURE__ */ jsx(
Button,
{
sizeClassName: "text-sm px-8 py-4",
startIcon: /* @__PURE__ */ jsx(ReplyIcon, {}),
onClick: () => setReplyFormVisible(!replyFormVisible),
children: /* @__PURE__ */ jsx(Trans, { message: "Reply" })
}
),
/* @__PURE__ */ jsx(ThumbButtons, { model: comment, showUpvotesOnly: true }),
/* @__PURE__ */ jsx(
CommentOptionsTrigger,
{
comment,
canDelete,
user
}
)
] })
] })
] }),
replyFormVisible ? /* @__PURE__ */ jsx(
NewCommentForm,
{
className: !(comment == null ? void 0 : comment.depth) ? "pl-20" : void 0,
commentable,
inReplyTo: comment,
autoFocus: true,
onSuccess: () => {
setReplyFormVisible(false);
}
}
) : null
]
}
);
}
const Position = memo(({ commentable, position }) => {
if (!commentable.duration)
return null;
const seconds = position / 100 * (commentable.duration / 1e3);
return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted", children: /* @__PURE__ */ jsx(
Trans,
{
message: "at :position",
values: {
position: /* @__PURE__ */ jsx(FormattedDuration, { seconds })
}
}
) });
});
function CommentOptionsTrigger({
comment,
canDelete,
user
}) {
const deleteComments = useDeleteComments();
const reportComment = useSubmitReport(comment);
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const showDeleteButton = (comment.user_id === (user == null ? void 0 : user.id) || canDelete) && !comment.deleted;
const handleReport = () => {
reportComment.mutate({});
};
const handleDelete = (isConfirmed) => {
setIsDeleteDialogOpen(false);
if (isConfirmed) {
deleteComments.mutate(
{ commentIds: [comment.id] },
{
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["comment"] });
}
}
);
}
};
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsxs(MenuTrigger, { children: [
/* @__PURE__ */ jsx(Button, { startIcon: /* @__PURE__ */ jsx(MoreVertIcon, {}), sizeClassName: "text-sm px-8 py-4", children: /* @__PURE__ */ jsx(Trans, { message: "More" }) }),
/* @__PURE__ */ jsxs(Menu, { children: [
/* @__PURE__ */ jsx(Item, { value: "report", onSelected: () => handleReport(), children: /* @__PURE__ */ jsx(Trans, { message: "Report comment" }) }),
showDeleteButton && /* @__PURE__ */ jsx(
Item,
{
value: "delete",
onSelected: () => setIsDeleteDialogOpen(true),
children: /* @__PURE__ */ jsx(Trans, { message: "Delete" })
}
)
] })
] }),
/* @__PURE__ */ jsx(
DialogTrigger,
{
type: "modal",
isOpen: isDeleteDialogOpen,
onClose: (isConfirmed) => handleDelete(isConfirmed),
children: /* @__PURE__ */ jsx(
ConfirmationDialog,
{
isDanger: true,
title: /* @__PURE__ */ jsx(Trans, { message: "Delete comment?" }),
body: /* @__PURE__ */ jsx(Trans, { message: "Are you sure you want to delete this comment?" }),
confirm: /* @__PURE__ */ jsx(Trans, { message: "Delete" })
}
)
}
)
] });
}
function UserDisplayName({ user }) {
const { auth } = useContext(SiteConfigContext);
if (auth.getUserProfileLink) {
return /* @__PURE__ */ jsx(
Link,
{
to: auth.getUserProfileLink(user),
className: "text-base font-medium hover:underline",
children: user.display_name
}
);
}
return /* @__PURE__ */ jsx("div", { className: "text-base font-medium", children: user.display_name });
}
const accountRequiredMessage = message(
"Please <l>login</l> or <r>create account</r> to comment"
);
function CommentList({
className: className2,
commentable,
canDeleteAllComments = false,
children,
perPage = 25
}) {
const { items, totalItems, ...query } = useComments(commentable, { perPage });
if (query.isError) {
return null;
}
return /* @__PURE__ */ jsxs("div", { className: className2, children: [
/* @__PURE__ */ jsxs("div", { className: "mb-8 pb-8 border-b flex items-center gap-8", children: [
/* @__PURE__ */ jsx(CommentIcon, { size: "sm", className: "text-muted" }),
query.isInitialLoading ? /* @__PURE__ */ jsx(Trans, { message: "Loading comments..." }) : /* @__PURE__ */ jsx(
Trans,
{
message: ":count comments",
values: { count: /* @__PURE__ */ jsx(FormattedNumber, { value: totalItems || 0 }) }
}
)
] }),
children,
/* @__PURE__ */ jsx(AccountRequiredCard, { message: accountRequiredMessage }),
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: query.isInitialLoading ? /* @__PURE__ */ jsx(CommentSkeletons, { count: 4 }) : /* @__PURE__ */ jsx(
CommentListItems,
{
comments: items,
canDeleteAllComments,
commentable
}
) }),
/* @__PURE__ */ jsx(InfiniteScrollSentinel, { query, variant: "loadMore" })
] });
}
function CommentListItems({
comments,
commentable,
canDeleteAllComments
}) {
if (!comments.length) {
return /* @__PURE__ */ jsx(
IllustratedMessage,
{
className: "mt-24",
size: "sm",
title: /* @__PURE__ */ jsx(Trans, { message: "Seems a little quiet over here" }),
description: /* @__PURE__ */ jsx(Trans, { message: "Be the first to comment" })
}
);
}
return /* @__PURE__ */ jsx(m.div, { ...opacityAnimation, children: comments.map((comment) => /* @__PURE__ */ jsx(
CommentListItem$1,
{
comment,
commentable,
canDelete: canDeleteAllComments
},
comment.id
)) }, "comments");
}
function CommentSkeletons({ count }) {
return /* @__PURE__ */ jsx(m.div, { ...opacityAnimation, children: [...new Array(count).keys()].map((index) => /* @__PURE__ */ jsxs(
"div",
{
className: "flex items-start gap-24 py-18 min-h-70 group",
children: [
/* @__PURE__ */ jsx(Skeleton, { variant: "avatar", radius: "rounded-full", size: "w-60 h-60" }),
/* @__PURE__ */ jsxs("div", { className: "text-sm flex-auto", children: [
/* @__PURE__ */ jsx(Skeleton, { className: "text-base max-w-184 mb-4" }),
/* @__PURE__ */ jsx(Skeleton, { className: "text-sm" }),
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-8 mt-10", children: [
/* @__PURE__ */ jsx(Skeleton, { className: "text-sm max-w-70" }),
/* @__PURE__ */ jsx(Skeleton, { className: "text-sm max-w-40" }),
/* @__PURE__ */ jsx(Skeleton, { className: "text-sm max-w-60" })
] })
] })
]
},
index
)) }, "loading-skeleton");
}
function WatchPageTitleDetails() {
var _a;
const { data } = useWatchPageVideo();
const isStreamingMode = useIsStreamingMode();
const content2 = !data ? /* @__PURE__ */ jsx(
Layout,
{
poster: /* @__PURE__ */ jsx(Skeleton, { variant: "rect", size: "w-132 aspect-poster" }),
titleLink: /* @__PURE__ */ jsx(Skeleton, { className: "max-w-144" }),
videoName: /* @__PURE__ */ jsx(Skeleton, { className: "max-w-240" }),
description: /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(Skeleton, {}),
/* @__PURE__ */ jsx(Skeleton, {})
] }),
rate: /* @__PURE__ */ jsxs("div", { className: "flex h-32 items-center gap-2", children: [
/* @__PURE__ */ jsx(Skeleton, { variant: "rect", size: "w-56 h-24", className: "mr-10" }),
/* @__PURE__ */ jsx(Skeleton, { variant: "rect", size: "w-56 h-24" })
] })
},
"skeleton"
) : /* @__PURE__ */ jsx(
Layout,
{
poster: /* @__PURE__ */ jsx(
TitlePoster,
{
size: "w-132",
srcSize: "md",
title: data.title,
showPlayButton: true,
className: "max-md:hidden"
}
),
titleLink: /* @__PURE__ */ jsx(TitleLink, { title: data.title }),
videoName: !isStreamingMode ? data.video.name : void 0,
episodeName: data.episode ? /* @__PURE__ */ jsxs(EpisodeLink, { title: data.title, episode: data.episode, children: [
data.episode.name,
" (",
/* @__PURE__ */ jsx(CompactSeasonEpisode, { episode: data.episode }),
")"
] }) : void 0,
description: ((_a = data.episode) == null ? void 0 : _a.description) || data.title.description,
rate: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
/* @__PURE__ */ jsx(ThumbButtons, { model: data.video, className: "mr-auto" }),
/* @__PURE__ */ jsx(ReportButton, { video: data.video }),
/* @__PURE__ */ jsx(ShareButton$1, { video: data.video })
] })
},
"loaded"
);
return /* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: content2 });
}
function ShareButton$1({ video }) {
const link = getWatchLink(video, { absolute: true });
return /* @__PURE__ */ jsx(ShareMenuTrigger, { link, children: /* @__PURE__ */ jsx(Tooltip, { label: /* @__PURE__ */ jsx(Trans, { message: "Share" }), children: /* @__PURE__ */ jsx(IconButton, { children: /* @__PURE__ */ jsx(ShareIcon, {}) }) }) });
}
function ReportButton({ video }) {
const report = useSubmitReport(video);
const deleteReport2 = useDeleteReport(video);
const [isReported, setIsReported] = useState(video.current_user_reported);
return /* @__PURE__ */ jsx(Tooltip, { label: /* @__PURE__ */ jsx(Trans, { message: "Report" }), children: /* @__PURE__ */ jsx(
IconButton,
{
onClick: () => {
if (isReported) {
deleteReport2.mutate();
} else {
report.mutate({});
}
setIsReported(!isReported);
},
children: /* @__PURE__ */ jsx(FlagIcon, {})
}
) });
}
function Layout({
poster,
titleLink,
videoName,
episodeName,
description,
rate
}) {
return /* @__PURE__ */ jsxs(
m.div,
{
className: "flex items-start gap-16 overflow-hidden rounded pr-6",
...opacityAnimation,
children: [
poster,
/* @__PURE__ */ jsxs("div", { className: "flex-auto py-6", children: [
/* @__PURE__ */ jsx("h1", { className: "mb-6 text-2xl font-medium", children: titleLink }),
episodeName && /* @__PURE__ */ jsx("div", { className: "text-base font-medium", children: episodeName }),
videoName && /* @__PURE__ */ jsx("div", { className: "text-base font-medium", children: videoName }),
/* @__PURE__ */ jsx("div", { className: "my-12", children: rate }),
description && /* @__PURE__ */ jsx("p", { className: "max-w-780 text-sm text-muted", children: description })
] })
]
}
);
}
function WatchPageAside() {
const { data } = useWatchPageVideo();
const content2 = !data ? /* @__PURE__ */ jsxs(m.div, { ...opacityAnimation, children: [
/* @__PURE__ */ jsx(VideoGridItemSkeleton, { className: "mb-34" }),
/* @__PURE__ */ jsx(VideoGridItemSkeleton, { className: "mb-34" }),
/* @__PURE__ */ jsx(VideoGridItemSkeleton, { className: "mb-34" })
] }, "skeleton") : /* @__PURE__ */ jsx(m.div, { ...opacityAnimation, children: data.related_videos.map((video) => /* @__PURE__ */ jsx(RelatedVideo, { video, activeVideo: data.video }, video.id)) }, "loaded");
return /* @__PURE__ */ jsxs("aside", { className: "w-350 flex-shrink-0 max-lg:mt-54", children: [
/* @__PURE__ */ jsx(
SiteSectionHeading,
{
fontWeight: "font-medium",
fontSize: "text-2xl",
margin: "mb-28",
children: /* @__PURE__ */ jsx(Header, { video: data == null ? void 0 : data.video })
}
),
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: content2 })
] });
}
function Header({ video }) {
const isStreamingMode = useIsStreamingMode();
if (!video) {
return /* @__PURE__ */ jsx("div", { className: "h-32" });
}
return isStreamingMode ? /* @__PURE__ */ jsx(Trans, { message: "Related movies & series" }) : /* @__PURE__ */ jsx(Trans, { message: "Related videos" });
}
function RelatedVideo({ video, activeVideo }) {
const isStreamingMode = useIsStreamingMode();
let name = video.name;
if (isStreamingMode) {
if (video.episode) {
name = /* @__PURE__ */ jsxs("span", { children: [
video.episode.name,
" (",
/* @__PURE__ */ jsx(CompactSeasonEpisode, { episode: video.episode }),
")"
] });
} else {
name = video.title.name;
}
}
return /* @__PURE__ */ jsx(
VideoGridItem,
{
video,
title: video.title,
episode: video.episode,
forceTitleBackdrop: isStreamingMode,
className: clsx(
"mb-24 text-sm",
activeVideo.id === video.id && "text-primary"
),
showCategory: !isStreamingMode,
name
}
);
}
const className = "flex items-center flex-wrap gap-14";
function WatchPageAlternativeVideos({ data }) {
const navigate = useNavigate();
const { streaming } = useSettings();
const title = data == null ? void 0 : data.title;
const episode = data == null ? void 0 : data.episode;
const video = data == null ? void 0 : data.video;
const showEpisodeSelector = title && episode && video && (video.type === "embed" || video.type === "external");
if (!showEpisodeSelector && !streaming.show_video_selector) {
return null;
}
return /* @__PURE__ */ jsxs("div", { className: "mt-14 flex items-start justify-between gap-48", children: [
streaming.show_video_selector && /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
VideoDropdown,
{
className: "lg:hidden",
videos: (data == null ? void 0 : data.alternative_videos) || []
}
),
/* @__PURE__ */ jsx("div", { className: "max-lg:hidden", children: /* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: data ? /* @__PURE__ */ jsx(VideoList, { videos: data.alternative_videos }) : /* @__PURE__ */ jsx(Skeletons, {}) }) })
] }),
showEpisodeSelector && /* @__PURE__ */ jsx(
EpisodeSelector,
{
title,
currentEpisode: episode,
onSelected: (episode2) => {
navigate(getWatchLink(episode2.primary_video));
},
trigger: /* @__PURE__ */ jsx(
Button,
{
variant: "outline",
className: "min-h-40",
startIcon: /* @__PURE__ */ jsx(MediaEpisodesIcon, {}),
children: /* @__PURE__ */ jsx(Trans, { message: "Episodes" })
}
)
}
)
] });
}
function VideoDropdown({ videos, className: className2 }) {
const navigate = useNavigate();
return /* @__PURE__ */ jsxs(MenuTrigger, { children: [
/* @__PURE__ */ jsx(
Button,
{
variant: "outline",
className: clsx("min-h-40", className2),
startIcon: /* @__PURE__ */ jsx(MediaPlayIcon, {}),
children: /* @__PURE__ */ jsx(Trans, { message: "Other sources" })
}
),
/* @__PURE__ */ jsx(Menu, { children: videos.map((video) => /* @__PURE__ */ jsx(
Item,
{
value: video.id,
startIcon: /* @__PURE__ */ jsx(MediaPlayIcon, {}),
endSection: /* @__PURE__ */ jsx(QualityBadge, { video }),
onSelected: () => navigate(getWatchLink(video)),
children: video.name
},
video.id
)) })
] });
}
function VideoList({ videos }) {
const { videoId } = useParams();
if (videos.length < 2) {
return null;
}
return /* @__PURE__ */ jsx(
m.div,
{
className,
...opacityAnimation,
children: videos.map((video) => /* @__PURE__ */ jsxs(
Button,
{
elementType: Link,
to: getWatchLink(video),
variant: "outline",
color: videoId === `${video.id}` ? "primary" : "chip",
startIcon: /* @__PURE__ */ jsx(MediaPlayIcon, { "aria-hidden": true }),
className: "min-h-40 gap-10",
children: [
video.name,
/* @__PURE__ */ jsx(QualityBadge, { video })
]
},
video.id
))
},
"alternative-sources"
);
}
function QualityBadge({ video }) {
if (!video.quality || video.quality === "default") {
return null;
}
return /* @__PURE__ */ jsx("span", { className: "rounded border px-6 text-xs font-bold uppercase", children: video.quality });
}
function Skeletons() {
return /* @__PURE__ */ jsxs(
m.div,
{
className: clsx(className, "h-40"),
...opacityAnimation,
children: [
/* @__PURE__ */ jsx(Skeleton, { variant: "rect", size: "h-full w-[116px]" }),
/* @__PURE__ */ jsx(Skeleton, { variant: "rect", size: "h-full w-[116px]" }),
/* @__PURE__ */ jsx(Skeleton, { variant: "rect", size: "h-full w-[116px]" }),
/* @__PURE__ */ jsx(Skeleton, { variant: "rect", size: "h-full w-[116px]" }),
/* @__PURE__ */ jsx(Skeleton, { variant: "rect", size: "h-full w-[116px]" })
]
},
"skeletons"
);
}
function WatchPage() {
const darkThemeVars = useDarkThemeVariables();
useScrollToTop();
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(MainNavbar, {}),
/* @__PURE__ */ jsx("div", { style: darkThemeVars, className: "dark min-h-screen bg text", children: /* @__PURE__ */ jsxs("div", { className: "container mx-auto p-14 md:p-24", children: [
/* @__PURE__ */ jsx(Content, {}),
/* @__PURE__ */ jsx(Footer, { className: "mt-48" })
] }) })
] });
}
function Content() {
const { titles, comments } = useSettings();
const { isLoggedIn, hasPermission } = useAuth();
const query = useWatchPageVideo();
const { data, isLoading } = query;
const title = data == null ? void 0 : data.title;
const episode = data == null ? void 0 : data.episode;
const video = data == null ? void 0 : data.video;
let commentable = video;
if (!(comments == null ? void 0 : comments.per_video)) {
commentable = episode || title;
}
const shouldShowComments = title && video && titles.enable_comments && hasPermission("comments.view");
if (data || isLoading) {
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(VideoWrapper, { data }),
/* @__PURE__ */ jsx(WatchPageAlternativeVideos, { data }),
/* @__PURE__ */ jsx(AdHost, { slot: "watch_top", className: "pt-48" }),
/* @__PURE__ */ jsxs("section", { className: "mt-42 items-start gap-56 lg:flex", children: [
/* @__PURE__ */ jsxs("div", { className: "flex-auto", children: [
/* @__PURE__ */ jsx(WatchPageTitleDetails, {}),
shouldShowComments && /* @__PURE__ */ jsx(
CommentList,
{
commentable,
className: "mt-44",
perPage: 20,
children: isLoggedIn && hasPermission("comments.create") && /* @__PURE__ */ jsx(
NewCommentForm,
{
commentable,
className: "mb-14 mt-24"
}
)
}
)
] }),
/* @__PURE__ */ jsx(WatchPageAside, {})
] })
] }, (video == null ? void 0 : video.id) || "loading");
}
return /* @__PURE__ */ jsx(PageErrorMessage, {});
}
function VideoWrapper({ data }) {
const isStreamingMode = useIsStreamingMode();
const { hasPermission } = useAuth();
const [isVisible, setIsVisible] = useState(false);
useLayoutEffect(() => {
setIsVisible(true);
}, []);
return /* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: (data == null ? void 0 : data.video) && isVisible ? /* @__PURE__ */ jsx(m.div, { ...opacityAnimation, children: hasPermission("videos.play") ? /* @__PURE__ */ jsx(
SiteVideoPlayer,
{
title: data.title,
episode: data.episode,
video: data.video,
relatedVideos: data.related_videos,
autoPlay: true,
logPlays: true,
showEpisodeSelector: isStreamingMode
}
) : /* @__PURE__ */ jsx(UpgradeMessage, { video: data.video }) }, "player") : /* @__PURE__ */ jsx(m.div, { className: "relative", ...opacityAnimation, children: /* @__PURE__ */ jsx(VideoPlayerSkeleton, { animate: true }) }, "skeleton") });
}
function UpgradeMessage({ video }) {
return /* @__PURE__ */ jsxs("div", { className: "relative flex aspect-video items-center justify-center bg-alt", children: [
/* @__PURE__ */ jsx("div", { className: "blur", children: /* @__PURE__ */ jsx(VideoThumbnail, { video }) }),
/* @__PURE__ */ jsxs("div", { className: "absolute h-max w-max max-w-full rounded-lg bg-black/60 p-24 text-lg font-medium", children: [
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Trans, { message: "Your current plan does not allow watching videos. Upgrade to unlock this feature." }) }),
/* @__PURE__ */ jsx("div", { className: "mt-14 text-center", children: /* @__PURE__ */ jsx(
Button,
{
variant: "flat",
color: "primary",
elementType: Link,
to: "/pricing",
children: /* @__PURE__ */ jsx(Trans, { message: "Upgrade" })
}
) })
] })
] });
}
function TitleVideosPage() {
const query = useTitle("titlePage");
const content2 = query.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(PageContent$8, { title: query.data.title }),
";"
] }) : /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
return /* @__PURE__ */ jsx(SitePageLayout, { children: content2 });
}
function PageContent$8({ title }) {
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(TitlePageHeaderImage, { title }),
/* @__PURE__ */ jsxs("div", { className: "container mx-auto mt-24 px-14 md:mt-40 md:px-24", children: [
/* @__PURE__ */ jsx(TitlePageHeader, { title, showPoster: true }),
/* @__PURE__ */ jsx(
VideoGrid,
{
videos: title.videos,
title,
count: 24,
heading: /* @__PURE__ */ jsx(SiteSectionHeading, { children: /* @__PURE__ */ jsx(Trans, { message: "Video gallery" }) })
}
)
] })
] });
}
function TitleImagesPage() {
const query = useTitle("titlePage");
const content2 = query.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(PageContent$7, { title: query.data.title }),
";"
] }) : /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
return /* @__PURE__ */ jsx(SitePageLayout, { children: content2 });
}
function PageContent$7({ title }) {
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(TitlePageHeaderImage, { title }),
/* @__PURE__ */ jsxs("div", { className: "container mx-auto mt-24 px-14 md:mt-40 md:px-24", children: [
/* @__PURE__ */ jsx(TitlePageHeader, { title, showPoster: true }),
/* @__PURE__ */ jsx(
TitlePageImageGrid,
{
images: title.images,
srcSize: "lg",
count: 24,
heading: /* @__PURE__ */ jsx(SiteSectionHeading, { children: /* @__PURE__ */ jsx(Trans, { message: "Image gallery" }) })
}
)
] })
] });
}
function PersonPageAside({ data: { person, total_credits_count } }) {
const { hasPermission } = useAuth();
const age = /* @__PURE__ */ jsx(
Trans,
{
message: ":count years old",
values: { count: /* @__PURE__ */ jsx(PersonAge, { person }) }
}
);
return /* @__PURE__ */ jsx(
TitlePageAsideLayout,
{
className: "max-md:flex",
poster: /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
/* @__PURE__ */ jsx(PersonPoster, { person, size: "w-140 md:w-full", srcSize: "lg" }),
hasPermission("titles.update") && /* @__PURE__ */ jsx(
IconButton,
{
elementType: Link,
to: `/admin/people/${person.id}/edit`,
className: "absolute bottom-6 right-4",
color: "white",
children: /* @__PURE__ */ jsx(EditIcon, {})
}
)
] }),
/* @__PURE__ */ jsx(ShareButton, { person })
] }),
children: /* @__PURE__ */ jsxs("dl", { className: "mt-12 md:mt-24", children: [
person.known_for && /* @__PURE__ */ jsx(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Known for" }), children: /* @__PURE__ */ jsx(Trans, { message: person.known_for }) }),
person.gender && /* @__PURE__ */ jsx(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Gender" }), children: /* @__PURE__ */ jsx("span", { className: "capitalize", children: /* @__PURE__ */ jsx(Trans, { message: person.gender }) }) }),
total_credits_count ? /* @__PURE__ */ jsx(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Known credits" }), children: total_credits_count }) : null,
person.birth_date ? /* @__PURE__ */ jsxs(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Born" }), children: [
/* @__PURE__ */ jsx(FormattedDate, { date: person.birth_date }),
" ",
!person.death_date && age
] }) : null,
person.birth_place ? /* @__PURE__ */ jsx(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Birthplace" }), children: person.birth_place }) : null,
person.death_date ? /* @__PURE__ */ jsxs(DetailItem, { label: /* @__PURE__ */ jsx(Trans, { message: "Died" }), children: [
/* @__PURE__ */ jsx(FormattedDate, { date: person.death_date }),
" (",
age,
")"
] }) : null
] })
}
);
}
function ShareButton({ person }) {
const link = getPersonLink(person, { absolute: true });
return /* @__PURE__ */ jsx(ShareMenuTrigger, { link, children: /* @__PURE__ */ jsx(
Button,
{
variant: "outline",
color: "primary",
startIcon: /* @__PURE__ */ jsx(ShareIcon, {}),
className: "mt-14 md:min-h-40 md:w-full",
children: /* @__PURE__ */ jsx(Trans, { message: "Share" })
}
) });
}
function useFullPersonCreditsForTitle({ person, credit, department }, options) {
return useQuery({
queryKey: [
"people",
`${person.id}`,
"full-credits",
`${credit.id}`,
`${department}`
],
queryFn: () => fetchCredits(person.id, credit.id, department),
enabled: options.enabled
});
}
function fetchCredits(personId, titleId, department) {
return apiClient.get(
`people/${personId}/full-credits/${titleId}/${department}`
).then((response) => response.data);
}
function CharacterOrJob({ credit, className: className2 }) {
var _a, _b, _c, _d;
return /* @__PURE__ */ jsx("div", { className: className2, children: ((_a = credit.pivot) == null ? void 0 : _a.department) === "actors" ? ((_b = credit.pivot) == null ? void 0 : _b.character) ?? /* @__PURE__ */ jsx(Trans, { message: "Unknown" }) : /* @__PURE__ */ jsx("span", { className: "capitalize", children: ((_c = credit.pivot) == null ? void 0 : _c.job) ? /* @__PURE__ */ jsx(Trans, { message: (_d = credit.pivot) == null ? void 0 : _d.job }) : /* @__PURE__ */ jsx(Trans, { message: "Unknown" }) }) });
}
function PersonPageCredits({ data: { credits, person } }) {
return /* @__PURE__ */ jsxs("div", { className: "mt-34", children: [
/* @__PURE__ */ jsx(SiteSectionHeading, { fontSize: "text-xl", children: /* @__PURE__ */ jsx(Trans, { message: "Credits" }) }),
/* @__PURE__ */ jsx(Accordion, { mode: "multiple", defaultExpandedValues: [0], isLazy: true, children: Object.entries(credits).map(([department, credits2]) => /* @__PURE__ */ jsx(
AccordionItem,
{
labelClassName: "font-semibold text-base",
description: /* @__PURE__ */ jsx(
Trans,
{
message: "(:count credits)",
values: { count: credits2.length }
}
),
label: /* @__PURE__ */ jsx("span", { className: "capitalize", children: /* @__PURE__ */ jsx(
Trans,
{
message: department === "actors" ? "Acting" : department
}
) }),
children: credits2.map((credit, index) => {
var _a;
const isLast = credit === credits2[credits2.length - 1];
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsxs("div", { className: "flex items-start py-6", children: [
/* @__PURE__ */ jsx(
TitlePoster,
{
title: credit,
size: "w-40",
className: "mr-12",
lazy: true,
srcSize: "sm"
}
),
/* @__PURE__ */ jsxs("div", { className: "mr-24 pt-2", children: [
/* @__PURE__ */ jsx("div", { className: "font-semibold text-base", children: /* @__PURE__ */ jsx(TitleLink, { title: credit }) }),
/* @__PURE__ */ jsx(
CharacterOrJob,
{
className: "text-sm text-muted",
credit
}
),
credit.credited_episode_count ? /* @__PURE__ */ jsx(
EpisodeList,
{
credit,
department,
person
}
) : null
] }),
/* @__PURE__ */ jsx("div", { className: "text-sm text-muted ml-auto", children: credit.year })
] }),
!isLast && credit.year !== ((_a = credits2[index + 1]) == null ? void 0 : _a.year) && /* @__PURE__ */ jsx("div", { className: "h-1 w-full bg-divider my-8" })
] }, credit.id);
})
},
department
)) })
] });
}
function EpisodeList({ credit, department, person }) {
var _a;
const [loadMoreEpisodes, setLoadMoreEpisodes] = useState(false);
const query = useFullPersonCreditsForTitle(
{ person, department, credit },
{
enabled: loadMoreEpisodes
}
);
const allEpisodesLoaded = credit.episodes.length === credit.credited_episode_count || query.data != null;
const isLoadingMore = query.isLoading && query.fetchStatus !== "idle";
const shouldShowLoadMoreBtn = isLoadingMore || !allEpisodesLoaded;
const episodeCredits = ((_a = query.data) == null ? void 0 : _a.credits.length) ? query.data.credits : credit.episodes;
return /* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
/* @__PURE__ */ jsx("div", { children: episodeCredits.map((episodeCredit) => /* @__PURE__ */ jsx("div", { className: "text-xs pl-10 mb-4", children: /* @__PURE__ */ jsxs(BulletSeparatedItems, { children: [
/* @__PURE__ */ jsxs("span", { children: [
"-",
" ",
/* @__PURE__ */ jsx(
EpisodeLink,
{
title: credit,
episode: episodeCredit,
seasonNumber: episodeCredit.season_number
}
),
" ",
"(",
episodeCredit.year,
")"
] }),
/* @__PURE__ */ jsx(CompactSeasonEpisode, { episode: episodeCredit }),
/* @__PURE__ */ jsx(CharacterOrJob, { credit: episodeCredit })
] }) }, episodeCredit.id)) }),
shouldShowLoadMoreBtn && /* @__PURE__ */ jsx("div", { className: "mt-8", children: /* @__PURE__ */ jsx(
Button,
{
size: "xs",
disabled: isLoadingMore,
onClick: () => {
setLoadMoreEpisodes(true);
},
children: /* @__PURE__ */ jsx(
Trans,
{
message: "Show all :count episodes",
values: { count: credit.credited_episode_count }
}
)
}
) })
] });
}
function PersonPage() {
const query = usePerson("personPage");
const content2 = query.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(PageContent$6, { data: query.data })
] }) : /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
return /* @__PURE__ */ jsx(SitePageLayout, { children: content2 });
}
function PageContent$6({ data }) {
const { person, knownFor } = data;
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("div", { className: "container mx-auto mt-14 px-14 md:mt-40 md:px-24", children: /* @__PURE__ */ jsxs("div", { className: "items-start gap-54 md:flex", children: [
/* @__PURE__ */ jsx(PersonPageAside, { data }),
/* @__PURE__ */ jsxs("main", { className: "flex-auto @container max-md:mt-34", children: [
/* @__PURE__ */ jsx(TitlePageHeaderLayout, { name: person.name }),
/* @__PURE__ */ jsx(Biography, { person }),
/* @__PURE__ */ jsx(AdHost, { slot: "person_top", className: "pt-48" }),
/* @__PURE__ */ jsx(KnowForList, { items: knownFor }),
/* @__PURE__ */ jsx(PersonPageCredits, { data })
] })
] }) }) });
}
function Biography({ person }) {
if (!person.description)
return null;
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(SiteSectionHeading, { fontSize: "text-xl", children: /* @__PURE__ */ jsx(Trans, { message: "Biography" }) }),
/* @__PURE__ */ jsx(
TruncatedDescription,
{
className: "text-sm",
description: person.description
}
)
] });
}
function KnowForList({ items }) {
if (!(items == null ? void 0 : items.length))
return null;
return /* @__PURE__ */ jsxs("div", { className: "mt-34", children: [
/* @__PURE__ */ jsx(SiteSectionHeading, { fontSize: "text-xl", children: /* @__PURE__ */ jsx(Trans, { message: "Known for" }) }),
/* @__PURE__ */ jsx(ContentGridLayout, { variant: "portrait", children: items.slice(0, 4).map((item) => /* @__PURE__ */ jsx(
TitlePortraitGridItem,
{
item,
description: /* @__PURE__ */ jsx(CharacterOrJob, { className: "text-muted", credit: item })
},
item.id
)) })
] });
}
function TitleFullCreditsPage() {
const query = useTitle("titleCreditsPage");
const content2 = query.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(PageContent$5, { data: query.data })
] }) : /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
return /* @__PURE__ */ jsx(SitePageLayout, { children: content2 });
}
function PageContent$5({
data: { title, credits: groupedCredits = {} }
}) {
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(TitlePageHeaderImage, { title }),
/* @__PURE__ */ jsxs("div", { className: "container mx-auto mt-24 px-14 md:mt-40 md:px-24", children: [
/* @__PURE__ */ jsx(TitlePageHeader, { title, showPoster: true }),
/* @__PURE__ */ jsxs("div", { className: "mt-48 @container", children: [
/* @__PURE__ */ jsx(SiteSectionHeading, { headingType: "h2", className: "mb-40", children: /* @__PURE__ */ jsx(Trans, { message: "Full cast and crew" }) }),
Object.entries(groupedCredits).map(([department, credits]) => /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx("h3", { className: "mb-16 text-2xl font-bold capitalize", children: /* @__PURE__ */ jsx(Trans, { message: department }) }),
/* @__PURE__ */ jsx(TitleCreditsGrid, { credits, className: "mb-68" })
] }, department))
] })
] })
] });
}
function EpisodeFullCreditsPage() {
const query = useEpisode("episodeCreditsPage");
const content2 = query.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(PageContent$4, { data: query.data })
] }) : /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
return /* @__PURE__ */ jsx(SitePageLayout, { children: content2 });
}
function PageContent$4({
data: { title, episode, credits: groupedCredits }
}) {
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(TitlePageHeaderImage, { title, episode }),
/* @__PURE__ */ jsxs("div", { className: "container mx-auto mt-24 px-14 md:mt-40 md:px-24", children: [
/* @__PURE__ */ jsx(EpisodePageHeader, { title, episode, showPoster: true }),
/* @__PURE__ */ jsxs("div", { className: "mt-48 @container", children: [
/* @__PURE__ */ jsx(SiteSectionHeading, { headingType: "h2", className: "mb-40", children: /* @__PURE__ */ jsx(Trans, { message: "Full cast and crew" }) }),
groupedCredits && Object.entries(groupedCredits).map(([department, credits]) => /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx("h3", { className: "mb-16 text-2xl font-bold capitalize", children: /* @__PURE__ */ jsx(Trans, { message: department }) }),
/* @__PURE__ */ jsx(TitleCreditsGrid, { credits, className: "mb-68" })
] }, department))
] })
] })
] });
}
function NewsArticlePage() {
const query = useNewsArticle("newsArticlePage");
const content2 = query.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(PageContent$3, { data: query.data })
] }) : /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
return /* @__PURE__ */ jsx(SitePageLayout, { children: content2 });
}
function PageContent$3({ data: { article, related } }) {
return /* @__PURE__ */ jsxs("div", { className: "container mx-auto mt-14 items-start gap-40 px-14 md:mt-40 md:px-24 lg:flex", children: [
/* @__PURE__ */ jsxs("main", { className: "mb-24 rounded border p-16 flex-auto", children: [
/* @__PURE__ */ jsx("h1", { className: "mb-24 text-3xl md:text-4xl", children: article.title }),
/* @__PURE__ */ jsxs("div", { className: "items-start gap-16 md:flex", children: [
/* @__PURE__ */ jsx(
NewsArticleImage,
{
article,
size: "w-184 h-184",
className: "max-md:mb-24"
}
),
/* @__PURE__ */ jsx(
"div",
{
className: "prose text dark:prose-invert",
dangerouslySetInnerHTML: { __html: article.body }
}
)
] }),
/* @__PURE__ */ jsxs(BulletSeparatedItems, { className: "mt-24 text-sm text-muted", children: [
/* @__PURE__ */ jsx(FormattedDate, { date: article.created_at }),
article.byline ? /* @__PURE__ */ jsx(NewsArticleByline, { article }) : null,
article.source ? /* @__PURE__ */ jsx(NewsArticleSourceLink, { article }) : null
] })
] }),
/* @__PURE__ */ jsx(OtherNews, { articles: related })
] });
}
function OtherNews({ articles }) {
return /* @__PURE__ */ jsxs("div", { className: "w-full max-w-full flex-shrink-0 lg:w-400", children: [
/* @__PURE__ */ jsx("h2", { className: "mb-14 text-2xl", children: /* @__PURE__ */ jsx(Trans, { message: "Other news" }) }),
articles.map((article) => /* @__PURE__ */ jsxs(
"div",
{
className: "mb-14 flex items-center gap-14 rounded border pr-14",
children: [
/* @__PURE__ */ jsx(NewsArticleImage, { article, size: "w-80 h-80", lazy: false }),
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
/* @__PURE__ */ jsx("h3", { className: "line-clamp-2 text-sm font-semibold", children: /* @__PURE__ */ jsx(NewsArticleLink, { article }) }),
/* @__PURE__ */ jsxs(BulletSeparatedItems, { className: "mt-6 text-sm text-muted", children: [
/* @__PURE__ */ jsx(FormattedDate, { date: article.created_at }),
/* @__PURE__ */ jsx(NewsArticleByline, { article })
] })
] })
]
},
article.id
))
] });
}
function useDeleteList() {
const { trans } = useTrans();
return useMutation({
mutationFn: (payload) => deleteList(payload),
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ["channel"] });
toast(trans(message("List deleted")));
},
onError: (err) => showHttpErrorToast(err)
});
}
function deleteList(payload) {
return apiClient.delete(`channel/${payload.listId}`).then((r2) => r2.data);
}
function UserListIndexItem({
list,
user,
showVisibility = true
}) {
const { user: authUser } = useAuth();
const canEdit = authUser && authUser.id === user.id;
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-24 border-b py-24", children: [
/* @__PURE__ */ jsx(
ItemsPreview,
{
className: "max-md:hidden",
list
}
),
/* @__PURE__ */ jsxs("section", { className: "flex-auto", children: [
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-8", children: [
/* @__PURE__ */ jsx(
UserListLink,
{
list,
className: "mr-auto block text-lg font-semibold capitalize"
}
),
!list.config.preventDeletion && !list.internal && canEdit && /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
Button,
{
elementType: Link,
to: `${getUserListLink(list)}/edit`,
variant: "outline",
size: "2xs",
color: "primary",
children: /* @__PURE__ */ jsx(Trans, { message: "Edit" })
}
),
/* @__PURE__ */ jsxs(DialogTrigger, { type: "modal", children: [
/* @__PURE__ */ jsx(
Button,
{
color: "danger",
variant: "outline",
radius: "rounded",
size: "2xs",
children: /* @__PURE__ */ jsx(Trans, { message: "Delete" })
}
),
/* @__PURE__ */ jsx(DeleteListDialog, { list })
] })
] })
] }),
list.description && /* @__PURE__ */ jsx("p", { className: "mt-8 whitespace-nowrap text-sm text-muted", children: list.description }),
/* @__PURE__ */ jsx("div", { className: "mt-12 text-sm", children: /* @__PURE__ */ jsxs("div", { className: "items-center justify-between gap-24 md:flex", children: [
user && /* @__PURE__ */ jsx(UserListByline, { user }),
/* @__PURE__ */ jsx(
UserListDetails,
{
list,
showVisibility,
className: "max-md:mt-12"
}
)
] }) })
] })
] });
}
function ItemsPreview({ list, className: className2 }) {
var _a, _b;
if (!((_a = list.items) == null ? void 0 : _a.length))
return null;
return /* @__PURE__ */ jsx(
"div",
{
className: clsx("flex items-center overflow-hidden rounded", className2),
children: (_b = list.items) == null ? void 0 : _b.map((item, index) => /* @__PURE__ */ jsxs(
"div",
{
style: { zIndex: 100 - index },
className: clsx(
"relative overflow-hidden rounded shadow-[2px_0_7px_#000]",
index !== 0 && "-ml-30"
),
children: [
item.model_type === "title" ? /* @__PURE__ */ jsx(TitlePoster, { title: item, size: "w-70", srcSize: "sm" }) : /* @__PURE__ */ jsx(PersonPoster, { person: item, size: "w-70", srcSize: "sm" }),
/* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 shadow-[inset_0_0_0_1px_rgba(221,238,255,.35)]" })
]
},
item.id
))
}
);
}
function DeleteListDialog({ list }) {
const deleteList2 = useDeleteList();
const { close } = useDialogContext();
return /* @__PURE__ */ jsx(
ConfirmationDialog,
{
isDanger: true,
title: /* @__PURE__ */ jsx(Trans, { message: "Delete list" }),
body: /* @__PURE__ */ jsx(Trans, { message: "Are you sure you want to delete this list?" }),
confirm: /* @__PURE__ */ jsx(Trans, { message: "Delete" }),
isLoading: deleteList2.isPending,
onConfirm: () => deleteList2.mutate({ listId: list.id }, { onSuccess: close })
}
);
}
function useProfileLists() {
const { userId = "me" } = useParams();
return useInfiniteData({
endpoint: `user-profile/${userId}/lists`,
queryKey: ["channel", "profile-lists", userId],
paginate: "simple"
});
}
function UserListsIndexPage() {
const query = useProfileLists();
const content2 = query.data ? /* @__PURE__ */ jsx(PageContent$2, { query }) : /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
return /* @__PURE__ */ jsxs(SitePageLayout, { children: [
/* @__PURE__ */ jsx(StaticPageTitle, { children: /* @__PURE__ */ jsx(Trans, { message: "Your lists" }) }),
/* @__PURE__ */ jsxs("div", { className: "container mx-auto mt-48 px-24", children: [
/* @__PURE__ */ jsx("header", { children: /* @__PURE__ */ jsx(
SiteSectionHeading,
{
headingType: "h1",
margin: "mb-34",
actions: /* @__PURE__ */ jsx(
Button,
{
variant: "flat",
color: "primary",
elementType: Link,
to: "new",
children: /* @__PURE__ */ jsx(Trans, { message: "New list" })
}
),
children: /* @__PURE__ */ jsx(Trans, { message: "My lists" })
}
) }),
content2
] })
] });
}
function PageContent$2({ query }) {
const { user } = useAuth();
if (query.noResults) {
return /* @__PURE__ */ jsx(
IllustratedMessage,
{
className: "mt-80",
image: /* @__PURE__ */ jsx(SvgImage, { src: todoImage }),
title: /* @__PURE__ */ jsx(Trans, { message: "You have not created any lists yet." })
}
);
}
return /* @__PURE__ */ jsxs("div", { children: [
query.items.map((list) => /* @__PURE__ */ jsx(UserListIndexItem, { list, user }, list.id)),
/* @__PURE__ */ jsx(InfiniteScrollSentinel, { query })
] });
}
const userProfileQueryKey = (userId) => [
"users",
`${userId}`,
"profile"
];
function useUserProfile() {
const { userId } = useParams();
return useQuery({
queryKey: userProfileQueryKey(userId),
queryFn: () => fetchProfile(userId)
});
}
function fetchProfile(userId) {
return apiClient.get(`user-profile/${userId}`).then((response) => response.data);
}
function ProfileDescription({ profile, className: className2 }) {
if (!profile)
return null;
return /* @__PURE__ */ jsxs("div", { className: clsx("text-sm", className2), children: [
profile.description && /* @__PURE__ */ jsx("p", { className: "rounded text-secondary whitespace-nowrap overflow-hidden overflow-ellipsis", children: profile.description }),
profile.city || profile.country ? /* @__PURE__ */ jsx("div", { className: "flex items-center gap-24 justify-between mt-4", children: (profile.city || profile.country) && /* @__PURE__ */ jsxs("div", { className: "rounded text-secondary w-max", children: [
profile.city,
profile.city && ",",
" ",
profile.country
] }) }) : null
] });
}
function useFollowedUsers() {
const { user } = useAuth();
return useQuery({
queryKey: ["users", "followed", "ids"],
queryFn: () => fetchIds(),
enabled: !!user
});
}
function useIsUserFollowing(user) {
const { data, isLoading } = useFollowedUsers();
return {
isLoading,
isFollowing: !!(data == null ? void 0 : data.ids.includes(user.id))
};
}
function fetchIds() {
return apiClient.get(`users/me/followed-users/ids`).then((response) => response.data);
}
function useFollowUser() {
return useMutation({
mutationFn: (payload) => followUser(payload),
onSuccess: async (response, { user }) => {
await queryClient.invalidateQueries({ queryKey: ["users"] });
toast(message("Following :name", { values: { name: user.display_name } }));
},
onError: (r2) => showHttpErrorToast(r2)
});
}
function followUser({ user }) {
return apiClient.post(`users/${user.id}/follow`).then((r2) => r2.data);
}
function useUnfollowUser() {
return useMutation({
mutationFn: (payload) => unfollowUser(payload),
onSuccess: async (response, { user }) => {
await queryClient.invalidateQueries({ queryKey: ["users"] });
toast(
message("Stopped following :name", { values: { name: user.display_name } })
);
},
onError: (r2) => showHttpErrorToast(r2)
});
}
function unfollowUser({ user }) {
return apiClient.post(`users/${user.id}/unfollow`).then((r2) => r2.data);
}
function FollowButton({
user,
className: className2,
minWidth = "min-w-82",
...buttonProps
}) {
const { user: currentUser } = useAuth();
const { isFollowing, isLoading } = useIsUserFollowing(user);
const followUser2 = useFollowUser();
const unfollowUser2 = useUnfollowUser();
const mergedClassName = clsx(className2, minWidth);
if (isFollowing) {
return /* @__PURE__ */ jsx(
Button,
{
...buttonProps,
className: mergedClassName,
onClick: () => unfollowUser2.mutate({ user }),
disabled: !currentUser || (currentUser == null ? void 0 : currentUser.id) === user.id || unfollowUser2.isPending || isLoading,
children: /* @__PURE__ */ jsx(Trans, { message: "Unfollow" })
}
);
}
return /* @__PURE__ */ jsx(
Button,
{
...buttonProps,
className: mergedClassName,
onClick: () => followUser2.mutate({ user }),
disabled: !currentUser || (currentUser == null ? void 0 : currentUser.id) === user.id || followUser2.isPending || isLoading,
children: /* @__PURE__ */ jsx(Trans, { message: "Follow" })
}
);
}
function ProfileLinksForm() {
const { fields, append, remove } = useFieldArray({
name: "links"
});
return /* @__PURE__ */ jsxs("div", { children: [
fields.map((field, index) => {
return /* @__PURE__ */ jsxs("div", { className: "flex gap-10 mb-10 items-end", children: [
/* @__PURE__ */ jsx(
FormTextField,
{
required: true,
type: "url",
label: /* @__PURE__ */ jsx(Trans, { message: "URL" }),
name: `links.${index}.url`,
size: "sm",
className: "flex-auto"
}
),
/* @__PURE__ */ jsx(
FormTextField,
{
required: true,
label: /* @__PURE__ */ jsx(Trans, { message: "Short title" }),
name: `links.${index}.title`,
size: "sm",
className: "flex-auto"
}
),
/* @__PURE__ */ jsx(
IconButton,
{
size: "sm",
color: "primary",
className: "flex-shrink-0",
onClick: () => {
remove(index);
},
children: /* @__PURE__ */ jsx(CloseIcon, {})
}
)
] }, field.id);
}),
/* @__PURE__ */ jsx(
Button,
{
variant: "text",
color: "primary",
startIcon: /* @__PURE__ */ jsx(AddIcon, {}),
size: "xs",
onClick: () => {
append({ url: "", title: "" });
},
children: /* @__PURE__ */ jsx(Trans, { message: "Add another link" })
}
)
] });
}
function useUpdateUserProfile(form) {
const { user } = useAuth();
const { trans } = useTrans();
return useMutation({
mutationFn: (payload) => updateProfile(payload),
onSuccess: async () => {
if (user) {
await queryClient.invalidateQueries({
queryKey: userProfileQueryKey(user.id)
});
}
toast(trans(message("Profile updated")));
},
onError: (err) => onFormQueryError(err, form)
});
}
function updateProfile(payload) {
return apiClient.put("user-profile/me", payload).then((r2) => r2.data);
}
function EditUserProfileDialog({ user }) {
var _a, _b, _c, _d;
const { close, formId } = useDialogContext();
const { data } = useValueLists(["countries"]);
const form = useForm({
defaultValues: {
user: {
username: user.username,
avatar: user.avatar,
first_name: user.first_name,
last_name: user.last_name
},
profile: {
city: (_a = user.profile) == null ? void 0 : _a.city,
country: (_b = user.profile) == null ? void 0 : _b.country,
description: (_c = user.profile) == null ? void 0 : _c.description
},
links: user.links
}
});
const updateProfile2 = useUpdateUserProfile(form);
return /* @__PURE__ */ jsxs(Dialog, { size: "xl", children: [
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(Trans, { message: "Edit your profile" }) }),
/* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsx(
Form,
{
id: formId,
form,
onSubmit: (values) => updateProfile2.mutate(values, { onSuccess: () => close() }),
children: /* @__PURE__ */ jsxs(FileUploadProvider, { children: [
/* @__PURE__ */ jsxs("div", { className: "md:flex items-start gap-30", children: [
/* @__PURE__ */ jsx(
FormImageSelector,
{
label: /* @__PURE__ */ jsx(Trans, { message: "Avatar" }),
name: "user.avatar",
diskPrefix: "avatars",
variant: "avatar",
previewSize: "w-200 h-200",
className: "max-md:mb-20"
}
),
/* @__PURE__ */ jsxs("div", { className: "flex-auto", children: [
/* @__PURE__ */ jsx(
FormTextField,
{
name: "user.username",
label: /* @__PURE__ */ jsx(Trans, { message: "Username" }),
className: "mb-24"
}
),
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-24", children: [
/* @__PURE__ */ jsx(
FormTextField,
{
name: "user.first_name",
label: /* @__PURE__ */ jsx(Trans, { message: "First name" }),
className: "flex-1 mb-24"
}
),
/* @__PURE__ */ jsx(
FormTextField,
{
name: "user.last_name",
label: /* @__PURE__ */ jsx(Trans, { message: "Last name" }),
className: "flex-1 mb-24"
}
)
] }),
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-24", children: [
/* @__PURE__ */ jsx(
FormTextField,
{
name: "profile.city",
label: /* @__PURE__ */ jsx(Trans, { message: "City" }),
className: "flex-1 mb-24"
}
),
/* @__PURE__ */ jsxs(
FormSelect,
{
showSearchField: true,
className: "flex-1 mb-24",
selectionMode: "single",
name: "profile.country",
label: /* @__PURE__ */ jsx(Trans, { message: "Country" }),
children: [
/* @__PURE__ */ jsx(Item, { value: void 0, children: /* @__PURE__ */ jsx(Trans, { message: "None" }) }, "none"),
(_d = data == null ? void 0 : data.countries) == null ? void 0 : _d.map((country) => /* @__PURE__ */ jsx(Item, { value: country.name, children: country.name }, country.code))
]
}
)
] }),
/* @__PURE__ */ jsx(
FormTextField,
{
name: "profile.description",
label: /* @__PURE__ */ jsx(Trans, { message: "Description" }),
inputElementType: "textarea",
rows: 4
}
)
] })
] }),
/* @__PURE__ */ jsxs("div", { className: "mt-24", children: [
/* @__PURE__ */ jsx("div", { className: "mb-16 pb-16 border-b", children: /* @__PURE__ */ jsx(Trans, { message: "Your links" }) }),
/* @__PURE__ */ jsx(ProfileLinksForm, {})
] })
] })
}
) }),
/* @__PURE__ */ jsxs(DialogFooter, { children: [
/* @__PURE__ */ jsx(
Button,
{
type: "button",
onClick: () => {
close();
},
children: /* @__PURE__ */ jsx(Trans, { message: "Cancel" })
}
),
/* @__PURE__ */ jsx(
Button,
{
form: formId,
type: "submit",
variant: "flat",
color: "primary",
disabled: updateProfile2.isPending,
children: /* @__PURE__ */ jsx(Trans, { message: "Save" })
}
)
] })
] });
}
function ProfileStatsList({ user }) {
const {
auth: { getUserProfileLink }
} = useContext(SiteConfigContext);
const profileLink = getUserProfileLink(user);
return /* @__PURE__ */ jsxs(StatsItems, { children: [
/* @__PURE__ */ jsx(
StatsItem,
{
label: /* @__PURE__ */ jsx(Trans, { message: "Followers" }),
value: user.followers_count || 0,
link: `${profileLink}/followers`
}
),
/* @__PURE__ */ jsx(
StatsItem,
{
label: /* @__PURE__ */ jsx(Trans, { message: "Following" }),
value: user.followed_users_count || 0,
link: `${profileLink}/followed-users`
}
),
/* @__PURE__ */ jsx(
StatsItem,
{
label: /* @__PURE__ */ jsx(Trans, { message: "Lists" }),
value: user.lists_count || 0,
link: `${profileLink}/lists`
}
)
] });
}
function StatsItems(props) {
const children = Children.toArray(props.children);
return /* @__PURE__ */ jsx("div", { className: "flex items-center", children: children.map((child, index) => /* @__PURE__ */ jsxs(Fragment, { children: [
child,
index < children.length - 1 && /* @__PURE__ */ jsx("div", { className: "mx-10 h-34 w-1 bg-divider" })
] }, index)) });
}
function StatsItem({ label, value, link }) {
return /* @__PURE__ */ jsxs(Link, { to: link, className: "group block text-center", children: [
/* @__PURE__ */ jsx("div", { className: "text-lg font-bold", children: /* @__PURE__ */ jsx(FormattedNumber, { value }) }),
/* @__PURE__ */ jsx("div", { className: "text-xs uppercase text-muted transition-colors group-hover:text-primary", children: label })
] });
}
function RemoteFavicon({
url,
className: className2,
size = "w-16 h-16",
alt
}) {
if (!url) {
return null;
}
const src = getFaviconSrc(url);
return /* @__PURE__ */ jsx(
"img",
{
className: clsx(size, className2),
src: getFaviconSrc(url),
alt: alt || `${src} favicon`
}
);
}
const getFaviconSrc = memoize((url) => {
if (url.includes("youtube")) {
return "https://www.youtube.com/s/desktop/ca54e1bd/img/favicon.ico";
}
if (!isAbsoluteUrl(url)) {
url = `${window.location.protocol}//${window.location.host}`;
}
const domain = new URL(url).origin;
return "https://www.google.com/s2/favicons?domain=" + domain;
});
function ProfileLinks({ links, className: className2 }) {
if (!(links == null ? void 0 : links.length))
return null;
if (links.length === 1) {
return /* @__PURE__ */ jsxs(
"a",
{
className: "flex items-center max-md:justify-center gap-6 mt-24 md:mt-12 hover:text-primary transition-colors",
href: links[0].url,
children: [
/* @__PURE__ */ jsx(OpenInNewIcon, { className: "text-muted", size: "sm" }),
/* @__PURE__ */ jsx("span", { className: "capitalize", children: links[0].title })
]
}
);
}
return /* @__PURE__ */ jsx("div", { className: clsx("flex items-center", className2), children: links.map((link) => /* @__PURE__ */ jsx(Tooltip, { label: link.title, children: /* @__PURE__ */ jsx(
ButtonBase,
{
elementType: "a",
href: link.url,
target: "_blank",
rel: "noreferrer",
children: /* @__PURE__ */ jsx(RemoteFavicon, { url: link.url, alt: link.title, size: "w-20 h-20" })
}
) }, link.url)) });
}
function ProfilePageHeader({ user }) {
const { user: currentUser } = useAuth();
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col md:flex-row items-center gap-24", children: [
/* @__PURE__ */ jsx(UserAvatar, { user, circle: true, size: "w-140 h-140" }),
/* @__PURE__ */ jsxs("div", { className: "flex-auto", children: [
/* @__PURE__ */ jsxs("div", { className: "flex items-center mb-8 gap-8", children: [
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold", children: user.display_name }),
user.is_pro && /* @__PURE__ */ jsx(Chip, { size: "xs", color: "primary", radius: "rounded", className: "mt-2", children: /* @__PURE__ */ jsx(Trans, { message: "PRO" }) })
] }),
/* @__PURE__ */ jsx(ProfileDescription, { profile: user.profile }),
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-14 mt-12", children: [
(currentUser == null ? void 0 : currentUser.id) !== user.id && /* @__PURE__ */ jsx(
FollowButton,
{
variant: "outline",
color: "primary",
size: "xs",
user
}
),
(currentUser == null ? void 0 : currentUser.id) === user.id && /* @__PURE__ */ jsx(EditButton, { user })
] })
] }),
/* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(ProfileStatsList, { user }),
/* @__PURE__ */ jsx(
ProfileLinks,
{
links: user.links,
className: "flex-shrink-0 ml-auto mt-12"
}
)
] })
] });
}
function EditButton({ user }) {
return /* @__PURE__ */ jsxs(DialogTrigger, { type: "modal", children: [
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "xs", startIcon: /* @__PURE__ */ jsx(EditIcon, {}), children: /* @__PURE__ */ jsx(Trans, { message: "Edit profile" }) }),
/* @__PURE__ */ jsx(EditUserProfileDialog, { user })
] });
}
const PageTabs = [
{ uri: "lists", label: message("Lists") },
{ uri: "ratings", label: message("Ratings") },
{ uri: "reviews", label: message("Reviews") },
{ uri: "comments", label: message("Comments") },
{ uri: "followers", label: message("Followers") },
{ uri: "followed-users", label: message("Following") }
];
function UserProfilePage() {
const query = useUserProfile();
const content2 = query.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(PageContent$1, { user: query.data.user })
] }) : /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
return /* @__PURE__ */ jsx(SitePageLayout, { children: content2 });
}
function PageContent$1({ user }) {
return /* @__PURE__ */ jsxs("div", { className: "container mx-auto mt-24 px-14 md:mt-40 md:px-24", children: [
/* @__PURE__ */ jsx(ProfilePageHeader, { user }),
/* @__PURE__ */ jsx(ProfileTabs, { user })
] });
}
function ProfileTabs({ user }) {
const {
auth: { getUserProfileLink }
} = useContext(SiteConfigContext);
const profileLink = getUserProfileLink(user);
const { pathname } = useLocation();
const tabName = pathname.split("/").pop();
let selectedTab = PageTabs.findIndex((tab) => tab.uri === tabName);
if (selectedTab === -1) {
selectedTab = 0;
}
return /* @__PURE__ */ jsxs(Tabs, { className: "mt-34", selectedTab, children: [
/* @__PURE__ */ jsx(TabList, { children: PageTabs.map((tab) => /* @__PURE__ */ jsx(
Tab,
{
width: "min-w-132",
elementType: Link,
to: `${profileLink}/${tab.uri}`,
replace: true,
children: /* @__PURE__ */ jsx(Trans, { ...tab.label })
},
tab.uri
)) }),
/* @__PURE__ */ jsx("div", { className: "mt-24", children: /* @__PURE__ */ jsx(Outlet, {}) })
] });
}
function ProfileListsPanel() {
const userQuery = useUserProfile();
const user = userQuery.data.user;
const listsQuery = useProfileLists();
if (listsQuery.noResults) {
return /* @__PURE__ */ jsx(
IllustratedMessage,
{
imageHeight: "h-auto",
imageMargin: "mb-14",
image: /* @__PURE__ */ jsx(ListAltIcon, { className: "text-muted" }),
size: "sm",
title: /* @__PURE__ */ jsx(Trans, { message: "No lists yet" }),
description: /* @__PURE__ */ jsx(
Trans,
{
message: "Follow :user for updates on lists they create in the future.",
values: { user: user.display_name }
}
)
}
);
}
if (listsQuery.data) {
return /* @__PURE__ */ jsxs("div", { children: [
listsQuery.items.map((list) => /* @__PURE__ */ jsx(
UserListIndexItem,
{
list,
user,
showVisibility: false
},
list.id
)),
/* @__PURE__ */ jsx(InfiniteScrollSentinel, { query: listsQuery })
] });
}
return /* @__PURE__ */ jsx(PageStatus, { query: listsQuery });
}
function useProfileRatings() {
const { userId = "me" } = useParams();
return useInfiniteData({
endpoint: `user-profile/${userId}/ratings`,
queryKey: ["reviews", "profile-page-ratings", userId],
paginate: "simple"
});
}
function EpisodePortraitGridItem({
item,
title,
rating
}) {
return /* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx(
EpisodePoster,
{
episode: item,
title,
srcSize: "lg",
aspect: "aspect-poster",
showPlayButton: true
}
),
/* @__PURE__ */ jsxs("div", { className: "mt-10 text-sm", children: [
/* @__PURE__ */ jsx(TitleRating, { score: rating ?? item.rating, className: "mb-4" }),
/* @__PURE__ */ jsx(
TitleLinkWithEpisodeNumber,
{
title,
episode: item,
className: "block font-medium text-base"
}
)
] })
] });
}
function ProfileRatingsPanel() {
const userQuery = useUserProfile();
const user = userQuery.data.user;
const ratingsQuery = useProfileRatings();
if (ratingsQuery.noResults) {
return /* @__PURE__ */ jsx(
IllustratedMessage,
{
imageHeight: "h-auto",
imageMargin: "mb-14",
image: /* @__PURE__ */ jsx(StarIcon, { className: "text-muted" }),
size: "sm",
title: /* @__PURE__ */ jsx(Trans, { message: "No ratings yet" }),
description: /* @__PURE__ */ jsx(
Trans,
{
message: "Follow :user for updates on titles they rate in the future.",
values: { user: user.display_name }
}
)
}
);
}
if (ratingsQuery.data) {
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(ContentGridLayout, { variant: "portrait", children: ratingsQuery.items.map((review) => {
const reviewable = review.reviewable;
if (reviewable.model_type === "episode") {
return /* @__PURE__ */ jsx(
EpisodePortraitGridItem,
{
item: reviewable,
title: reviewable.title,
rating: review.score
},
review.id
);
}
return /* @__PURE__ */ jsx(
TitlePortraitGridItem,
{
item: review.reviewable,
rating: review.score
},
review.id
);
}) }),
/* @__PURE__ */ jsx(InfiniteScrollSentinel, { query: ratingsQuery })
] });
}
return /* @__PURE__ */ jsx(PageStatus, { query: ratingsQuery });
}
function useProfileReviews() {
const { userId = "me" } = useParams();
return useInfiniteData({
endpoint: `user-profile/${userId}/reviews`,
queryKey: ["reviews", "profile-page-reviews", userId],
paginate: "simple"
});
}
function ProfileReviewsPanel() {
const userQuery = useUserProfile();
const user = userQuery.data.user;
const reviewsQuery = useProfileReviews();
if (reviewsQuery.noResults) {
return /* @__PURE__ */ jsx(
IllustratedMessage,
{
imageHeight: "h-auto",
imageMargin: "mb-14",
image: /* @__PURE__ */ jsx(RateReviewIcon, { className: "text-muted" }),
size: "sm",
title: /* @__PURE__ */ jsx(Trans, { message: "No reviews yet" }),
description: /* @__PURE__ */ jsx(
Trans,
{
message: "Follow :user for updates on titles they review in the future.",
values: { user: user.display_name }
}
)
}
);
}
if (reviewsQuery.data) {
return /* @__PURE__ */ jsxs(Fragment, { children: [
reviewsQuery.items.map((review) => /* @__PURE__ */ jsx(ReviewListItem, { review }, review.id)),
/* @__PURE__ */ jsx(InfiniteScrollSentinel, { query: reviewsQuery })
] });
}
return /* @__PURE__ */ jsx(PageStatus, { query: reviewsQuery });
}
function ReviewListItem({ review }) {
const totalVotes = review.helpful_count + review.not_helpful_count;
const reviewable = review.reviewable;
const title = reviewable.model_type === "episode" ? reviewable.title : reviewable;
return /* @__PURE__ */ jsxs("div", { className: "mb-24 flex items-start gap-24 border-b pb-24", children: [
/* @__PURE__ */ jsx(TitlePoster, { title, size: "w-90", srcSize: "sm" }),
/* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx("div", { className: "text-lg font-semibold", children: reviewable.model_type === "episode" ? /* @__PURE__ */ jsx(
TitleLinkWithEpisodeNumber,
{
title,
episode: reviewable,
target: "_blank"
}
) : /* @__PURE__ */ jsx(TitleLink, { title, target: "_blank" }) }),
/* @__PURE__ */ jsx(TitleRating, { className: "mb-8 mt-14", score: review.score }),
/* @__PURE__ */ jsx("div", { className: "text-base font-semibold", children: review.title }),
/* @__PURE__ */ jsx("p", { className: "mt-10 whitespace-pre-line text-sm", children: review.body }),
totalVotes ? /* @__PURE__ */ jsx("div", { className: "mt-12 text-xs text-muted", children: /* @__PURE__ */ jsx(
Trans,
{
message: ":helpfulCount out of :total people found this helpful.",
values: {
helpfulCount: review.helpful_count,
total: review.helpful_count + review.not_helpful_count
}
}
) }) : null
] })
] });
}
function useProfileComments() {
const { userId = "me" } = useParams();
return useInfiniteData({
endpoint: `user-profile/${userId}/comments`,
queryKey: ["comment", "profile-page-comments", userId],
paginate: "simple"
});
}
function ProfileCommentsPanel() {
const userQuery = useUserProfile();
const user = userQuery.data.user;
const commentsQuery = useProfileComments();
if (commentsQuery.noResults) {
return /* @__PURE__ */ jsx(
IllustratedMessage,
{
imageHeight: "h-auto",
imageMargin: "mb-14",
image: /* @__PURE__ */ jsx(RateReviewIcon, { className: "text-muted" }),
size: "sm",
title: /* @__PURE__ */ jsx(Trans, { message: "No comments yet" }),
description: /* @__PURE__ */ jsx(
Trans,
{
message: "Follow :user for updates on comments they post in the future.",
values: { user: user.display_name }
}
)
}
);
}
if (commentsQuery.data) {
return /* @__PURE__ */ jsxs(Fragment, { children: [
commentsQuery.items.map((comment) => /* @__PURE__ */ jsx(CommentListItem, { comment }, comment.id)),
/* @__PURE__ */ jsx(InfiniteScrollSentinel, { query: commentsQuery })
] });
}
return /* @__PURE__ */ jsx(PageStatus, { query: commentsQuery });
}
function CommentListItem({ comment }) {
const commentable = comment.commentable;
const title = commentable.model_type === "episode" ? commentable.title : commentable;
return /* @__PURE__ */ jsxs("div", { className: "mb-24 flex items-start gap-24 border-b pb-24", children: [
/* @__PURE__ */ jsx(TitlePoster, { title, size: "w-90", srcSize: "sm" }),
/* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx("div", { className: "text-lg font-semibold", children: commentable.model_type === "episode" ? /* @__PURE__ */ jsx(
TitleLinkWithEpisodeNumber,
{
title,
episode: commentable,
target: "_blank"
}
) : /* @__PURE__ */ jsx(TitleLink, { title, target: "_blank" }) }),
/* @__PURE__ */ jsx("time", { className: "mt-12 block text-xs text-muted", children: /* @__PURE__ */ jsx(FormattedRelativeTime, { date: comment.created_at }) }),
/* @__PURE__ */ jsx("p", { className: "mt-8 whitespace-pre-line text-sm", children: comment.content }),
comment.upvotes ? /* @__PURE__ */ jsxs("div", { className: "mt-12 flex items-center gap-8 text-muted", children: [
/* @__PURE__ */ jsx(ThumbUpIcon, { size: "sm" }),
/* @__PURE__ */ jsx("div", { children: comment.upvotes })
] }) : null
] })
] });
}
function useProfileFollowers() {
const { userId = "me" } = useParams();
return useInfiniteData({
endpoint: `users/${userId}/followers`,
queryKey: ["users", "profile-page-followers", userId],
paginate: "simple"
});
}
function FollowerListItem({ follower }) {
return /* @__PURE__ */ jsxs(
"div",
{
className: "flex items-center gap-16 mb-16 pb-16 border-b",
children: [
/* @__PURE__ */ jsx(UserAvatar, { user: follower, size: "lg" }),
/* @__PURE__ */ jsxs("div", { className: "text-sm", children: [
/* @__PURE__ */ jsx(UserProfileLink, { user: follower }),
follower.followers_count && follower.followers_count > 0 ? /* @__PURE__ */ jsx("div", { className: "text-xs text-muted", children: /* @__PURE__ */ jsx(
Trans,
{
message: "[one 1 followers|other :count followers]",
values: { count: follower.followers_count }
}
) }) : null
] }),
/* @__PURE__ */ jsx(
FollowButton,
{
variant: "outline",
size: "xs",
className: "ml-auto",
user: follower
}
)
]
},
follower.id
);
}
function ProfileFollowersPanel() {
const userQuery = useUserProfile();
const user = userQuery.data.user;
const followersQuery = useProfileFollowers();
if (followersQuery.noResults) {
return /* @__PURE__ */ jsx(
IllustratedMessage,
{
imageHeight: "h-auto",
imageMargin: "mb-14",
image: /* @__PURE__ */ jsx(BookmarkBorderIcon, { className: "text-muted" }),
size: "sm",
title: /* @__PURE__ */ jsx(Trans, { message: "No followers yet" }),
description: /* @__PURE__ */ jsx(
Trans,
{
message: "Be the first to follow :name.",
values: { name: user.display_name }
}
)
}
);
}
if (followersQuery.data) {
return /* @__PURE__ */ jsxs(Fragment, { children: [
followersQuery.items.map((follower) => /* @__PURE__ */ jsx(FollowerListItem, { follower }, follower.id)),
/* @__PURE__ */ jsx(InfiniteScrollSentinel, { query: followersQuery })
] });
}
return /* @__PURE__ */ jsx(PageStatus, { query: followersQuery });
}
function useProfileFollowedUsers() {
const { userId = "me" } = useParams();
return useInfiniteData({
endpoint: `users/${userId}/followed-users`,
queryKey: ["users", "profile-page-followed-users", userId],
paginate: "simple"
});
}
function ProfileFollowedUsersPanel() {
const userQuery = useUserProfile();
const user = userQuery.data.user;
const followedUsersQuery = useProfileFollowedUsers();
if (followedUsersQuery.noResults) {
return /* @__PURE__ */ jsx(
IllustratedMessage,
{
imageHeight: "h-auto",
imageMargin: "mb-14",
image: /* @__PURE__ */ jsx(BookmarkBorderIcon, { className: "text-muted" }),
size: "sm",
title: /* @__PURE__ */ jsx(Trans, { message: "Not following anyone yet" }),
description: /* @__PURE__ */ jsx(
Trans,
{
message: "Check back later to see users :user is following.",
values: { user: user.display_name }
}
)
}
);
}
if (followedUsersQuery.data) {
return /* @__PURE__ */ jsxs(Fragment, { children: [
followedUsersQuery.items.map((followedUser) => /* @__PURE__ */ jsx(FollowerListItem, { follower: followedUser }, followedUser.id)),
/* @__PURE__ */ jsx(InfiniteScrollSentinel, { query: followedUsersQuery })
] });
}
return /* @__PURE__ */ jsx(PageStatus, { query: followedUsersQuery });
}
function SearchPage() {
const { query: searchTerm } = useParams();
const query = useSearchResults("searchPage", searchTerm);
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(PageMetaTags, { query }),
/* @__PURE__ */ jsx(SitePageLayout, { children: /* @__PURE__ */ jsx("section", { className: "container mx-auto mt-24 px-14 md:mt-40 md:px-24", children: /* @__PURE__ */ jsxs("main", { children: [
/* @__PURE__ */ jsx(MobileSearchBar, {}),
/* @__PURE__ */ jsx(PageContent, { query })
] }) }) })
] });
}
function MobileSearchBar() {
const { searchQuery = "" } = useParams();
const navigate = useNavigate();
const { trans } = useTrans();
return /* @__PURE__ */ jsx(
TextField,
{
defaultValue: searchQuery,
onChange: (e) => {
navigate(`/search/${e.target.value}`, { replace: true });
},
autoFocus: true,
className: "w-full md:hidden",
size: "lg",
placeholder: trans(message("Search..."))
}
);
}
function PageContent({ query }) {
const { branding } = useSettings();
if (query.data) {
return /* @__PURE__ */ jsx(SearchResults, { query });
}
if (query.fetchStatus === "idle") {
return /* @__PURE__ */ jsx(
IllustratedMessage,
{
className: "mt-40",
image: /* @__PURE__ */ jsx(SearchIcon, { size: "xl" }),
imageHeight: "h-auto",
imageMargin: "mb-12",
title: /* @__PURE__ */ jsx(
Trans,
{
message: "Search :siteName",
values: { siteName: branding.site_name }
}
),
description: /* @__PURE__ */ jsx(Trans, { message: "Find movies, tv series, people and more." })
}
);
}
return /* @__PURE__ */ jsx(PageStatus, { query, loaderClassName: "absolute inset-0 m-auto" });
}
function SearchResults({ query }) {
const { query: searchTerm } = useParams();
const { movies, series, people } = useMemo(() => {
var _a;
const movies2 = [];
const series2 = [];
const people2 = [];
(_a = query.data) == null ? void 0 : _a.results.forEach((result) => {
if (result.model_type === TITLE_MODEL && result.is_series) {
series2.push(result);
} else if (result.model_type === TITLE_MODEL && !result.is_series) {
movies2.push(result);
} else if (result.model_type === PERSON_MODEL) {
people2.push(result);
}
});
return { movies: movies2, series: series2, people: people2 };
}, [query]);
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
SiteSectionHeading,
{
className: "my-24 md:mb-48",
headingType: "h1",
fontSize: "text-xl md:text-3xl",
hideBorder: true,
children: /* @__PURE__ */ jsx(
Trans,
{
message: "Search results for: “:query“",
values: { query: searchTerm }
}
)
}
),
movies.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-48", children: [
/* @__PURE__ */ jsx(SiteSectionHeading, { fontSize: "text-2xl", children: /* @__PURE__ */ jsx(Trans, { message: "Movies" }) }),
/* @__PURE__ */ jsx(ContentGrid, { content: movies, variant: "portrait" })
] }),
series.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-48", children: [
/* @__PURE__ */ jsx(SiteSectionHeading, { fontSize: "text-2xl", children: /* @__PURE__ */ jsx(Trans, { message: "Series" }) }),
/* @__PURE__ */ jsx(ContentGrid, { content: series, variant: "portrait" })
] }),
people.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-48", children: [
/* @__PURE__ */ jsx(SiteSectionHeading, { fontSize: "text-2xl", children: /* @__PURE__ */ jsx(Trans, { message: "People" }) }),
/* @__PURE__ */ jsx(ContentGrid, { content: people, variant: "portrait" })
] })
] });
}
const RouteConfig = [
{
index: true,
element: /* @__PURE__ */ jsx(HomepageChannelPage, {})
},
{
path: "search",
element: /* @__PURE__ */ jsx(SearchPage, {})
},
{
path: "search/:query",
element: /* @__PURE__ */ jsx(SearchPage, {})
},
// Watch
{
path: "watch/:videoId",
element: /* @__PURE__ */ jsx(WatchPage, {})
},
// Titles
{
path: "/titles/:titleId/:titleSlug",
element: /* @__PURE__ */ jsx(TitlePage, {})
},
{
path: "/titles/:titleId/:titleSlug/videos",
element: /* @__PURE__ */ jsx(TitleVideosPage, {})
},
{
path: "/titles/:titleId/:titleSlug/images",
element: /* @__PURE__ */ jsx(TitleImagesPage, {})
},
{
path: "/titles/:titleId/:titleSlug/full-credits",
element: /* @__PURE__ */ jsx(TitleFullCreditsPage, {})
},
{
path: "/titles/:titleId/:titleSlug/season/:season",
element: /* @__PURE__ */ jsx(SeasonPage, {})
},
{
path: "/titles/:titleId/:titleSlug/season/:season/episode/:episode",
element: /* @__PURE__ */ jsx(EpisodePage, {})
},
{
path: "/titles/:titleId/:titleSlug/season/:season/episode/:episode/full-credits",
element: /* @__PURE__ */ jsx(EpisodeFullCreditsPage, {})
},
// People
{
path: "/people/:personId",
element: /* @__PURE__ */ jsx(PersonPage, {})
},
{
path: "/people/:personId/:personSlug",
element: /* @__PURE__ */ jsx(PersonPage, {})
},
// News
{
path: "/news/:articleId",
element: /* @__PURE__ */ jsx(NewsArticlePage, {})
},
// Profile page
{
path: "user/:userId/:slug",
element: /* @__PURE__ */ jsx(UserProfilePage, {}),
children: [
{
index: true,
element: /* @__PURE__ */ jsx(ProfileListsPanel, {})
},
{
path: "lists",
element: /* @__PURE__ */ jsx(ProfileListsPanel, {})
},
{
path: "ratings",
element: /* @__PURE__ */ jsx(ProfileRatingsPanel, {})
},
{
path: "reviews",
element: /* @__PURE__ */ jsx(ProfileReviewsPanel, {})
},
{
path: "comments",
element: /* @__PURE__ */ jsx(ProfileCommentsPanel, {})
},
{
path: "followers",
element: /* @__PURE__ */ jsx(ProfileFollowersPanel, {})
},
{
path: "followed-users",
element: /* @__PURE__ */ jsx(ProfileFollowedUsersPanel, {})
}
]
},
{
path: "user/:userId/:slug/:tab",
element: /* @__PURE__ */ jsx(UserProfilePage, {})
},
// User Lists
{
path: "/lists",
element: /* @__PURE__ */ jsx(AuthRoute, { children: /* @__PURE__ */ jsx(UserListsIndexPage, {}) })
},
{
path: "/lists/new",
element: /* @__PURE__ */ jsx(AuthRoute, { children: /* @__PURE__ */ jsx(SitePageLayout, { children: /* @__PURE__ */ jsx(CreateUserListPage, {}) }) })
},
{
path: "/lists/:slugOrId",
element: /* @__PURE__ */ jsx(ChannelPage, { type: "list" })
},
{
path: "/lists/:slugOrId/edit",
element: /* @__PURE__ */ jsx(SitePageLayout, { children: /* @__PURE__ */ jsx(EditUserListPage, {}) })
},
// Channels
{
path: ":slugOrId",
element: /* @__PURE__ */ jsx(ChannelPage, {})
},
{
path: "channel/:slugOrId",
element: /* @__PURE__ */ jsx(ChannelPage, {})
},
{
path: ":slugOrId/:restriction",
element: /* @__PURE__ */ jsx(ChannelPage, {})
},
{
path: "channel/:slugOrId/:restriction",
element: /* @__PURE__ */ jsx(ChannelPage, {})
},
{
path: "*",
element: /* @__PURE__ */ jsx(NotFoundPage, {})
}
];
function HomepageChannelPage() {
const { homepage } = useSettings();
let slugOrId = "homepage";
if ((homepage == null ? void 0 : homepage.type) === "channel" && homepage.value) {
slugOrId = homepage.value;
}
return /* @__PURE__ */ jsx(ChannelPage, { slugOrId });
}
function SiteRoutes() {
return useRoutes(RouteConfig);
}
export {
SiteRoutes as default
};
//# sourceMappingURL=site-routes-cce2e301.mjs.map