@burdenoff/microfe-hookmovies 2026.731.1 → 2026.827.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hookmovies/HookMoviesRoutes.js +1 -1
- package/dist/hookmovies/HookMoviesRoutes.js.map +1 -1
- package/dist/hookmovies/components/AddToListButton.d.ts +17 -0
- package/dist/hookmovies/components/AddToListButton.d.ts.map +1 -0
- package/dist/hookmovies/components/AddToListButton.js +216 -0
- package/dist/hookmovies/components/AddToListButton.js.map +1 -0
- package/dist/hookmovies/components/index.d.ts +1 -0
- package/dist/hookmovies/components/index.d.ts.map +1 -1
- package/dist/hookmovies/components/index.js +1 -0
- package/dist/hookmovies/context/HookMoviesContext.js +1 -1
- package/dist/hookmovies/context/HookMoviesContext.js.map +1 -1
- package/dist/hookmovies/hooks/index.d.ts +2 -2
- package/dist/hookmovies/hooks/index.d.ts.map +1 -1
- package/dist/hookmovies/hooks/useHookMoviesApi.d.ts +50 -3
- package/dist/hookmovies/hooks/useHookMoviesApi.d.ts.map +1 -1
- package/dist/hookmovies/hooks/useHookMoviesApi.js +124 -89
- package/dist/hookmovies/hooks/useHookMoviesApi.js.map +1 -1
- package/dist/hookmovies/index.d.ts +2 -2
- package/dist/hookmovies/index.d.ts.map +1 -1
- package/dist/hookmovies/pages/auditions/AuditionCreatePage.js +1 -1
- package/dist/hookmovies/pages/auditions/AuditionCreatePage.js.map +1 -1
- package/dist/hookmovies/pages/auditions/AuditionDetailPage.js +1 -1
- package/dist/hookmovies/pages/auditions/AuditionDetailPage.js.map +1 -1
- package/dist/hookmovies/pages/catalog/TitleDetailPage.js +1 -1
- package/dist/hookmovies/pages/catalog/TitleDetailPage.js.map +1 -1
- package/dist/hookmovies/pages/catalog/TitlesPage.d.ts.map +1 -1
- package/dist/hookmovies/pages/catalog/TitlesPage.js +119 -108
- package/dist/hookmovies/pages/catalog/TitlesPage.js.map +1 -1
- package/dist/hookmovies/pages/commerce/CheckoutPage.js +1 -1
- package/dist/hookmovies/pages/commerce/CheckoutPage.js.map +1 -1
- package/dist/hookmovies/pages/consumer/DiscoveryPage.d.ts.map +1 -1
- package/dist/hookmovies/pages/consumer/DiscoveryPage.js +169 -146
- package/dist/hookmovies/pages/consumer/DiscoveryPage.js.map +1 -1
- package/dist/hookmovies/pages/consumer/PlayerPage.js +1 -1
- package/dist/hookmovies/pages/consumer/PlayerPage.js.map +1 -1
- package/dist/hookmovies/pages/consumer/TitleViewPage.d.ts.map +1 -1
- package/dist/hookmovies/pages/consumer/TitleViewPage.js +149 -141
- package/dist/hookmovies/pages/consumer/TitleViewPage.js.map +1 -1
- package/dist/hookmovies/pages/engagement/ReviewsPage.d.ts.map +1 -1
- package/dist/hookmovies/pages/engagement/ReviewsPage.js +205 -101
- package/dist/hookmovies/pages/engagement/ReviewsPage.js.map +1 -1
- package/dist/hookmovies/pages/library/ListsPage.d.ts.map +1 -1
- package/dist/hookmovies/pages/library/ListsPage.js +340 -184
- package/dist/hookmovies/pages/library/ListsPage.js.map +1 -1
- package/dist/hookmovies/pages/localization/LocalizationPage.js +1 -1
- package/dist/hookmovies/pages/localization/LocalizationPage.js.map +1 -1
- package/dist/hookmovies/pages/productions/ProductionDetailPage.js +1 -1
- package/dist/hookmovies/pages/productions/ProductionDetailPage.js.map +1 -1
- package/dist/hookmovies/pages/social/WatchPartyRoomPage.js +1 -1
- package/dist/hookmovies/pages/social/WatchPartyRoomPage.js.map +1 -1
- package/dist/index.js +5 -5
- package/package.json +5 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useHookMovies as e } from "./context/HookMoviesContext.js";
|
|
2
2
|
import { HomePage as t } from "./pages/HomePage.js";
|
|
3
3
|
import { Suspense as n, lazy as r } from "react";
|
|
4
|
-
import { Navigate as i, Route as a, Routes as o, useLocation as s } from "react-router
|
|
4
|
+
import { Navigate as i, Route as a, Routes as o, useLocation as s } from "react-router";
|
|
5
5
|
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
6
6
|
import { FeatureGate as u } from "@burdenoff/fe-libs/shared/feature-flags";
|
|
7
7
|
//#region src/hookmovies/HookMoviesRoutes.tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HookMoviesRoutes.js","names":[],"sources":["../../src/hookmovies/HookMoviesRoutes.tsx"],"sourcesContent":["/**\n * HookMovies Routes\n * @module hookmovies\n *\n * Real domain routes for the HookMovies workspace product: catalog (titles,\n * studios, people), production lifecycle, casting auditions, audience\n * engagement (reviews), rights & distribution, and the user library (lists +\n * entitlements). All data comes from the live `hookmovies` subgraph.\n */\n\nimport { type FC, lazy, Suspense, type ReactNode, type ReactElement } from 'react';\nimport { Routes, Route, Navigate, useLocation } from 'react-router-dom';\nimport { FeatureGate } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { useHookMovies } from './context/HookMoviesContext';\n\n// Eager — primary landing\nimport { HomePage } from './pages/HomePage';\n\n// Catalog\nconst TitlesPage = lazy(() =>\n import('./pages/catalog/TitlesPage').then((m) => ({ default: m.TitlesPage }))\n);\nconst TitleCreatePage = lazy(() =>\n import('./pages/catalog/TitleCreatePage').then((m) => ({ default: m.TitleCreatePage }))\n);\nconst TitleDetailPage = lazy(() =>\n import('./pages/catalog/TitleDetailPage').then((m) => ({ default: m.TitleDetailPage }))\n);\nconst StudiosPage = lazy(() =>\n import('./pages/catalog/StudiosPage').then((m) => ({ default: m.StudiosPage }))\n);\nconst PeoplePage = lazy(() =>\n import('./pages/catalog/PeoplePage').then((m) => ({ default: m.PeoplePage }))\n);\n\n// Productions\nconst ProductionsPage = lazy(() =>\n import('./pages/productions/ProductionsPage').then((m) => ({ default: m.ProductionsPage }))\n);\nconst ProductionCreatePage = lazy(() =>\n import('./pages/productions/ProductionCreatePage').then((m) => ({\n default: m.ProductionCreatePage,\n }))\n);\nconst ProductionDetailPage = lazy(() =>\n import('./pages/productions/ProductionDetailPage').then((m) => ({\n default: m.ProductionDetailPage,\n }))\n);\n\n// Auditions\nconst AuditionsPage = lazy(() =>\n import('./pages/auditions/AuditionsPage').then((m) => ({ default: m.AuditionsPage }))\n);\nconst AuditionCreatePage = lazy(() =>\n import('./pages/auditions/AuditionCreatePage').then((m) => ({ default: m.AuditionCreatePage }))\n);\nconst AuditionDetailPage = lazy(() =>\n import('./pages/auditions/AuditionDetailPage').then((m) => ({ default: m.AuditionDetailPage }))\n);\n\n// Engagement\nconst ReviewsPage = lazy(() =>\n import('./pages/engagement/ReviewsPage').then((m) => ({ default: m.ReviewsPage }))\n);\n\n// Distribution\nconst RightsWindowsPage = lazy(() =>\n import('./pages/distribution/RightsWindowsPage').then((m) => ({ default: m.RightsWindowsPage }))\n);\n\n// Library\nconst ListsPage = lazy(() =>\n import('./pages/library/ListsPage').then((m) => ({ default: m.ListsPage }))\n);\nconst EntitlementsPage = lazy(() =>\n import('./pages/library/EntitlementsPage').then((m) => ({ default: m.EntitlementsPage }))\n);\n\n// Consumer (audience-facing) — discovery, title view, playback, hooks feed\nconst DiscoveryPage = lazy(() =>\n import('./pages/consumer/DiscoveryPage').then((m) => ({ default: m.DiscoveryPage }))\n);\nconst TitleViewPage = lazy(() =>\n import('./pages/consumer/TitleViewPage').then((m) => ({ default: m.TitleViewPage }))\n);\nconst PlayerPage = lazy(() =>\n import('./pages/consumer/PlayerPage').then((m) => ({ default: m.PlayerPage }))\n);\nconst HooksPage = lazy(() =>\n import('./pages/consumer/HooksPage').then((m) => ({ default: m.HooksPage }))\n);\n\n// Social — viewing profiles & synchronized watch parties\nconst ProfilesPage = lazy(() =>\n import('./pages/social/ProfilesPage').then((m) => ({ default: m.ProfilesPage }))\n);\nconst WatchPartyListPage = lazy(() =>\n import('./pages/social/WatchPartyListPage').then((m) => ({ default: m.WatchPartyListPage }))\n);\nconst WatchPartyRoomPage = lazy(() =>\n import('./pages/social/WatchPartyRoomPage').then((m) => ({ default: m.WatchPartyRoomPage }))\n);\n\n// Commerce — checkout (TVOD purchase / rental) & creator payouts\nconst CheckoutPage = lazy(() =>\n import('./pages/commerce/CheckoutPage').then((m) => ({ default: m.CheckoutPage }))\n);\nconst PayoutsPage = lazy(() =>\n import('./pages/analytics/PayoutsPage').then((m) => ({ default: m.PayoutsPage }))\n);\n\n// Analytics — creator / operator performance dashboards\nconst AnalyticsPage = lazy(() =>\n import('./pages/analytics/AnalyticsPage').then((m) => ({ default: m.AnalyticsPage }))\n);\n\n// Trust & safety — moderation queue\nconst ModerationPage = lazy(() =>\n import('./pages/trust/ModerationPage').then((m) => ({ default: m.ModerationPage }))\n);\n\n// Onboarding — language / content preferences\nconst OnboardingPage = lazy(() =>\n import('./pages/onboarding/OnboardingPage').then((m) => ({ default: m.OnboardingPage }))\n);\n\n// Developer portal — API keys\nconst DevPortalPage = lazy(() =>\n import('./pages/developer/DevPortalPage').then((m) => ({ default: m.DevPortalPage }))\n);\n\n// Live — FAST linear channels & schedules\nconst LivePage = lazy(() => import('./pages/live/LivePage').then((m) => ({ default: m.LivePage })));\n\n// Localization — per-title subtitle / caption / dub track management\nconst LocalizationPage = lazy(() =>\n import('./pages/localization/LocalizationPage').then((m) => ({ default: m.LocalizationPage }))\n);\n\n// AI — concierge / recommendations assistant\nconst ConciergePage = lazy(() =>\n import('./pages/ai/ConciergePage').then((m) => ({ default: m.ConciergePage }))\n);\n\nconst PageLoader: FC = () => (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"h-8 w-8 animate-spin rounded-full border-b-2 border-action-primary-bg\" />\n </div>\n);\n\nconst FeatureDisabledFallback: FC = () => (\n <div className=\"flex min-h-[400px] flex-col items-center justify-center gap-2 px-6 text-center\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Coming soon</h2>\n <p className=\"max-w-sm text-sm text-text-secondary\">\n This feature is currently disabled for this workspace.\n </p>\n </div>\n);\n\n/**\n * Wrap a route element in a `FeatureGate` with the shared \"coming soon\"\n * fallback. `defaultValue={true}` keeps already-shipped screens visible\n * before their flag is seeded — seeding must never hide a working feature.\n */\nfunction gated(flag: string, element: ReactNode): ReactElement {\n return (\n <FeatureGate flag={flag} defaultValue={true} fallback={<FeatureDisabledFallback />}>\n {element}\n </FeatureGate>\n );\n}\n\nexport const HookMoviesRoutes: FC = () => {\n const { basePath, isStandalone } = useHookMovies();\n const location = useLocation();\n\n const normalizedBasePath = basePath === '/' ? '' : (basePath ?? '').replace(/\\/$/, '');\n\n if (normalizedBasePath && !isStandalone) {\n const pathMatches =\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + '/');\n\n if (!pathMatches) {\n return null;\n }\n }\n\n return (\n <div className=\"flex min-h-full flex-col\">\n <Suspense fallback={<PageLoader />}>\n <Routes>\n {/* Overview / dashboard */}\n <Route index element={<HomePage />} />\n\n {/* Catalog */}\n <Route path=\"catalog/titles\" element={<TitlesPage />} />\n <Route path=\"catalog/titles/new\" element={<TitleCreatePage />} />\n <Route path=\"catalog/titles/:id\" element={<TitleDetailPage />} />\n <Route path=\"catalog/studios\" element={<StudiosPage />} />\n <Route path=\"catalog/people\" element={<PeoplePage />} />\n\n {/* Productions */}\n <Route path=\"productions\" element={<ProductionsPage />} />\n <Route path=\"productions/new\" element={<ProductionCreatePage />} />\n <Route path=\"productions/:id\" element={<ProductionDetailPage />} />\n\n {/* Auditions */}\n <Route path=\"auditions\" element={<AuditionsPage />} />\n <Route path=\"auditions/new\" element={<AuditionCreatePage />} />\n <Route path=\"auditions/:id\" element={<AuditionDetailPage />} />\n\n {/* Engagement */}\n <Route path=\"engagement/reviews\" element={<ReviewsPage />} />\n\n {/* Distribution */}\n <Route path=\"distribution/rights\" element={<RightsWindowsPage />} />\n\n {/* Library */}\n <Route path=\"library/lists\" element={<ListsPage />} />\n <Route path=\"library/entitlements\" element={<EntitlementsPage />} />\n\n {/* Consumer (audience-facing) */}\n <Route path=\"browse\" element={<DiscoveryPage />} />\n <Route path=\"title/:id\" element={<TitleViewPage />} />\n <Route path=\"watch/:titleId\" element={<PlayerPage />} />\n <Route path=\"watch/:titleId/episode/:episodeId\" element={<PlayerPage />} />\n <Route path=\"hooks\" element={gated('hookmovies.hooks.enabled', <HooksPage />)} />\n\n {/* Social — profiles & watch parties */}\n <Route path=\"profiles\" element={<ProfilesPage />} />\n <Route path=\"watch-party\" element={<WatchPartyListPage />} />\n <Route path=\"watch-party/:id\" element={<WatchPartyRoomPage />} />\n\n {/* Commerce — checkout & payouts */}\n <Route path=\"checkout/:titleId\" element={<CheckoutPage />} />\n <Route path=\"payouts\" element={<PayoutsPage />} />\n\n {/* Analytics */}\n <Route path=\"analytics\" element={<AnalyticsPage />} />\n\n {/* Trust & safety */}\n <Route path=\"trust/moderation\" element={<ModerationPage />} />\n\n {/* Onboarding */}\n <Route path=\"onboarding/languages\" element={<OnboardingPage />} />\n\n {/* Developer portal */}\n <Route path=\"developer\" element={<DevPortalPage />} />\n\n {/* Live — FAST channels */}\n <Route path=\"live\" element={gated('hookmovies.fast.enabled', <LivePage />)} />\n\n {/* Localization */}\n <Route path=\"title/:id/localization\" element={<LocalizationPage />} />\n\n {/* AI concierge */}\n <Route path=\"concierge\" element={gated('hookmovies.ai.concierge', <ConciergePage />)} />\n\n {/* Fallback */}\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HookMoviesRoutes.js","names":[],"sources":["../../src/hookmovies/HookMoviesRoutes.tsx"],"sourcesContent":["/**\n * HookMovies Routes\n * @module hookmovies\n *\n * Real domain routes for the HookMovies workspace product: catalog (titles,\n * studios, people), production lifecycle, casting auditions, audience\n * engagement (reviews), rights & distribution, and the user library (lists +\n * entitlements). All data comes from the live `hookmovies` subgraph.\n */\n\nimport { type FC, lazy, Suspense, type ReactNode, type ReactElement } from 'react';\nimport { Routes, Route, Navigate, useLocation } from 'react-router';\nimport { FeatureGate } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { useHookMovies } from './context/HookMoviesContext';\n\n// Eager — primary landing\nimport { HomePage } from './pages/HomePage';\n\n// Catalog\nconst TitlesPage = lazy(() =>\n import('./pages/catalog/TitlesPage').then((m) => ({ default: m.TitlesPage }))\n);\nconst TitleCreatePage = lazy(() =>\n import('./pages/catalog/TitleCreatePage').then((m) => ({ default: m.TitleCreatePage }))\n);\nconst TitleDetailPage = lazy(() =>\n import('./pages/catalog/TitleDetailPage').then((m) => ({ default: m.TitleDetailPage }))\n);\nconst StudiosPage = lazy(() =>\n import('./pages/catalog/StudiosPage').then((m) => ({ default: m.StudiosPage }))\n);\nconst PeoplePage = lazy(() =>\n import('./pages/catalog/PeoplePage').then((m) => ({ default: m.PeoplePage }))\n);\n\n// Productions\nconst ProductionsPage = lazy(() =>\n import('./pages/productions/ProductionsPage').then((m) => ({ default: m.ProductionsPage }))\n);\nconst ProductionCreatePage = lazy(() =>\n import('./pages/productions/ProductionCreatePage').then((m) => ({\n default: m.ProductionCreatePage,\n }))\n);\nconst ProductionDetailPage = lazy(() =>\n import('./pages/productions/ProductionDetailPage').then((m) => ({\n default: m.ProductionDetailPage,\n }))\n);\n\n// Auditions\nconst AuditionsPage = lazy(() =>\n import('./pages/auditions/AuditionsPage').then((m) => ({ default: m.AuditionsPage }))\n);\nconst AuditionCreatePage = lazy(() =>\n import('./pages/auditions/AuditionCreatePage').then((m) => ({ default: m.AuditionCreatePage }))\n);\nconst AuditionDetailPage = lazy(() =>\n import('./pages/auditions/AuditionDetailPage').then((m) => ({ default: m.AuditionDetailPage }))\n);\n\n// Engagement\nconst ReviewsPage = lazy(() =>\n import('./pages/engagement/ReviewsPage').then((m) => ({ default: m.ReviewsPage }))\n);\n\n// Distribution\nconst RightsWindowsPage = lazy(() =>\n import('./pages/distribution/RightsWindowsPage').then((m) => ({ default: m.RightsWindowsPage }))\n);\n\n// Library\nconst ListsPage = lazy(() =>\n import('./pages/library/ListsPage').then((m) => ({ default: m.ListsPage }))\n);\nconst EntitlementsPage = lazy(() =>\n import('./pages/library/EntitlementsPage').then((m) => ({ default: m.EntitlementsPage }))\n);\n\n// Consumer (audience-facing) — discovery, title view, playback, hooks feed\nconst DiscoveryPage = lazy(() =>\n import('./pages/consumer/DiscoveryPage').then((m) => ({ default: m.DiscoveryPage }))\n);\nconst TitleViewPage = lazy(() =>\n import('./pages/consumer/TitleViewPage').then((m) => ({ default: m.TitleViewPage }))\n);\nconst PlayerPage = lazy(() =>\n import('./pages/consumer/PlayerPage').then((m) => ({ default: m.PlayerPage }))\n);\nconst HooksPage = lazy(() =>\n import('./pages/consumer/HooksPage').then((m) => ({ default: m.HooksPage }))\n);\n\n// Social — viewing profiles & synchronized watch parties\nconst ProfilesPage = lazy(() =>\n import('./pages/social/ProfilesPage').then((m) => ({ default: m.ProfilesPage }))\n);\nconst WatchPartyListPage = lazy(() =>\n import('./pages/social/WatchPartyListPage').then((m) => ({ default: m.WatchPartyListPage }))\n);\nconst WatchPartyRoomPage = lazy(() =>\n import('./pages/social/WatchPartyRoomPage').then((m) => ({ default: m.WatchPartyRoomPage }))\n);\n\n// Commerce — checkout (TVOD purchase / rental) & creator payouts\nconst CheckoutPage = lazy(() =>\n import('./pages/commerce/CheckoutPage').then((m) => ({ default: m.CheckoutPage }))\n);\nconst PayoutsPage = lazy(() =>\n import('./pages/analytics/PayoutsPage').then((m) => ({ default: m.PayoutsPage }))\n);\n\n// Analytics — creator / operator performance dashboards\nconst AnalyticsPage = lazy(() =>\n import('./pages/analytics/AnalyticsPage').then((m) => ({ default: m.AnalyticsPage }))\n);\n\n// Trust & safety — moderation queue\nconst ModerationPage = lazy(() =>\n import('./pages/trust/ModerationPage').then((m) => ({ default: m.ModerationPage }))\n);\n\n// Onboarding — language / content preferences\nconst OnboardingPage = lazy(() =>\n import('./pages/onboarding/OnboardingPage').then((m) => ({ default: m.OnboardingPage }))\n);\n\n// Developer portal — API keys\nconst DevPortalPage = lazy(() =>\n import('./pages/developer/DevPortalPage').then((m) => ({ default: m.DevPortalPage }))\n);\n\n// Live — FAST linear channels & schedules\nconst LivePage = lazy(() => import('./pages/live/LivePage').then((m) => ({ default: m.LivePage })));\n\n// Localization — per-title subtitle / caption / dub track management\nconst LocalizationPage = lazy(() =>\n import('./pages/localization/LocalizationPage').then((m) => ({ default: m.LocalizationPage }))\n);\n\n// AI — concierge / recommendations assistant\nconst ConciergePage = lazy(() =>\n import('./pages/ai/ConciergePage').then((m) => ({ default: m.ConciergePage }))\n);\n\nconst PageLoader: FC = () => (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"h-8 w-8 animate-spin rounded-full border-b-2 border-action-primary-bg\" />\n </div>\n);\n\nconst FeatureDisabledFallback: FC = () => (\n <div className=\"flex min-h-[400px] flex-col items-center justify-center gap-2 px-6 text-center\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Coming soon</h2>\n <p className=\"max-w-sm text-sm text-text-secondary\">\n This feature is currently disabled for this workspace.\n </p>\n </div>\n);\n\n/**\n * Wrap a route element in a `FeatureGate` with the shared \"coming soon\"\n * fallback. `defaultValue={true}` keeps already-shipped screens visible\n * before their flag is seeded — seeding must never hide a working feature.\n */\nfunction gated(flag: string, element: ReactNode): ReactElement {\n return (\n <FeatureGate flag={flag} defaultValue={true} fallback={<FeatureDisabledFallback />}>\n {element}\n </FeatureGate>\n );\n}\n\nexport const HookMoviesRoutes: FC = () => {\n const { basePath, isStandalone } = useHookMovies();\n const location = useLocation();\n\n const normalizedBasePath = basePath === '/' ? '' : (basePath ?? '').replace(/\\/$/, '');\n\n if (normalizedBasePath && !isStandalone) {\n const pathMatches =\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + '/');\n\n if (!pathMatches) {\n return null;\n }\n }\n\n return (\n <div className=\"flex min-h-full flex-col\">\n <Suspense fallback={<PageLoader />}>\n <Routes>\n {/* Overview / dashboard */}\n <Route index element={<HomePage />} />\n\n {/* Catalog */}\n <Route path=\"catalog/titles\" element={<TitlesPage />} />\n <Route path=\"catalog/titles/new\" element={<TitleCreatePage />} />\n <Route path=\"catalog/titles/:id\" element={<TitleDetailPage />} />\n <Route path=\"catalog/studios\" element={<StudiosPage />} />\n <Route path=\"catalog/people\" element={<PeoplePage />} />\n\n {/* Productions */}\n <Route path=\"productions\" element={<ProductionsPage />} />\n <Route path=\"productions/new\" element={<ProductionCreatePage />} />\n <Route path=\"productions/:id\" element={<ProductionDetailPage />} />\n\n {/* Auditions */}\n <Route path=\"auditions\" element={<AuditionsPage />} />\n <Route path=\"auditions/new\" element={<AuditionCreatePage />} />\n <Route path=\"auditions/:id\" element={<AuditionDetailPage />} />\n\n {/* Engagement */}\n <Route path=\"engagement/reviews\" element={<ReviewsPage />} />\n\n {/* Distribution */}\n <Route path=\"distribution/rights\" element={<RightsWindowsPage />} />\n\n {/* Library */}\n <Route path=\"library/lists\" element={<ListsPage />} />\n <Route path=\"library/entitlements\" element={<EntitlementsPage />} />\n\n {/* Consumer (audience-facing) */}\n <Route path=\"browse\" element={<DiscoveryPage />} />\n <Route path=\"title/:id\" element={<TitleViewPage />} />\n <Route path=\"watch/:titleId\" element={<PlayerPage />} />\n <Route path=\"watch/:titleId/episode/:episodeId\" element={<PlayerPage />} />\n <Route path=\"hooks\" element={gated('hookmovies.hooks.enabled', <HooksPage />)} />\n\n {/* Social — profiles & watch parties */}\n <Route path=\"profiles\" element={<ProfilesPage />} />\n <Route path=\"watch-party\" element={<WatchPartyListPage />} />\n <Route path=\"watch-party/:id\" element={<WatchPartyRoomPage />} />\n\n {/* Commerce — checkout & payouts */}\n <Route path=\"checkout/:titleId\" element={<CheckoutPage />} />\n <Route path=\"payouts\" element={<PayoutsPage />} />\n\n {/* Analytics */}\n <Route path=\"analytics\" element={<AnalyticsPage />} />\n\n {/* Trust & safety */}\n <Route path=\"trust/moderation\" element={<ModerationPage />} />\n\n {/* Onboarding */}\n <Route path=\"onboarding/languages\" element={<OnboardingPage />} />\n\n {/* Developer portal */}\n <Route path=\"developer\" element={<DevPortalPage />} />\n\n {/* Live — FAST channels */}\n <Route path=\"live\" element={gated('hookmovies.fast.enabled', <LivePage />)} />\n\n {/* Localization */}\n <Route path=\"title/:id/localization\" element={<LocalizationPage />} />\n\n {/* AI concierge */}\n <Route path=\"concierge\" element={gated('hookmovies.ai.concierge', <ConciergePage />)} />\n\n {/* Fallback */}\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
|
|
3
|
+
interface AddToListButtonProps {
|
|
4
|
+
/** The catalog title to add / remove. */
|
|
5
|
+
titleId: string;
|
|
6
|
+
/** Used for accessible labels so the control reads well out of context. */
|
|
7
|
+
titleName?: string;
|
|
8
|
+
/**
|
|
9
|
+
* `cta` — a full labelled button for hero / detail call-to-action rows.
|
|
10
|
+
* `icon` — a compact square button for poster cards.
|
|
11
|
+
*/
|
|
12
|
+
variant?: 'cta' | 'icon';
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const AddToListButton: FC<AddToListButtonProps>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=AddToListButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AddToListButton.d.ts","sourceRoot":"","sources":["../../../src/hookmovies/components/AddToListButton.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,KAAK,EAAE,EAAuC,MAAM,OAAO,CAAC;AA8BrE,UAAU,oBAAoB;IAC5B,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,CA4SpD,CAAC"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { cn as e } from "../utils/cn.js";
|
|
2
|
+
import { parseListItems as t, useCreateList as n, useMyLists as r, useUpdateList as i } from "../hooks/useHookMoviesApi.js";
|
|
3
|
+
import { ErrorState as a, LoadingState as o } from "./StateViews.js";
|
|
4
|
+
import { useEffect as s, useState as c } from "react";
|
|
5
|
+
import { Bookmark as l, Check as u, ListPlus as d, ListVideo as f, Loader2 as p, Plus as m, X as h } from "lucide-react";
|
|
6
|
+
import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
7
|
+
//#region src/hookmovies/components/AddToListButton.tsx
|
|
8
|
+
var y = {
|
|
9
|
+
limit: 100,
|
|
10
|
+
offset: 0
|
|
11
|
+
}, b = ["WATCHLIST", "PLAYLIST"], x = {
|
|
12
|
+
WATCHLIST: l,
|
|
13
|
+
PLAYLIST: f
|
|
14
|
+
}, S = (e) => e.charAt(0) + e.slice(1).toLowerCase().replace(/_/g, " "), C = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]", w = "mb-1.5 block text-xs font-medium text-text-secondary", T = ({ titleId: l, titleName: f, variant: T = "cta", className: E }) => {
|
|
15
|
+
let [D, O] = c(!1), [k, A] = c(!1), [j, M] = c(null), [N, P] = c(null), [F, I] = c(""), [L, R] = c("WATCHLIST"), z = r(void 0, y), B = i(), V = n(), H = z.data?.items ?? [], U = H.filter((e) => t(e.items).some((e) => e.titleId === l)).length > 0;
|
|
16
|
+
s(() => {
|
|
17
|
+
if (!D) return;
|
|
18
|
+
let e = (e) => {
|
|
19
|
+
e.key === "Escape" && O(!1);
|
|
20
|
+
};
|
|
21
|
+
return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
|
|
22
|
+
}, [D]);
|
|
23
|
+
let W = () => {
|
|
24
|
+
O(!1), A(!1), P(null);
|
|
25
|
+
}, G = async (e) => {
|
|
26
|
+
P(null), M(e.id);
|
|
27
|
+
let n = t(e.items), r = n.some((e) => e.titleId === l) ? n.filter((e) => e.titleId !== l) : [...n, {
|
|
28
|
+
titleId: l,
|
|
29
|
+
note: null
|
|
30
|
+
}];
|
|
31
|
+
try {
|
|
32
|
+
await B.mutateAsync({
|
|
33
|
+
id: e.id,
|
|
34
|
+
input: { items: r }
|
|
35
|
+
});
|
|
36
|
+
} catch (e) {
|
|
37
|
+
P(e instanceof Error ? e.message : "Failed to update the list (you can only edit your own)");
|
|
38
|
+
} finally {
|
|
39
|
+
M(null);
|
|
40
|
+
}
|
|
41
|
+
}, K = async (e) => {
|
|
42
|
+
if (e.preventDefault(), P(null), !F.trim()) {
|
|
43
|
+
P("Name is required.");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
await V.mutateAsync({
|
|
48
|
+
name: F.trim(),
|
|
49
|
+
kind: L,
|
|
50
|
+
visibility: "PRIVATE",
|
|
51
|
+
items: [{
|
|
52
|
+
titleId: l,
|
|
53
|
+
note: null
|
|
54
|
+
}]
|
|
55
|
+
}), I(""), R("WATCHLIST"), A(!1);
|
|
56
|
+
} catch (e) {
|
|
57
|
+
P(e instanceof Error ? e.message : "Failed to create the list");
|
|
58
|
+
}
|
|
59
|
+
}, q = f ? ` ${f}` : "", J = U ? "In your lists" : "Add to List";
|
|
60
|
+
return /* @__PURE__ */ v(g, { children: [T === "icon" ? /* @__PURE__ */ _("button", {
|
|
61
|
+
type: "button",
|
|
62
|
+
onClick: () => O(!0),
|
|
63
|
+
"aria-label": `${J}${q ? ` —${q}` : ""}`,
|
|
64
|
+
title: J,
|
|
65
|
+
className: e("inline-flex size-8 items-center justify-center rounded-lg border border-border-seam", "bg-bg-overlay/80 text-text-secondary backdrop-blur-sm transition-colors", "hover:border-border-strong hover:text-text-primary", "focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]", U && "text-status-success-text", E),
|
|
66
|
+
children: _(U ? u : d, { className: "h-4 w-4" })
|
|
67
|
+
}) : /* @__PURE__ */ v("button", {
|
|
68
|
+
type: "button",
|
|
69
|
+
onClick: () => O(!0),
|
|
70
|
+
"aria-label": `${J}${q ? ` —${q}` : ""}`,
|
|
71
|
+
className: e("inline-flex items-center gap-2 rounded-xl border border-border-seam bg-bg-surface/60", "px-5 py-2.5 text-sm font-semibold text-text-primary backdrop-blur transition-colors", "hover:bg-bg-surface focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]", E),
|
|
72
|
+
children: [U ? /* @__PURE__ */ _(u, { className: "h-5 w-5 text-status-success-text" }) : /* @__PURE__ */ _(m, { className: "h-5 w-5" }), J]
|
|
73
|
+
}), D && /* @__PURE__ */ _("div", {
|
|
74
|
+
className: "fixed inset-0 z-50 flex items-center justify-center bg-bg-canvas/90 p-4 backdrop-blur-sm",
|
|
75
|
+
role: "dialog",
|
|
76
|
+
"aria-modal": "true",
|
|
77
|
+
"aria-label": `Add${q} to a list`,
|
|
78
|
+
onClick: W,
|
|
79
|
+
children: /* @__PURE__ */ v("div", {
|
|
80
|
+
className: "relative w-full max-w-md overflow-hidden rounded-2xl border border-border-seam bg-bg-surface shadow-2xl",
|
|
81
|
+
onClick: (e) => e.stopPropagation(),
|
|
82
|
+
children: [/* @__PURE__ */ v("div", {
|
|
83
|
+
className: "flex items-start justify-between gap-3 border-b border-border-seam px-5 py-4",
|
|
84
|
+
children: [/* @__PURE__ */ v("div", {
|
|
85
|
+
className: "min-w-0",
|
|
86
|
+
children: [/* @__PURE__ */ _("h2", {
|
|
87
|
+
className: "text-sm font-semibold text-text-primary",
|
|
88
|
+
children: "Add to a list"
|
|
89
|
+
}), /* @__PURE__ */ _("p", {
|
|
90
|
+
className: "mt-0.5 line-clamp-1 text-xs text-text-secondary",
|
|
91
|
+
children: f ?? "Pick one of your watchlists or playlists."
|
|
92
|
+
})]
|
|
93
|
+
}), /* @__PURE__ */ _("button", {
|
|
94
|
+
type: "button",
|
|
95
|
+
onClick: W,
|
|
96
|
+
"aria-label": "Close",
|
|
97
|
+
className: "rounded-md p-1 text-text-secondary transition-colors hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
98
|
+
children: /* @__PURE__ */ _(h, { className: "h-4 w-4" })
|
|
99
|
+
})]
|
|
100
|
+
}), /* @__PURE__ */ v("div", {
|
|
101
|
+
className: "px-5 py-4",
|
|
102
|
+
children: [
|
|
103
|
+
N && /* @__PURE__ */ _("div", {
|
|
104
|
+
role: "alert",
|
|
105
|
+
className: "mb-3 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text",
|
|
106
|
+
children: N
|
|
107
|
+
}),
|
|
108
|
+
z.isLoading ? /* @__PURE__ */ _(o, {
|
|
109
|
+
label: "Loading your lists…",
|
|
110
|
+
className: "min-h-[8rem]"
|
|
111
|
+
}) : z.isError ? /* @__PURE__ */ _(a, {
|
|
112
|
+
title: "Couldn't load your lists",
|
|
113
|
+
onRetry: () => void z.refetch(),
|
|
114
|
+
className: "min-h-[8rem]"
|
|
115
|
+
}) : H.length === 0 ? /* @__PURE__ */ _("p", {
|
|
116
|
+
className: "mb-3 text-sm text-text-secondary",
|
|
117
|
+
children: "You don't have any lists yet — create one below and this title goes straight into it."
|
|
118
|
+
}) : /* @__PURE__ */ _("ul", {
|
|
119
|
+
className: "-mx-1 max-h-[45vh] space-y-1 overflow-y-auto px-1",
|
|
120
|
+
children: H.map((n) => {
|
|
121
|
+
let r = x[n.kind], i = t(n.items).some((e) => e.titleId === l), a = j === n.id;
|
|
122
|
+
return /* @__PURE__ */ _("li", { children: /* @__PURE__ */ v("button", {
|
|
123
|
+
type: "button",
|
|
124
|
+
onClick: () => void G(n),
|
|
125
|
+
disabled: a,
|
|
126
|
+
"aria-pressed": i,
|
|
127
|
+
className: e("flex w-full items-center gap-3 rounded-lg border px-3 py-2 text-left transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]", "disabled:opacity-60", i ? "border-status-success-border bg-status-success-bg-subtle" : "border-border-subtle hover:border-border-strong hover:bg-bg-sunken"),
|
|
128
|
+
children: [
|
|
129
|
+
/* @__PURE__ */ _(r, { className: "h-4 w-4 shrink-0 text-text-secondary" }),
|
|
130
|
+
/* @__PURE__ */ v("span", {
|
|
131
|
+
className: "min-w-0 flex-1",
|
|
132
|
+
children: [/* @__PURE__ */ _("span", {
|
|
133
|
+
className: "line-clamp-1 block text-sm font-medium text-text-primary",
|
|
134
|
+
children: n.name
|
|
135
|
+
}), /* @__PURE__ */ v("span", {
|
|
136
|
+
className: "block text-[11px] text-text-secondary",
|
|
137
|
+
children: [
|
|
138
|
+
S(n.kind),
|
|
139
|
+
" · ",
|
|
140
|
+
n.itemCount,
|
|
141
|
+
" ",
|
|
142
|
+
n.itemCount === 1 ? "item" : "items"
|
|
143
|
+
]
|
|
144
|
+
})]
|
|
145
|
+
}),
|
|
146
|
+
a ? /* @__PURE__ */ _(p, { className: "h-4 w-4 shrink-0 animate-spin text-text-secondary" }) : i ? /* @__PURE__ */ _(u, { className: "h-4 w-4 shrink-0 text-status-success-text" }) : /* @__PURE__ */ _(m, { className: "h-4 w-4 shrink-0 text-text-secondary" })
|
|
147
|
+
]
|
|
148
|
+
}) }, n.id);
|
|
149
|
+
})
|
|
150
|
+
}),
|
|
151
|
+
!z.isLoading && !z.isError && /* @__PURE__ */ _("div", {
|
|
152
|
+
className: "mt-3 border-t border-border-seam pt-3",
|
|
153
|
+
children: k || H.length === 0 ? /* @__PURE__ */ v("form", {
|
|
154
|
+
onSubmit: (e) => void K(e),
|
|
155
|
+
className: "space-y-3",
|
|
156
|
+
children: [
|
|
157
|
+
/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("label", {
|
|
158
|
+
htmlFor: `add-to-list-name-${l}`,
|
|
159
|
+
className: w,
|
|
160
|
+
children: "New list name *"
|
|
161
|
+
}), /* @__PURE__ */ _("input", {
|
|
162
|
+
id: `add-to-list-name-${l}`,
|
|
163
|
+
type: "text",
|
|
164
|
+
value: F,
|
|
165
|
+
onChange: (e) => I(e.target.value),
|
|
166
|
+
placeholder: "e.g. Weekend Watch",
|
|
167
|
+
className: C,
|
|
168
|
+
autoFocus: !0,
|
|
169
|
+
required: !0
|
|
170
|
+
})] }),
|
|
171
|
+
/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("label", {
|
|
172
|
+
htmlFor: `add-to-list-kind-${l}`,
|
|
173
|
+
className: w,
|
|
174
|
+
children: "Kind"
|
|
175
|
+
}), /* @__PURE__ */ _("select", {
|
|
176
|
+
id: `add-to-list-kind-${l}`,
|
|
177
|
+
value: L,
|
|
178
|
+
onChange: (e) => R(e.target.value),
|
|
179
|
+
className: C,
|
|
180
|
+
children: b.map((e) => /* @__PURE__ */ _("option", {
|
|
181
|
+
value: e,
|
|
182
|
+
children: S(e)
|
|
183
|
+
}, e))
|
|
184
|
+
})] }),
|
|
185
|
+
/* @__PURE__ */ v("div", {
|
|
186
|
+
className: "flex items-center gap-2",
|
|
187
|
+
children: [/* @__PURE__ */ v("button", {
|
|
188
|
+
type: "submit",
|
|
189
|
+
disabled: V.isPending,
|
|
190
|
+
className: "inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-text transition-opacity hover:opacity-90 disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
191
|
+
children: [/* @__PURE__ */ _(m, { className: "h-3.5 w-3.5" }), V.isPending ? "Creating…" : "Create & add"]
|
|
192
|
+
}), H.length > 0 && /* @__PURE__ */ _("button", {
|
|
193
|
+
type: "button",
|
|
194
|
+
onClick: () => A(!1),
|
|
195
|
+
disabled: V.isPending,
|
|
196
|
+
className: "rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-secondary transition-colors hover:text-text-primary disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
197
|
+
children: "Cancel"
|
|
198
|
+
})]
|
|
199
|
+
})
|
|
200
|
+
]
|
|
201
|
+
}) : /* @__PURE__ */ v("button", {
|
|
202
|
+
type: "button",
|
|
203
|
+
onClick: () => A(!0),
|
|
204
|
+
className: "inline-flex items-center gap-2 text-xs font-medium text-text-secondary transition-colors hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] rounded",
|
|
205
|
+
children: [/* @__PURE__ */ _(m, { className: "h-3.5 w-3.5" }), "New list"]
|
|
206
|
+
})
|
|
207
|
+
})
|
|
208
|
+
]
|
|
209
|
+
})]
|
|
210
|
+
})
|
|
211
|
+
})] });
|
|
212
|
+
};
|
|
213
|
+
//#endregion
|
|
214
|
+
export { T as AddToListButton };
|
|
215
|
+
|
|
216
|
+
//# sourceMappingURL=AddToListButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AddToListButton.js","names":[],"sources":["../../../src/hookmovies/components/AddToListButton.tsx"],"sourcesContent":["/**\n * Add-to-list control\n * @module hookmovies/components\n *\n * The affordance that puts a title INTO one of the caller's library lists —\n * the write half of `library/lists`, which could previously only create empty\n * collections.\n *\n * The subgraph has no per-item add/remove mutation: `HokList.items` is an\n * ordered `JSON` array (`[{ titleId, note }]`) written wholesale through\n * `hokUpdateList`, which re-derives `itemCount` from its length. So every\n * toggle here reads the list's current items, adds/removes exactly one entry,\n * and writes the whole array back — untouched entries are always preserved.\n *\n * The picker is a centered modal rather than an anchored popover on purpose:\n * these triggers live inside horizontally-scrolling rails and `overflow`\n * containers that would clip a popover.\n */\n\nimport { type FC, type FormEvent, useEffect, useState } from 'react';\nimport { Bookmark, Check, ListPlus, ListVideo, Loader2, Plus, X } from 'lucide-react';\nimport {\n useMyLists,\n useCreateList,\n useUpdateList,\n parseListItems,\n type HokList,\n type HokListKind,\n} from '../hooks/useHookMoviesApi';\nimport { LoadingState, ErrorState } from './StateViews';\nimport { cn } from '../utils/cn';\n\n/** The subgraph clamps any list page at 100 rows — ask for exactly that. */\nconst LISTS_PAGE = { limit: 100, offset: 0 } as const;\n\nconst KIND_OPTIONS: HokListKind[] = ['WATCHLIST', 'PLAYLIST'];\n\nconst kindIcon: Record<HokListKind, typeof ListVideo> = {\n WATCHLIST: Bookmark,\n PLAYLIST: ListVideo,\n};\n\nconst titleCase = (value: string): string =>\n value.charAt(0) + value.slice(1).toLowerCase().replace(/_/g, ' ');\n\nconst fieldClass =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\nconst labelClass = 'mb-1.5 block text-xs font-medium text-text-secondary';\n\ninterface AddToListButtonProps {\n /** The catalog title to add / remove. */\n titleId: string;\n /** Used for accessible labels so the control reads well out of context. */\n titleName?: string;\n /**\n * `cta` — a full labelled button for hero / detail call-to-action rows.\n * `icon` — a compact square button for poster cards.\n */\n variant?: 'cta' | 'icon';\n className?: string;\n}\n\nexport const AddToListButton: FC<AddToListButtonProps> = ({\n titleId,\n titleName,\n variant = 'cta',\n className,\n}) => {\n const [open, setOpen] = useState(false);\n const [showCreate, setShowCreate] = useState(false);\n const [pendingListId, setPendingListId] = useState<string | null>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n const [newName, setNewName] = useState('');\n const [newKind, setNewKind] = useState<HokListKind>('WATCHLIST');\n\n const lists = useMyLists(undefined, LISTS_PAGE);\n const updateList = useUpdateList();\n const createList = useCreateList();\n\n const items = lists.data?.items ?? [];\n const memberOf = items.filter((list) =>\n parseListItems(list.items).some((item) => item.titleId === titleId)\n );\n const isMember = memberOf.length > 0;\n\n // Close the picker on Escape, mirroring the trailer modal on the title view.\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') setOpen(false);\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [open]);\n\n const closeModal = () => {\n setOpen(false);\n setShowCreate(false);\n setActionError(null);\n };\n\n const handleToggle = async (list: HokList) => {\n setActionError(null);\n setPendingListId(list.id);\n const current = parseListItems(list.items);\n const alreadyIn = current.some((item) => item.titleId === titleId);\n const next = alreadyIn\n ? current.filter((item) => item.titleId !== titleId)\n : [...current, { titleId, note: null }];\n try {\n await updateList.mutateAsync({ id: list.id, input: { items: next } });\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : 'Failed to update the list (you can only edit your own)'\n );\n } finally {\n setPendingListId(null);\n }\n };\n\n const handleCreate = async (e: FormEvent) => {\n e.preventDefault();\n setActionError(null);\n if (!newName.trim()) {\n setActionError('Name is required.');\n return;\n }\n try {\n await createList.mutateAsync({\n name: newName.trim(),\n kind: newKind,\n visibility: 'PRIVATE',\n items: [{ titleId, note: null }],\n });\n setNewName('');\n setNewKind('WATCHLIST');\n setShowCreate(false);\n } catch (err) {\n setActionError(err instanceof Error ? err.message : 'Failed to create the list');\n }\n };\n\n const forLabel = titleName ? ` ${titleName}` : '';\n const triggerLabel = isMember ? 'In your lists' : 'Add to List';\n\n return (\n <>\n {variant === 'icon' ? (\n <button\n type=\"button\"\n onClick={() => setOpen(true)}\n aria-label={`${triggerLabel}${forLabel ? ` —${forLabel}` : ''}`}\n title={triggerLabel}\n className={cn(\n 'inline-flex size-8 items-center justify-center rounded-lg border border-border-seam',\n 'bg-bg-overlay/80 text-text-secondary backdrop-blur-sm transition-colors',\n 'hover:border-border-strong hover:text-text-primary',\n 'focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]',\n isMember && 'text-status-success-text',\n className\n )}\n >\n {isMember ? <Check className=\"h-4 w-4\" /> : <ListPlus className=\"h-4 w-4\" />}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={() => setOpen(true)}\n aria-label={`${triggerLabel}${forLabel ? ` —${forLabel}` : ''}`}\n className={cn(\n 'inline-flex items-center gap-2 rounded-xl border border-border-seam bg-bg-surface/60',\n 'px-5 py-2.5 text-sm font-semibold text-text-primary backdrop-blur transition-colors',\n 'hover:bg-bg-surface focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]',\n className\n )}\n >\n {isMember ? (\n <Check className=\"h-5 w-5 text-status-success-text\" />\n ) : (\n <Plus className=\"h-5 w-5\" />\n )}\n {triggerLabel}\n </button>\n )}\n\n {open && (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-canvas/90 p-4 backdrop-blur-sm\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={`Add${forLabel} to a list`}\n onClick={closeModal}\n >\n <div\n className=\"relative w-full max-w-md overflow-hidden rounded-2xl border border-border-seam bg-bg-surface shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-start justify-between gap-3 border-b border-border-seam px-5 py-4\">\n <div className=\"min-w-0\">\n <h2 className=\"text-sm font-semibold text-text-primary\">Add to a list</h2>\n <p className=\"mt-0.5 line-clamp-1 text-xs text-text-secondary\">\n {titleName ?? 'Pick one of your watchlists or playlists.'}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={closeModal}\n aria-label=\"Close\"\n className=\"rounded-md p-1 text-text-secondary transition-colors hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n\n <div className=\"px-5 py-4\">\n {actionError && (\n <div\n role=\"alert\"\n className=\"mb-3 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\"\n >\n {actionError}\n </div>\n )}\n\n {lists.isLoading ? (\n <LoadingState label=\"Loading your lists…\" className=\"min-h-[8rem]\" />\n ) : lists.isError ? (\n <ErrorState\n title=\"Couldn't load your lists\"\n onRetry={() => void lists.refetch()}\n className=\"min-h-[8rem]\"\n />\n ) : items.length === 0 ? (\n <p className=\"mb-3 text-sm text-text-secondary\">\n You don't have any lists yet — create one below and this title goes straight\n into it.\n </p>\n ) : (\n <ul className=\"-mx-1 max-h-[45vh] space-y-1 overflow-y-auto px-1\">\n {items.map((list) => {\n const KindIcon = kindIcon[list.kind];\n const inList = parseListItems(list.items).some(\n (item) => item.titleId === titleId\n );\n const busy = pendingListId === list.id;\n return (\n <li key={list.id}>\n <button\n type=\"button\"\n onClick={() => void handleToggle(list)}\n disabled={busy}\n aria-pressed={inList}\n className={cn(\n 'flex w-full items-center gap-3 rounded-lg border px-3 py-2 text-left transition-colors',\n 'focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]',\n 'disabled:opacity-60',\n inList\n ? 'border-status-success-border bg-status-success-bg-subtle'\n : 'border-border-subtle hover:border-border-strong hover:bg-bg-sunken'\n )}\n >\n <KindIcon className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"line-clamp-1 block text-sm font-medium text-text-primary\">\n {list.name}\n </span>\n <span className=\"block text-[11px] text-text-secondary\">\n {titleCase(list.kind)} · {list.itemCount}{' '}\n {list.itemCount === 1 ? 'item' : 'items'}\n </span>\n </span>\n {busy ? (\n <Loader2 className=\"h-4 w-4 shrink-0 animate-spin text-text-secondary\" />\n ) : inList ? (\n <Check className=\"h-4 w-4 shrink-0 text-status-success-text\" />\n ) : (\n <Plus className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n )}\n </button>\n </li>\n );\n })}\n </ul>\n )}\n\n {!lists.isLoading && !lists.isError && (\n <div className=\"mt-3 border-t border-border-seam pt-3\">\n {showCreate || items.length === 0 ? (\n <form onSubmit={(e) => void handleCreate(e)} className=\"space-y-3\">\n <div>\n <label htmlFor={`add-to-list-name-${titleId}`} className={labelClass}>\n New list name *\n </label>\n <input\n id={`add-to-list-name-${titleId}`}\n type=\"text\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n placeholder=\"e.g. Weekend Watch\"\n className={fieldClass}\n autoFocus\n required\n />\n </div>\n <div>\n <label htmlFor={`add-to-list-kind-${titleId}`} className={labelClass}>\n Kind\n </label>\n <select\n id={`add-to-list-kind-${titleId}`}\n value={newKind}\n onChange={(e) => setNewKind(e.target.value as HokListKind)}\n className={fieldClass}\n >\n {KIND_OPTIONS.map((k) => (\n <option key={k} value={k}>\n {titleCase(k)}\n </option>\n ))}\n </select>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"submit\"\n disabled={createList.isPending}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-text transition-opacity hover:opacity-90 disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <Plus className=\"h-3.5 w-3.5\" />\n {createList.isPending ? 'Creating…' : 'Create & add'}\n </button>\n {items.length > 0 && (\n <button\n type=\"button\"\n onClick={() => setShowCreate(false)}\n disabled={createList.isPending}\n className=\"rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-secondary transition-colors hover:text-text-primary disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n Cancel\n </button>\n )}\n </div>\n </form>\n ) : (\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"inline-flex items-center gap-2 text-xs font-medium text-text-secondary transition-colors hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] rounded\"\n >\n <Plus className=\"h-3.5 w-3.5\" />\n New list\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n </>\n );\n};\n"],"mappings":"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"}
|
|
@@ -9,4 +9,5 @@ export { RatingDisplay } from './RatingDisplay';
|
|
|
9
9
|
export { EmptyState } from './EmptyState';
|
|
10
10
|
export { LoadingState, ErrorState } from './StateViews';
|
|
11
11
|
export { Pagination } from './Pagination';
|
|
12
|
+
export { AddToListButton } from './AddToListButton';
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hookmovies/components/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hookmovies/components/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { joinPath as e } from "../utils/navigation.js";
|
|
2
2
|
import { createContext as t, useCallback as n, useContext as r, useMemo as i, useState as a } from "react";
|
|
3
|
-
import { MemoryRouter as o, useNavigate as s } from "react-router
|
|
3
|
+
import { MemoryRouter as o, useNavigate as s } from "react-router";
|
|
4
4
|
import { jsx as c } from "react/jsx-runtime";
|
|
5
5
|
//#region src/hookmovies/context/HookMoviesContext.tsx
|
|
6
6
|
var l = t(null), u = (e) => `hookmovies:activeProfile:${e ?? "default"}`, d = (e) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HookMoviesContext.js","names":[],"sources":["../../../src/hookmovies/context/HookMoviesContext.tsx"],"sourcesContent":["/**\n * HookMovies Context Provider\n * @module hookmovies/context\n */\n\nimport type { FC, PropsWithChildren } from 'react';\nimport { createContext, useContext, useMemo, useCallback, useState } from 'react';\nimport { MemoryRouter, useNavigate as useRouterNavigate } from 'react-router
|
|
1
|
+
{"version":3,"file":"HookMoviesContext.js","names":[],"sources":["../../../src/hookmovies/context/HookMoviesContext.tsx"],"sourcesContent":["/**\n * HookMovies Context Provider\n * @module hookmovies/context\n */\n\nimport type { FC, PropsWithChildren } from 'react';\nimport { createContext, useContext, useMemo, useCallback, useState } from 'react';\nimport { MemoryRouter, useNavigate as useRouterNavigate } from 'react-router';\nimport type { HookMoviesRootProps } from '../types';\nimport { joinPath } from '../utils/navigation';\n\n// ============================================================================\n// Context\n// ============================================================================\n\ninterface HookMoviesContextValue extends Omit<\n HookMoviesRootProps,\n 'registerNavItems' | 'registerFooterItems' | 'navigate'\n> {\n isStandalone: boolean;\n /** Shell's navigate function (only available in integrated mode) */\n navigate?: (path: string) => void;\n /** Navigate to a path relative to basePath */\n navigateTo: (relativePath: string) => void;\n /** Get the full path for a relative path */\n getPath: (relativePath: string) => string;\n /**\n * Id of the currently selected viewing profile (Netflix-style per-account\n * profile), or `null` when none is chosen. Persisted to localStorage,\n * scoped per workspace. Consumer surfaces gate on this (e.g. the player and\n * discovery use it to apply the profile's language / maturity preferences).\n */\n activeProfileId: string | null;\n /** Select (or clear, with `null`) the active viewing profile; persists it. */\n setActiveProfile: (profileId: string | null) => void;\n}\n\nconst HookMoviesContext = createContext<HookMoviesContextValue | null>(null);\n\n// ============================================================================\n// Active profile persistence (localStorage, workspace-scoped)\n// ============================================================================\n\nconst activeProfileStorageKey = (workspaceId?: string): string =>\n `hookmovies:activeProfile:${workspaceId ?? 'default'}`;\n\nconst readStoredActiveProfile = (workspaceId?: string): string | null => {\n if (typeof window === 'undefined') return null;\n try {\n return window.localStorage.getItem(activeProfileStorageKey(workspaceId));\n } catch {\n return null;\n }\n};\n\n/**\n * State + persistence for the active viewing profile. Reads the initial value\n * from localStorage (per workspace) and writes through on every change.\n */\nfunction useActiveProfileState(\n workspaceId?: string\n): [string | null, (profileId: string | null) => void] {\n const [activeProfileId, setActiveProfileId] = useState<string | null>(() =>\n readStoredActiveProfile(workspaceId)\n );\n\n const setActiveProfile = useCallback(\n (profileId: string | null) => {\n setActiveProfileId(profileId);\n if (typeof window === 'undefined') return;\n try {\n const key = activeProfileStorageKey(workspaceId);\n if (profileId) {\n window.localStorage.setItem(key, profileId);\n } else {\n window.localStorage.removeItem(key);\n }\n } catch {\n // Ignore storage failures (private mode / quota) — in-memory state still works.\n }\n },\n [workspaceId]\n );\n\n return [activeProfileId, setActiveProfile];\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function useHookMovies(): HookMoviesContextValue {\n const context = useContext(HookMoviesContext);\n if (!context) {\n throw new Error('useHookMovies must be used within a HookMoviesProvider');\n }\n return context;\n}\n\n// ============================================================================\n// Provider Component\n// ============================================================================\n\ntype ProviderProps = Omit<HookMoviesRootProps, 'registerNavItems' | 'registerFooterItems'> & {\n isStandalone: boolean;\n};\n\n/** Provider for standalone mode (has access to MemoryRouter) */\nconst StandaloneProviderInner: FC<PropsWithChildren<ProviderProps>> = ({\n children,\n basePath,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n}) => {\n const routerNavigate = useRouterNavigate();\n const effectiveBasePath = basePath || '/';\n const [activeProfileId, setActiveProfile] = useActiveProfileState(workspaceId);\n\n const getPath = useCallback(\n (relativePath: string) => joinPath(effectiveBasePath, relativePath),\n [effectiveBasePath]\n );\n\n const navigateTo = useCallback(\n (relativePath: string) => {\n const fullPath = joinPath(effectiveBasePath, relativePath);\n routerNavigate(fullPath);\n },\n [effectiveBasePath, routerNavigate]\n );\n\n const contextValue = useMemo<HookMoviesContextValue>(\n () => ({\n basePath: effectiveBasePath,\n navigate: undefined,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n isStandalone: true,\n navigateTo,\n getPath,\n activeProfileId,\n setActiveProfile,\n }),\n [\n effectiveBasePath,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n navigateTo,\n getPath,\n activeProfileId,\n setActiveProfile,\n ]\n );\n\n return <HookMoviesContext.Provider value={contextValue}>{children}</HookMoviesContext.Provider>;\n};\n\n/** Provider for integrated mode (shell provides navigate) */\nconst IntegratedProviderInner: FC<\n PropsWithChildren<ProviderProps & { navigate: (path: string) => void }>\n> = ({\n children,\n basePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n}) => {\n const effectiveBasePath = basePath || '/';\n const [activeProfileId, setActiveProfile] = useActiveProfileState(workspaceId);\n\n const getPath = useCallback(\n (relativePath: string) => joinPath(effectiveBasePath, relativePath),\n [effectiveBasePath]\n );\n\n const navigateTo = useCallback(\n (relativePath: string) => {\n const fullPath = joinPath(effectiveBasePath, relativePath);\n navigate(fullPath);\n },\n [effectiveBasePath, navigate]\n );\n\n const contextValue = useMemo<HookMoviesContextValue>(\n () => ({\n basePath: effectiveBasePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n isStandalone: false,\n navigateTo,\n getPath,\n activeProfileId,\n setActiveProfile,\n }),\n [\n effectiveBasePath,\n navigate,\n currentUser,\n tenantId,\n workspaceId,\n apiGatewayUrl,\n authToken,\n navigateTo,\n getPath,\n activeProfileId,\n setActiveProfile,\n ]\n );\n\n return <HookMoviesContext.Provider value={contextValue}>{children}</HookMoviesContext.Provider>;\n};\n\nexport const HookMoviesProvider: FC<PropsWithChildren<HookMoviesRootProps>> = (props) => {\n const { children, navigate } = props;\n // Standalone mode: no navigate function provided (MFE manages its own router)\n // Integrated mode: navigate function provided by shell (shell provides router)\n const isStandalone = !navigate;\n\n // Standalone mode: wrap in MemoryRouter\n if (isStandalone) {\n return (\n <MemoryRouter>\n <StandaloneProviderInner {...props} isStandalone={true}>\n {children}\n </StandaloneProviderInner>\n </MemoryRouter>\n );\n }\n\n // Integrated mode: shell provides router\n return (\n <IntegratedProviderInner {...props} navigate={navigate} isStandalone={false}>\n {children}\n </IntegratedProviderInner>\n );\n};\n"],"mappings":";;;;;AAqCA,IAAM,IAAoB,EAA6C,KAAK,EAMtE,KAA2B,MAC/B,4BAA4B,KAAe,aAEvC,KAA2B,MAAwC;AACvE,KAAI,OAAO,SAAW,IAAa,QAAO;AAC1C,KAAI;AACF,SAAO,OAAO,aAAa,QAAQ,EAAwB,EAAY,CAAC;SAClE;AACN,SAAO;;;AAQX,SAAS,EACP,GACqD;CACrD,IAAM,CAAC,GAAiB,KAAsB,QAC5C,EAAwB,EAAY,CACrC;AAoBD,QAAO,CAAC,GAlBiB,GACtB,MAA6B;AAC5B,QAAmB,EAAU,EACzB,SAAO,SAAW,KACtB,KAAI;GACF,IAAM,IAAM,EAAwB,EAAY;AAChD,GAAI,IACF,OAAO,aAAa,QAAQ,GAAK,EAAU,GAE3C,OAAO,aAAa,WAAW,EAAI;UAE/B;IAIV,CAAC,EAAY,CACd,CAEyC;;AAO5C,SAAgB,IAAwC;CACtD,IAAM,IAAU,EAAW,EAAkB;AAC7C,KAAI,CAAC,EACH,OAAU,MAAM,yDAAyD;AAE3E,QAAO;;AAYT,IAAM,KAAiE,EACrE,aACA,aACA,gBACA,aACA,gBACA,kBACA,mBACI;CACJ,IAAM,IAAiB,GAAmB,EACpC,IAAoB,KAAY,KAChC,CAAC,GAAiB,KAAoB,EAAsB,EAAY,EAExE,IAAU,GACb,MAAyB,EAAS,GAAmB,EAAa,EACnE,CAAC,EAAkB,CACpB,EAEK,IAAa,GAChB,MAAyB;AAExB,IADiB,EAAS,GAAmB,EAAa,CAClC;IAE1B,CAAC,GAAmB,EAAe,CACpC,EAEK,IAAe,SACZ;EACL,UAAU;EACV,UAAU,KAAA;EACV;EACA;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;EACA;EACA;EACD,GACD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,QAAO,kBAAC,EAAkB,UAAnB;EAA4B,OAAO;EAAe;EAAsC,CAAA;GAI3F,KAED,EACH,aACA,aACA,aACA,gBACA,aACA,gBACA,kBACA,mBACI;CACJ,IAAM,IAAoB,KAAY,KAChC,CAAC,GAAiB,KAAoB,EAAsB,EAAY,EAExE,IAAU,GACb,MAAyB,EAAS,GAAmB,EAAa,EACnE,CAAC,EAAkB,CACpB,EAEK,IAAa,GAChB,MAAyB;AAExB,IADiB,EAAS,GAAmB,EAAa,CACxC;IAEpB,CAAC,GAAmB,EAAS,CAC9B,EAEK,IAAe,SACZ;EACL,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;EACA;EACA;EACD,GACD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;AAED,QAAO,kBAAC,EAAkB,UAAnB;EAA4B,OAAO;EAAe;EAAsC,CAAA;GAGpF,KAAkE,MAAU;CACvF,IAAM,EAAE,aAAU,gBAAa;AAiB/B,QAdsB,IAepB,kBAAC,GAAD;EAAyB,GAAI;EAAiB;EAAU,cAAc;EACnE;EACuB,CAAA,GAZxB,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EAAyB,GAAI;EAAO,cAAc;EAC/C;EACuB,CAAA,EACb,CAAA"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* HookMovies hooks barrel
|
|
3
3
|
* @module hookmovies/hooks
|
|
4
4
|
*/
|
|
5
|
-
export { useTitles, useTitle, useCreateTitle, useUpdateTitle, useTransitionTitle, useArchiveTitle, useStudios, useCreateStudio, usePeople, useCreatePerson, useProductions, useProduction, useCreateProduction, useTransitionProduction, useAuditions, useAuditionById, useAuditionApplications, useCreateAudition, useCloseAudition, useApplyToAudition, useScoreApplication, useReviews, useCreateReview, useDeleteReview, useRightsWindows, useCreateRightsWindow, useTransitionRightsWindow, useMyEntitlements, useRevokeEntitlement, useMyLists, useCreateList, useUpdateList, useDeleteList, useMyWatchProgress, useRecordProgress, useAddCredit, useCreateSeason, useCreateEpisode, useCheckEntitlement, useGrantEntitlement, useHealth, } from './useHookMoviesApi';
|
|
6
|
-
export type { HokPaginationInput, HokPageInfo, HokTitleType, HokTitleStatus, HokProductionStatus, HokAuditionStatus, HokApplicationStatus, HokCreditRole, HokReviewStatus, HokRightsWindowStatus, HokMonetizationMode, HokEntitlementSource, HokEntitlementStatus, HokListKind, HokListVisibility, HokStudio, HokPerson, HokCredit, HokEpisodeSummary, HokSeasonSummary, HokTitle, HokTitleDetail, HokProduction, HokProductionDetail, HokAudition, HokAuditionSummary, HokApplication, HokReview, HokRightsWindow, HokEntitlement, HokList, HokWatchProgress, HokTitleFilters, HokProductionFilters, HokAuditionFilters, HokReviewFilters, HokRightsFilters, CreateTitleInput, UpdateTitleInput, CreateStudioInput, CreatePersonInput, CreateProductionInput, CreateAuditionInput, ApplyToAuditionInput, CreateReviewInput, CreateRightsWindowInput, CreateListInput, HokSeason, HokEpisode, HokEntitlementCheck, HokCreateCreditInput, HokCreateSeasonInput, HokCreateEpisodeInput, HokRecordProgressInput, HokGrantEntitlementInput, HokUpdateListInput, } from './useHookMoviesApi';
|
|
5
|
+
export { useTitles, useTitle, useTitlesByIds, useCreateTitle, useUpdateTitle, useTransitionTitle, useArchiveTitle, useStudios, useCreateStudio, usePeople, useCreatePerson, useProductions, useProduction, useCreateProduction, useTransitionProduction, useAuditions, useAuditionById, useAuditionApplications, useCreateAudition, useCloseAudition, useApplyToAudition, useScoreApplication, useReviews, useCreateReview, useDeleteReview, useRightsWindows, useCreateRightsWindow, useTransitionRightsWindow, useMyEntitlements, useRevokeEntitlement, useMyLists, useCreateList, useUpdateList, useDeleteList, parseListItems, useMyWatchProgress, useRecordProgress, useAddCredit, useCreateSeason, useCreateEpisode, useCheckEntitlement, useGrantEntitlement, useHealth, } from './useHookMoviesApi';
|
|
6
|
+
export type { HokPaginationInput, HokPageInfo, HokTitleType, HokTitleStatus, HokProductionStatus, HokAuditionStatus, HokApplicationStatus, HokCreditRole, HokReviewStatus, HokRightsWindowStatus, HokMonetizationMode, HokEntitlementSource, HokEntitlementStatus, HokListKind, HokListVisibility, HokStudio, HokPerson, HokCredit, HokEpisodeSummary, HokSeasonSummary, HokTitle, HokTitleDetail, HokProduction, HokProductionDetail, HokAudition, HokAuditionSummary, HokApplication, HokReview, HokRightsWindow, HokEntitlement, HokList, HokListItem, HokWatchProgress, HokTitleFilters, HokProductionFilters, HokAuditionFilters, HokReviewFilters, HokRightsFilters, CreateTitleInput, UpdateTitleInput, CreateStudioInput, CreatePersonInput, CreateProductionInput, CreateAuditionInput, ApplyToAuditionInput, CreateReviewInput, CreateRightsWindowInput, CreateListInput, HokSeason, HokEpisode, HokEntitlementCheck, HokCreateCreditInput, HokCreateSeasonInput, HokCreateEpisodeInput, HokRecordProgressInput, HokGrantEntitlementInput, HokUpdateListInput, } from './useHookMoviesApi';
|
|
7
7
|
export { uploadFileToFiles, useFileUrl, FILE_FOLDERS } from './useFiles';
|
|
8
8
|
export type { UploadedFile } from './useFiles';
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hookmovies/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEL,SAAS,EACT,QAAQ,EACR,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,eAAe,EAEf,UAAU,EACV,eAAe,EAEf,SAAS,EACT,eAAe,EAEf,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,uBAAuB,EAEvB,YAAY,EACZ,eAAe,EACf,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EAEnB,UAAU,EACV,eAAe,EACf,eAAe,EAEf,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,oBAAoB,EAEpB,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EAEjB,YAAY,EAEZ,eAAe,EACf,gBAAgB,EAEhB,mBAAmB,EACnB,mBAAmB,EAEnB,SAAS,GACV,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EACV,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,SAAS,EACT,eAAe,EACf,cAAc,EACd,OAAO,EACP,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,eAAe,EACf,SAAS,EACT,UAAU,EACV,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACzE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hookmovies/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEL,SAAS,EACT,QAAQ,EACR,cAAc,EACd,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,eAAe,EAEf,UAAU,EACV,eAAe,EAEf,SAAS,EACT,eAAe,EAEf,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,uBAAuB,EAEvB,YAAY,EACZ,eAAe,EACf,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EAEnB,UAAU,EACV,eAAe,EACf,eAAe,EAEf,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,oBAAoB,EAEpB,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EAEjB,YAAY,EAEZ,eAAe,EACf,gBAAgB,EAEhB,mBAAmB,EACnB,mBAAmB,EAEnB,SAAS,GACV,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EACV,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,SAAS,EACT,eAAe,EACf,cAAc,EACd,OAAO,EACP,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,eAAe,EACf,SAAS,EACT,UAAU,EACV,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACzE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -216,6 +216,18 @@ export interface HokEntitlement {
|
|
|
216
216
|
updatedAt: string;
|
|
217
217
|
title: Pick<HokTitle, 'id' | 'title'> | null;
|
|
218
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* One entry in a list's ordered contents.
|
|
221
|
+
*
|
|
222
|
+
* `HokList.items` is a `JSON` column on the subgraph (`wspace-hookmovies-svc`
|
|
223
|
+
* documents it as "Ordered title ids with optional notes ([{titleId, note}])"),
|
|
224
|
+
* so the wire value is untyped. Never cast it — run it through
|
|
225
|
+
* {@link parseListItems}, which drops anything that isn't a well-formed entry.
|
|
226
|
+
*/
|
|
227
|
+
export interface HokListItem {
|
|
228
|
+
titleId: string;
|
|
229
|
+
note: string | null;
|
|
230
|
+
}
|
|
219
231
|
export interface HokList {
|
|
220
232
|
id: string;
|
|
221
233
|
name: string;
|
|
@@ -224,9 +236,18 @@ export interface HokList {
|
|
|
224
236
|
visibility: HokListVisibility;
|
|
225
237
|
ownerId: string;
|
|
226
238
|
itemCount: number;
|
|
239
|
+
/** Raw `JSON` payload — read it with {@link parseListItems}. */
|
|
240
|
+
items: unknown;
|
|
227
241
|
createdAt: string;
|
|
228
242
|
updatedAt: string;
|
|
229
243
|
}
|
|
244
|
+
/**
|
|
245
|
+
* Validate the raw `HokList.items` JSON into typed entries, preserving the
|
|
246
|
+
* stored order. Malformed entries (anything without a non-empty string
|
|
247
|
+
* `titleId`) are dropped rather than guessed at, so the UI never renders an
|
|
248
|
+
* invented row.
|
|
249
|
+
*/
|
|
250
|
+
export declare const parseListItems: (items: unknown) => HokListItem[];
|
|
230
251
|
export interface HokWatchProgress {
|
|
231
252
|
id: string;
|
|
232
253
|
titleId: string;
|
|
@@ -235,7 +256,12 @@ export interface HokWatchProgress {
|
|
|
235
256
|
completed: boolean;
|
|
236
257
|
lastDevice: string | null;
|
|
237
258
|
updatedAt: string;
|
|
238
|
-
|
|
259
|
+
/**
|
|
260
|
+
* `runtimeMinutes` rides along so resume surfaces can show real percent
|
|
261
|
+
* progress; it is nullable on the schema, so treat "no runtime" as
|
|
262
|
+
* "percentage unknown" rather than assuming a duration.
|
|
263
|
+
*/
|
|
264
|
+
title: Pick<HokTitle, 'id' | 'title' | 'type' | 'runtimeMinutes'> | null;
|
|
239
265
|
}
|
|
240
266
|
interface HokConnection<TItem> {
|
|
241
267
|
items: TItem[];
|
|
@@ -250,6 +276,20 @@ export interface HokTitleFilters {
|
|
|
250
276
|
}
|
|
251
277
|
export declare const useTitles: (filters?: HokTitleFilters, pagination?: HokPaginationInput, search?: string) => import('@tanstack/react-query').UseQueryResult<NoInfer<HokConnection<HokTitle>>, Error>;
|
|
252
278
|
export declare const useTitle: (id: string | undefined) => import('@tanstack/react-query').UseQueryResult<NoInfer<HokTitleDetail | null>, Error>;
|
|
279
|
+
/**
|
|
280
|
+
* Resolve an arbitrary set of title ids in ONE round trip.
|
|
281
|
+
*
|
|
282
|
+
* `hokListTitles` filters by search/type/status/studio but has no id filter, so
|
|
283
|
+
* a stored id set (a library list's `items`) can only be resolved through the
|
|
284
|
+
* `hokTitle(id:)` root field. Aliasing it once per id keeps that to a single
|
|
285
|
+
* request instead of one per row. Aliases are positional (`t0`, `t1`, …) so no
|
|
286
|
+
* caller-supplied text ever reaches the document.
|
|
287
|
+
*
|
|
288
|
+
* Ids the caller can't read (unpublished, deleted, out of scope) come back
|
|
289
|
+
* `null` and are simply absent from the returned map — callers must render that
|
|
290
|
+
* as "unavailable", never silently drop the row.
|
|
291
|
+
*/
|
|
292
|
+
export declare const useTitlesByIds: (ids: string[]) => import('@tanstack/react-query').UseQueryResult<NoInfer<Map<string, HokTitle>>, Error>;
|
|
253
293
|
export interface CreateTitleInput {
|
|
254
294
|
title: string;
|
|
255
295
|
type?: HokTitleType;
|
|
@@ -417,7 +457,8 @@ export interface CreateListInput {
|
|
|
417
457
|
description?: string;
|
|
418
458
|
kind?: HokListKind;
|
|
419
459
|
visibility?: HokListVisibility;
|
|
420
|
-
|
|
460
|
+
/** Ordered contents — the subgraph derives `itemCount` from this array. */
|
|
461
|
+
items?: HokListItem[];
|
|
421
462
|
}
|
|
422
463
|
export declare const useCreateList: () => import('@tanstack/react-query').UseMutationResult<HokList, Error, CreateListInput, unknown>;
|
|
423
464
|
export declare const useDeleteList: () => import('@tanstack/react-query').UseMutationResult<boolean, Error, string, unknown>;
|
|
@@ -503,7 +544,13 @@ export interface HokUpdateListInput {
|
|
|
503
544
|
name?: string;
|
|
504
545
|
description?: string;
|
|
505
546
|
visibility?: HokListVisibility;
|
|
506
|
-
|
|
547
|
+
/**
|
|
548
|
+
* Replaces the whole ordered contents array (the subgraph has no per-item
|
|
549
|
+
* add/remove mutation), and re-derives `itemCount` from its length. Always
|
|
550
|
+
* build it from the list's current {@link parseListItems} output so a write
|
|
551
|
+
* never drops entries the caller didn't touch.
|
|
552
|
+
*/
|
|
553
|
+
items?: HokListItem[];
|
|
507
554
|
}
|
|
508
555
|
/** Rename / re-scope / re-order a list's items; invalidates the caller's lists. */
|
|
509
556
|
export declare const useUpdateList: () => import('@tanstack/react-query').UseMutationResult<HokList, Error, {
|