@fluid-app/portal-sdk 0.1.218 → 0.1.220

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.
Files changed (80) hide show
  1. package/dist/{AppDownloadScreen-CZ0EOIZ5.mjs → AppDownloadScreen-Bhix461K.mjs} +1 -1
  2. package/dist/{AppDownloadScreen-CZ0EOIZ5.mjs.map → AppDownloadScreen-Bhix461K.mjs.map} +1 -1
  3. package/dist/{AppDownloadScreen-CBoC31wL.cjs → AppDownloadScreen-DwBzuPcF.cjs} +1 -1
  4. package/dist/{AppDownloadScreen-CBoC31wL.cjs.map → AppDownloadScreen-DwBzuPcF.cjs.map} +1 -1
  5. package/dist/{FluidProvider-22PONJDa.mjs → FluidProvider-DTttgSXi.mjs} +2 -2
  6. package/dist/{FluidProvider-22PONJDa.mjs.map → FluidProvider-DTttgSXi.mjs.map} +1 -1
  7. package/dist/{FluidProvider-DTdi38VO.cjs → FluidProvider-Dm4BhF_t.cjs} +2 -2
  8. package/dist/{FluidProvider-DTdi38VO.cjs.map → FluidProvider-Dm4BhF_t.cjs.map} +1 -1
  9. package/dist/{MessagingScreen-BM21ZxGL.mjs → MessagingScreen-CwEXQJlW.mjs} +2 -2
  10. package/dist/{MessagingScreen-BM21ZxGL.mjs.map → MessagingScreen-CwEXQJlW.mjs.map} +1 -1
  11. package/dist/{MessagingScreen-ehHW4LwI.cjs → MessagingScreen-DLQ5V0m4.cjs} +2 -2
  12. package/dist/{MessagingScreen-ehHW4LwI.cjs.map → MessagingScreen-DLQ5V0m4.cjs.map} +1 -1
  13. package/dist/{MessagingScreen-BDlC9VWJ.cjs → MessagingScreen-YBXJL7a9.cjs} +2 -2
  14. package/dist/{MySiteScreen-DUN5TTvU.mjs → MySiteScreen-BAPWqDfm.mjs} +11 -31
  15. package/dist/{MySiteScreen-DUN5TTvU.mjs.map → MySiteScreen-BAPWqDfm.mjs.map} +1 -1
  16. package/dist/{MySiteScreen-B0aOIzU4.cjs → MySiteScreen-CEX1qxdj.cjs} +2 -3
  17. package/dist/{MySiteScreen-B1L8coGs.cjs → MySiteScreen-DaNlmVSi.cjs} +24 -44
  18. package/dist/MySiteScreen-DaNlmVSi.cjs.map +1 -0
  19. package/dist/{PortalProductsApiProvider-CE71zDj9.mjs → PortalProductsApiProvider-BwIRudl_.mjs} +1 -1
  20. package/dist/{PortalProductsApiProvider-CE71zDj9.mjs.map → PortalProductsApiProvider-BwIRudl_.mjs.map} +1 -1
  21. package/dist/{PortalProductsApiProvider-Ca1oeTtJ.cjs → PortalProductsApiProvider-CRaocswH.cjs} +1 -1
  22. package/dist/{PortalProductsApiProvider-Ca1oeTtJ.cjs.map → PortalProductsApiProvider-CRaocswH.cjs.map} +1 -1
  23. package/dist/{ProfileScreen-DNRpWpex.cjs → ProfileScreen-B0WRifk_.cjs} +2 -2
  24. package/dist/{ProfileScreen-DNRpWpex.cjs.map → ProfileScreen-B0WRifk_.cjs.map} +1 -1
  25. package/dist/{ProfileScreen-VonnJyFa.mjs → ProfileScreen-BuejQU_V.mjs} +2 -2
  26. package/dist/{ProfileScreen-VonnJyFa.mjs.map → ProfileScreen-BuejQU_V.mjs.map} +1 -1
  27. package/dist/{ProfileScreen-CN1DDd-Q.cjs → ProfileScreen-g3se9Jw-.cjs} +2 -2
  28. package/dist/{ShareablesScreen-smU5pGyH.cjs → ShareablesScreen-CqvPzH1v.cjs} +3 -5
  29. package/dist/{PortalContentApiProvider-C9FeVwRb.mjs → ShareablesScreen-DV2nikzp.mjs} +460 -119
  30. package/dist/ShareablesScreen-DV2nikzp.mjs.map +1 -0
  31. package/dist/{PortalContentApiProvider-RXBp8FNj.cjs → ShareablesScreen-DwnMBftJ.cjs} +457 -156
  32. package/dist/ShareablesScreen-DwnMBftJ.cjs.map +1 -0
  33. package/dist/{ShopScreen-BAbAc2ah.cjs → ShopScreen-C-Ki6fuh.cjs} +3 -3
  34. package/dist/{ShopScreen-DQ1-68kV.mjs → ShopScreen-C2K1C2tt.mjs} +3 -3
  35. package/dist/{ShopScreen-DQ1-68kV.mjs.map → ShopScreen-C2K1C2tt.mjs.map} +1 -1
  36. package/dist/{ShopScreen-DcJ0DLvB.cjs → ShopScreen-smzNn37E.cjs} +3 -3
  37. package/dist/{ShopScreen-DcJ0DLvB.cjs.map → ShopScreen-smzNn37E.cjs.map} +1 -1
  38. package/dist/{UpgradeScreen-BdY0rCoF.cjs → UpgradeScreen-CNXQ1hcP.cjs} +1 -1
  39. package/dist/{UpgradeScreen-Dau5Elx4.mjs → UpgradeScreen-ChLiVSf7.mjs} +1 -1
  40. package/dist/{UpgradeScreen-Dau5Elx4.mjs.map → UpgradeScreen-ChLiVSf7.mjs.map} +1 -1
  41. package/dist/{UpgradeScreen-DrBa2uzD.cjs → UpgradeScreen-DMJUK4dl.cjs} +1 -1
  42. package/dist/{UpgradeScreen-DrBa2uzD.cjs.map → UpgradeScreen-DMJUK4dl.cjs.map} +1 -1
  43. package/dist/{dist-DWs3-WOI.cjs → dist-Bxa9x0H9.cjs} +218 -1
  44. package/dist/{dist-DWs3-WOI.cjs.map → dist-Bxa9x0H9.cjs.map} +1 -1
  45. package/dist/index.cjs +24 -53
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.d.cts +1 -20
  48. package/dist/index.d.cts.map +1 -1
  49. package/dist/index.d.mts +1 -20
  50. package/dist/index.d.mts.map +1 -1
  51. package/dist/index.mjs +25 -52
  52. package/dist/index.mjs.map +1 -1
  53. package/dist/{portal_tenant_content-0zpnjBot.cjs → portal_tenant_content-BvYxmADB.cjs} +18 -1
  54. package/dist/portal_tenant_content-BvYxmADB.cjs.map +1 -0
  55. package/dist/{portal_tenant_content-DzIQtSLE.mjs → portal_tenant_content-nHEI2qEY.mjs} +13 -2
  56. package/dist/portal_tenant_content-nHEI2qEY.mjs.map +1 -0
  57. package/dist/{sortable.esm-CJLSD-Ce.mjs → sortable.esm-fSGrAZU2.mjs} +141 -2
  58. package/dist/sortable.esm-fSGrAZU2.mjs.map +1 -0
  59. package/package.json +14 -14
  60. package/dist/MySiteScreen-B1L8coGs.cjs.map +0 -1
  61. package/dist/PortalContentApiProvider-C9FeVwRb.mjs.map +0 -1
  62. package/dist/PortalContentApiProvider-RXBp8FNj.cjs.map +0 -1
  63. package/dist/ProductsScreen-BD53vh6Y.cjs +0 -103
  64. package/dist/ProductsScreen-BD53vh6Y.cjs.map +0 -1
  65. package/dist/ProductsScreen-BtUZxJCt.mjs +0 -91
  66. package/dist/ProductsScreen-BtUZxJCt.mjs.map +0 -1
  67. package/dist/ProductsScreen-DNpzJ6lh.cjs +0 -15
  68. package/dist/ProductsScreen-pkOeOW8M.mjs +0 -13
  69. package/dist/ShareablesScreen-CW1e9x4K.mjs +0 -188
  70. package/dist/ShareablesScreen-CW1e9x4K.mjs.map +0 -1
  71. package/dist/ShareablesScreen-D1J2Kljk.mjs +0 -15
  72. package/dist/ShareablesScreen-DC8xXUo4.cjs +0 -200
  73. package/dist/ShareablesScreen-DC8xXUo4.cjs.map +0 -1
  74. package/dist/portal_tenant_content-0zpnjBot.cjs.map +0 -1
  75. package/dist/portal_tenant_content-DzIQtSLE.mjs.map +0 -1
  76. package/dist/sortable.esm-CJLSD-Ce.mjs.map +0 -1
  77. package/dist/use-mysite-portal-BV-BP3CE.mjs +0 -141
  78. package/dist/use-mysite-portal-BV-BP3CE.mjs.map +0 -1
  79. package/dist/use-mysite-portal-DzDYRU0u.cjs +0 -219
  80. package/dist/use-mysite-portal-DzDYRU0u.cjs.map +0 -1
@@ -1,14 +1,17 @@
1
1
  const require_chunk = require("./chunk-9hOWP6kD.cjs");
2
- const require_portal_tenant_content = require("./portal_tenant_content-0zpnjBot.cjs");
2
+ const require_portal_tenant_content = require("./portal_tenant_content-BvYxmADB.cjs");
3
3
  const require_PortalTenantClientProvider = require("./PortalTenantClientProvider-CVv-4rQ9.cjs");
4
4
  const require_src = require("./src-aItPhUAR.cjs");
5
5
  const require_ScreenHeaderContext = require("./ScreenHeaderContext-BXgWydjB.cjs");
6
+ const require_use_account = require("./use-account-C5QI6NSe.cjs");
7
+ const require_use_store = require("./use-store-BLcehk1A.cjs");
8
+ const require_AppNavigationContext = require("./AppNavigationContext-CbK8uCjS.cjs");
6
9
  const require_dist$3 = require("./dist-CGuUUVNt.cjs");
7
10
  const require_es = require("./es-DHLLltoR.cjs");
8
11
  const require_SearchSort = require("./SearchSort-DHDDqero.cjs");
9
12
  const require_dist$4 = require("./dist-DDZMFlal.cjs");
10
- const require_dist$5 = require("./dist-DWs3-WOI.cjs");
11
- const require_PortalProductsApiProvider = require("./PortalProductsApiProvider-Ca1oeTtJ.cjs");
13
+ const require_dist$5 = require("./dist-Bxa9x0H9.cjs");
14
+ const require_PortalProductsApiProvider = require("./PortalProductsApiProvider-CRaocswH.cjs");
12
15
  let react = require("react");
13
16
  react = require_chunk.__toESM(react);
14
17
  let _tanstack_react_query = require("@tanstack/react-query");
@@ -288,6 +291,25 @@ const useUpdatePlaylistMutation = (options) => {
288
291
  }
289
292
  });
290
293
  };
294
+ const useReorderPlaylistItemsMutation = (options) => {
295
+ const api = useShareablesApi();
296
+ const queryClient = (0, _tanstack_react_query.useQueryClient)();
297
+ return (0, _tanstack_react_query.useMutation)({
298
+ mutationFn: ({ playlistId, data }) => {
299
+ if (!api.playlists.reorderPlaylistItems) return Promise.resolve();
300
+ return api.playlists.reorderPlaylistItems(playlistId, data);
301
+ },
302
+ onSuccess: (_, { playlistId }) => {
303
+ if (api.playlists.reorderPlaylistItems) queryClient.invalidateQueries({ queryKey: shareablesKeys.playlists.detail(playlistId) });
304
+ options?.onSuccess?.(playlistId);
305
+ },
306
+ onError: (error, { playlistId }) => {
307
+ if (isCancellationError(error)) return;
308
+ console.error("Error reordering playlist items:", error);
309
+ options?.onError?.(error, playlistId);
310
+ }
311
+ });
312
+ };
291
313
  //#endregion
292
314
  //#region ../../shareables/ui/src/context.tsx
293
315
  const MISSING_PROVIDER = Symbol("missing-shareables-provider");
@@ -578,6 +600,83 @@ function ShareableListLayout({ filters, children, isLoading, error, errorMessage
578
600
  });
579
601
  }
580
602
  //#endregion
603
+ //#region ../../shareables/ui/src/components/shared/ShareableListRow.tsx
604
+ /**
605
+ * Container className for a list-view rendering of shareables. Pairs with
606
+ * `ShareableListRow` and mirrors `SHAREABLE_GRID_CLASS` for symmetry.
607
+ */
608
+ const SHAREABLE_LIST_CLASS = "divide-border divide-y rounded-lg border";
609
+ /**
610
+ * Single row in a shareables list view. The row body (thumbnail + title) is
611
+ * a `<button>` for keyboard/click navigation; `leading` and `trailing` slots
612
+ * are siblings so their interactive elements don't nest inside the body
613
+ * button. Hover styling applies to the entire row container.
614
+ */
615
+ function ShareableListRow({ imageUrl, imageAlt, title, subtitle, onClick, leading, trailing }) {
616
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
617
+ className: "hover:bg-muted flex items-center gap-3 px-4 py-3 transition-colors",
618
+ children: [
619
+ leading,
620
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
621
+ type: "button",
622
+ onClick,
623
+ className: "flex min-w-0 flex-1 items-center gap-4 text-left",
624
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
625
+ className: "bg-muted h-12 w-12 shrink-0 overflow-hidden rounded-md",
626
+ children: imageUrl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
627
+ src: imageUrl,
628
+ alt: imageAlt ?? title,
629
+ className: "h-full w-full object-cover"
630
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "bg-muted h-full w-full" })
631
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
632
+ className: "min-w-0 flex-1",
633
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
634
+ className: "text-foreground truncate text-sm font-medium",
635
+ children: title || "Untitled"
636
+ }), subtitle != null && subtitle !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
637
+ className: "text-muted-foreground flex items-center gap-1.5 text-xs",
638
+ children: subtitle
639
+ })]
640
+ })]
641
+ }),
642
+ trailing
643
+ ]
644
+ });
645
+ }
646
+ //#endregion
647
+ //#region ../../shareables/ui/src/components/shared/ViewModeToggle.tsx
648
+ /**
649
+ * Segmented list/grid toggle used in the filter bar of every shareable
650
+ * listing screen. Stateless — callers own the `viewMode` state.
651
+ */
652
+ function ViewModeToggle({ value, onChange }) {
653
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
654
+ className: "border-input bg-muted flex items-center rounded-lg border p-0.5",
655
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleButton, {
656
+ active: value === "list",
657
+ label: "List view",
658
+ onClick: () => onChange("list"),
659
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.List, { className: "h-4 w-4" })
660
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleButton, {
661
+ active: value === "grid",
662
+ label: "Grid view",
663
+ onClick: () => onChange("grid"),
664
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.LayoutGrid, { className: "h-4 w-4" })
665
+ })]
666
+ });
667
+ }
668
+ function ToggleButton({ active, label, onClick, children }) {
669
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
670
+ type: "button",
671
+ onClick,
672
+ title: label,
673
+ "aria-label": label,
674
+ "aria-pressed": active,
675
+ className: require_src.cn("flex h-8 w-8 items-center justify-center rounded-md transition-all", active ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"),
676
+ children
677
+ });
678
+ }
679
+ //#endregion
581
680
  //#region ../../shareables/ui/src/components/screens/ProductsScreen.tsx
582
681
  const PAGE_SIZE$4 = 24;
583
682
  const SORT_OPTIONS$1 = [
@@ -608,6 +707,7 @@ const SORT_OPTIONS$1 = [
608
707
  ];
609
708
  function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNavigate }) {
610
709
  const client = useShareablesClient();
710
+ const { navigate } = useShareablesUI();
611
711
  require_ScreenHeaderContext.useScreenHeaderBreadcrumbs((0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Breadcrumb, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.BreadcrumbList, {
612
712
  className: "text-lg",
613
713
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.BreadcrumbItem, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.BreadcrumbPage, {
@@ -618,6 +718,7 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
618
718
  const [searchTerm, setSearchTerm] = (0, react.useState)("");
619
719
  const [debouncedSearch, setDebouncedSearch] = (0, react.useState)("");
620
720
  const [sortValue, setSortValue] = (0, react.useState)("created_at_desc");
721
+ const [viewMode, setViewMode] = (0, react.useState)("grid");
621
722
  const observerTarget = (0, react.useRef)(null);
622
723
  (0, react.useEffect)(() => {
623
724
  const timer = setTimeout(() => {
@@ -705,9 +806,9 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
705
806
  errorMessage: "Failed to load products. Please try again.",
706
807
  isEmpty: products.length === 0,
707
808
  emptyMessage: debouncedSearch ? "No products match your search." : "No products available.",
708
- filters: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
709
- className: "flex justify-end",
710
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
809
+ filters: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
810
+ className: "flex items-center justify-end gap-2",
811
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
711
812
  className: "w-full max-w-sm",
712
813
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
713
814
  searchValue: searchTerm,
@@ -717,14 +818,18 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
717
818
  sortValue,
718
819
  onSortChange: setSortValue
719
820
  })
720
- })
821
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewModeToggle, {
822
+ value: viewMode,
823
+ onChange: setViewMode
824
+ })]
721
825
  }),
826
+ loadingFilterShape: "search-view",
722
827
  footer: isFetchingNextPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
723
828
  className: "flex justify-center py-4",
724
829
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" })
725
830
  }),
726
831
  sentinelRef: observerTarget,
727
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
832
+ children: viewMode === "grid" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
728
833
  className: SHAREABLE_GRID_CLASS,
729
834
  children: products.map((product) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareProductCard, {
730
835
  product: {
@@ -734,6 +839,14 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
734
839
  },
735
840
  mediaCount: product.media_count
736
841
  }, product.id))
842
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
843
+ className: SHAREABLE_LIST_CLASS,
844
+ children: products.map((product) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableListRow, {
845
+ imageUrl: product.image_url,
846
+ title: product.title,
847
+ subtitle: product.media_count != null ? `${product.media_count} assets` : void 0,
848
+ onClick: () => navigate(`product/${product.id}`)
849
+ }, product.id))
737
850
  })
738
851
  });
739
852
  }
@@ -1703,21 +1816,9 @@ function MediaListingScreen({ onNavigate }) {
1703
1816
  }), kindFilter === opt.value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, { className: "text-muted-foreground size-4" })]
1704
1817
  }, opt.value))
1705
1818
  })] }),
1706
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1707
- className: "border-input bg-muted flex items-center rounded-lg border p-0.5",
1708
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1709
- type: "button",
1710
- onClick: () => setViewMode("list"),
1711
- className: `flex h-8 w-8 items-center justify-center rounded-md transition-all ${viewMode === "list" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
1712
- title: "List view",
1713
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.List, { className: "h-4 w-4" })
1714
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1715
- type: "button",
1716
- onClick: () => setViewMode("grid"),
1717
- className: `flex h-8 w-8 items-center justify-center rounded-md transition-all ${viewMode === "grid" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
1718
- title: "Grid view",
1719
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.LayoutGrid, { className: "h-4 w-4" })
1720
- })]
1819
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewModeToggle, {
1820
+ value: viewMode,
1821
+ onChange: setViewMode
1721
1822
  })
1722
1823
  ]
1723
1824
  })]
@@ -1787,37 +1888,20 @@ function MediaListingScreen({ onNavigate }) {
1787
1888
  }, item.id);
1788
1889
  })
1789
1890
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1790
- className: "divide-border divide-y rounded-lg border",
1891
+ className: SHAREABLE_LIST_CLASS,
1791
1892
  children: filteredItems.map((item) => {
1792
1893
  const canEdit = !readOnly && item.owner_type === "user";
1793
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1794
- className: "hover:bg-muted flex items-center gap-4 px-4 py-3 transition-colors",
1795
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1796
- type: "button",
1797
- onClick: () => navigate(`media/${item.id}`),
1798
- className: "flex min-w-0 flex-1 items-center gap-4 text-left",
1799
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1800
- className: "bg-muted h-12 w-12 shrink-0 overflow-hidden rounded-md",
1801
- children: item.image_url ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
1802
- src: item.image_url,
1803
- alt: item.title ?? "",
1804
- className: "h-full w-full object-cover"
1805
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "bg-muted h-full w-full" })
1806
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1807
- className: "min-w-0 flex-1",
1808
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1809
- className: "text-foreground truncate text-sm font-medium",
1810
- children: item.title ?? "Untitled"
1811
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1812
- className: "text-muted-foreground flex items-center gap-1.5 text-xs",
1813
- children: [getMediaKindLabel(item.kind), item.owner_type === "user" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Badge, {
1814
- variant: "secondary",
1815
- className: "px-1.5 py-0 text-[10px] leading-4",
1816
- children: "My Media"
1817
- })]
1818
- })]
1819
- })]
1820
- }), canEdit && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MediaRowActionsMenu, { onDelete: () => setPendingDeleteId(item.id) })]
1894
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableListRow, {
1895
+ imageUrl: item.image_url,
1896
+ imageAlt: item.title ?? "",
1897
+ title: item.title ?? "Untitled",
1898
+ subtitle: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [getMediaKindLabel(item.kind), item.owner_type === "user" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Badge, {
1899
+ variant: "secondary",
1900
+ className: "px-1.5 py-0 text-[10px] leading-4",
1901
+ children: "My Media"
1902
+ })] }),
1903
+ onClick: () => navigate(`media/${item.id}`),
1904
+ trailing: canEdit && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MediaRowActionsMenu, { onDelete: () => setPendingDeleteId(item.id) })
1821
1905
  }, item.id);
1822
1906
  })
1823
1907
  })
@@ -8936,6 +9020,7 @@ function PlaylistsListingScreen(_props) {
8936
9020
  const [debouncedSearch, setDebouncedSearch] = (0, react.useState)("");
8937
9021
  const [sortValue, setSortValue] = (0, react.useState)("title");
8938
9022
  const [ownerFilter, setOwnerFilter] = (0, react.useState)("all");
9023
+ const [viewMode, setViewMode] = (0, react.useState)("grid");
8939
9024
  const [selectedIds, setSelectedIds] = (0, react.useState)(/* @__PURE__ */ new Set());
8940
9025
  const [pendingDeleteId, setPendingDeleteId] = (0, react.useState)(null);
8941
9026
  (0, react.useEffect)(() => {
@@ -9106,33 +9191,39 @@ function PlaylistsListingScreen(_props) {
9106
9191
  value: ownerFilter,
9107
9192
  onValueChange: setOwnerFilter,
9108
9193
  myLabel: "My Playlists"
9109
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9110
- className: "ml-auto w-full max-w-sm",
9111
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
9112
- searchValue: searchTerm,
9113
- onSearchChange: setSearchTerm,
9114
- placeholder: "Search playlists...",
9115
- sortOptions: [
9116
- {
9117
- label: "Name (A-Z)",
9118
- value: "title"
9119
- },
9120
- {
9121
- label: "Name (Z-A)",
9122
- value: "-title"
9123
- },
9124
- {
9125
- label: "Date Created (Newest)",
9126
- value: "-created_at"
9127
- },
9128
- {
9129
- label: "Date Created (Oldest)",
9130
- value: "created_at"
9131
- }
9132
- ],
9133
- sortValue,
9134
- onSortChange: setSortValue
9135
- })
9194
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9195
+ className: "ml-auto flex items-center gap-2",
9196
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9197
+ className: "w-full max-w-sm",
9198
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
9199
+ searchValue: searchTerm,
9200
+ onSearchChange: setSearchTerm,
9201
+ placeholder: "Search playlists...",
9202
+ sortOptions: [
9203
+ {
9204
+ label: "Name (A-Z)",
9205
+ value: "title"
9206
+ },
9207
+ {
9208
+ label: "Name (Z-A)",
9209
+ value: "-title"
9210
+ },
9211
+ {
9212
+ label: "Date Created (Newest)",
9213
+ value: "-created_at"
9214
+ },
9215
+ {
9216
+ label: "Date Created (Oldest)",
9217
+ value: "created_at"
9218
+ }
9219
+ ],
9220
+ sortValue,
9221
+ onSortChange: setSortValue
9222
+ })
9223
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewModeToggle, {
9224
+ value: viewMode,
9225
+ onChange: setViewMode
9226
+ })]
9136
9227
  })]
9137
9228
  });
9138
9229
  const footer = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [isFetchingNextPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -9154,8 +9245,8 @@ function PlaylistsListingScreen(_props) {
9154
9245
  }),
9155
9246
  footer,
9156
9247
  sentinelRef: observerTarget,
9157
- loadingFilterShape: "search-action",
9158
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9248
+ loadingFilterShape: "search-view",
9249
+ children: viewMode === "grid" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9159
9250
  className: GRID_CLASS,
9160
9251
  children: filteredPlaylists.map((playlist) => {
9161
9252
  const firstItem = playlist.items?.[0];
@@ -9177,6 +9268,61 @@ function PlaylistsListingScreen(_props) {
9177
9268
  onDelete: onDeletePlaylist ? () => setPendingDeleteId(playlist.id) : void 0
9178
9269
  }, playlist.id);
9179
9270
  })
9271
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9272
+ className: SHAREABLE_LIST_CLASS,
9273
+ children: filteredPlaylists.map((playlist) => {
9274
+ const firstItem = playlist.items?.[0];
9275
+ const imageUrl = playlist.image_url ?? firstItem?.image_url ?? firstItem?.relateable?.image_url ?? firstItem?.relateable?.compressed_image_url;
9276
+ const itemCount = playlist.items_count ?? playlist.items?.length ?? 0;
9277
+ const canEdit = !readOnly && playlist.user_id === user?.id;
9278
+ const isSelected = selectedIds.has(playlist.id);
9279
+ const title = playlist.title || "Untitled Playlist";
9280
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableListRow, {
9281
+ imageUrl,
9282
+ title,
9283
+ subtitle: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.Badge, {
9284
+ variant: "secondary",
9285
+ className: "px-1.5 py-0 text-[10px] leading-4",
9286
+ children: [
9287
+ itemCount,
9288
+ " ",
9289
+ itemCount === 1 ? "item" : "items"
9290
+ ]
9291
+ }),
9292
+ onClick: () => navigate(`playlists/${playlist.id}`),
9293
+ leading: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Checkbox, {
9294
+ checked: isSelected,
9295
+ onCheckedChange: (checked) => handleToggleSelection(playlist.id, checked === true),
9296
+ "aria-label": `Select ${title}`
9297
+ }),
9298
+ trailing: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [onToggleFavorite && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9299
+ type: "button",
9300
+ onClick: () => handleFavorite(playlist.id),
9301
+ "aria-label": playlist.is_favorited ? "Unfavorite" : "Favorite",
9302
+ className: "hover:bg-muted-foreground/10 flex h-8 w-8 items-center justify-center rounded-md transition-colors",
9303
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Heart, { className: require_src.cn("h-4 w-4 transition-colors", playlist.is_favorited ? "fill-destructive text-destructive" : "text-muted-foreground") })
9304
+ }), canEdit && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenu, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.DropdownMenuTrigger, {
9305
+ asChild: true,
9306
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Button, {
9307
+ variant: "ghost",
9308
+ size: "sm",
9309
+ className: "h-8 w-8 p-0",
9310
+ "aria-label": "Playlist actions",
9311
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.MoreVertical, { className: "h-4 w-4" })
9312
+ })
9313
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenuContent, {
9314
+ align: "end",
9315
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenuItem, {
9316
+ onClick: () => handleEdit(playlist.id),
9317
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Pencil, { className: "mr-2 h-4 w-4" }), "Edit"]
9318
+ }), onDeletePlaylist && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.DropdownMenuSeparator, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenuItem, {
9319
+ variant: "destructive",
9320
+ onClick: () => setPendingDeleteId(playlist.id),
9321
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Trash2, { className: "mr-2 h-4 w-4" }), "Delete"]
9322
+ })] })]
9323
+ })] })] })
9324
+ }, playlist.id);
9325
+ })
9180
9326
  })
9181
9327
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialog, {
9182
9328
  open: pendingDeleteId !== null,
@@ -10065,6 +10211,7 @@ function SortableTable({ items, setItems, onDeleteItem, isDeletePending, enableR
10065
10211
  }
10066
10212
  //#endregion
10067
10213
  //#region ../../shareables/ui/src/components/playlists/form/PlaylistItemsSection.tsx
10214
+ const REORDER_DEBOUNCE_MS = 500;
10068
10215
  const PLAYLIST_CONTENT_TYPES = new Set([
10069
10216
  "Medium",
10070
10217
  "Page",
@@ -10134,9 +10281,53 @@ function PlaylistItemsSection({ playlistId }) {
10134
10281
  });
10135
10282
  }
10136
10283
  });
10284
+ const reorderItemsMutation = useReorderPlaylistItemsMutation();
10285
+ const reorderTimerRef = (0, react.useRef)(null);
10286
+ const reorderRollbackRef = (0, react.useRef)(null);
10287
+ (0, react.useEffect)(() => () => {
10288
+ if (reorderTimerRef.current) clearTimeout(reorderTimerRef.current);
10289
+ }, []);
10290
+ const canPersistReorder = !!api.playlists.reorderPlaylistItems;
10137
10291
  const mergeAndOrder = (0, react.useCallback)((reorderedContent) => {
10138
- updateItems(computeOrderedItems([...reorderedContent, ...tailItems]));
10139
- }, [tailItems, updateItems]);
10292
+ const ordered = computeOrderedItems([...reorderedContent, ...tailItems]);
10293
+ if (playlistId && canPersistReorder && reorderTimerRef.current === null && reorderRollbackRef.current === null) reorderRollbackRef.current = tableItems;
10294
+ updateItems(ordered);
10295
+ if (!playlistId || !canPersistReorder) return;
10296
+ if (reorderTimerRef.current) clearTimeout(reorderTimerRef.current);
10297
+ reorderTimerRef.current = setTimeout(() => {
10298
+ reorderTimerRef.current = null;
10299
+ const rollback = reorderRollbackRef.current;
10300
+ reorderItemsMutation.mutate({
10301
+ playlistId,
10302
+ data: { items: ordered.filter((item) => Number.isInteger(item.id) && typeof item.order === "number").map((item) => ({
10303
+ id: item.id,
10304
+ order: item.order
10305
+ })) }
10306
+ }, {
10307
+ onSuccess: () => {
10308
+ if (reorderTimerRef.current === null) reorderRollbackRef.current = null;
10309
+ else reorderRollbackRef.current = ordered;
10310
+ },
10311
+ onError: (error) => {
10312
+ if (rollback) updateItems(rollback);
10313
+ reorderRollbackRef.current = null;
10314
+ showToast({
10315
+ title: "Failed to save new item order",
10316
+ type: "error",
10317
+ error
10318
+ });
10319
+ }
10320
+ });
10321
+ }, REORDER_DEBOUNCE_MS);
10322
+ }, [
10323
+ tailItems,
10324
+ tableItems,
10325
+ updateItems,
10326
+ playlistId,
10327
+ canPersistReorder,
10328
+ reorderItemsMutation.mutate,
10329
+ showToast
10330
+ ]);
10140
10331
  const handleDeleteItem = (itemId) => {
10141
10332
  removeItem(itemId);
10142
10333
  if (playlistId) removeItemMutation.mutate({
@@ -10192,13 +10383,7 @@ function PlaylistItemsSection({ playlistId }) {
10192
10383
  type: "success"
10193
10384
  });
10194
10385
  } catch {}
10195
- else {
10196
- addItem(newItem);
10197
- showToast({
10198
- title: "Item added. Save the playlist to persist these items.",
10199
- type: "warning"
10200
- });
10201
- }
10386
+ else addItem(newItem);
10202
10387
  }
10203
10388
  };
10204
10389
  const filePickerContextValue = (0, react.useMemo)(() => {
@@ -10800,31 +10985,6 @@ function ShareablesApp({ screen, detailId, action, onNavigate, onBack, countryCo
10800
10985
  return content;
10801
10986
  }
10802
10987
  //#endregion
10803
- //#region ../../shareables/ui/src/components/ProductsApp.tsx
10804
- function ProductsApp({ countryCode, companyLogoUrl, fetchProducts, fetchProduct, productId: controlledProductId, onSelectProduct: onSelectProductProp, onBack: onBackProp }) {
10805
- const [internalProductId, setInternalProductId] = (0, react.useState)(null);
10806
- const activeProductId = controlledProductId !== void 0 ? controlledProductId : internalProductId;
10807
- const handleSelectProduct = onSelectProductProp ?? setInternalProductId;
10808
- const handleBack = onBackProp ?? (() => setInternalProductId(null));
10809
- const handleNavigate = (screen, detailId) => {
10810
- if (screen === "products" && detailId) handleSelectProduct(detailId);
10811
- };
10812
- if (activeProductId) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProductDetailScreen, {
10813
- productId: activeProductId,
10814
- countryCode,
10815
- fetchProduct,
10816
- onNavigate: handleNavigate,
10817
- onBack: handleBack
10818
- });
10819
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProductsScreen, {
10820
- countryCode,
10821
- fetchProducts,
10822
- onNavigate: (screen, detailId) => {
10823
- if (detailId) handleSelectProduct(detailId);
10824
- }
10825
- });
10826
- }
10827
- //#endregion
10828
10988
  //#region ../../file-picker/api-client/src/api/url-proxy.ts
10829
10989
  const urlProxyResponseSchema = zod.z.object({
10830
10990
  data: zod.z.string(),
@@ -11490,6 +11650,9 @@ function createPlaylistsAdapter(client) {
11490
11650
  items: [],
11491
11651
  items_count: 0
11492
11652
  };
11653
+ },
11654
+ reorderPlaylistItems: async (playlistId, data) => {
11655
+ await require_portal_tenant_content.playlists_items_reorder(client, playlistId, { items: data.items });
11493
11656
  }
11494
11657
  };
11495
11658
  }
@@ -11856,53 +12019,191 @@ function PortalContentApiProvider({ children }) {
11856
12019
  });
11857
12020
  }
11858
12021
  //#endregion
11859
- Object.defineProperty(exports, "PortalContentApiProvider", {
11860
- enumerable: true,
11861
- get: function() {
11862
- return PortalContentApiProvider;
11863
- }
11864
- });
11865
- Object.defineProperty(exports, "ProductsApp", {
11866
- enumerable: true,
11867
- get: function() {
11868
- return ProductsApp;
11869
- }
11870
- });
11871
- Object.defineProperty(exports, "ShareablesApp", {
11872
- enumerable: true,
11873
- get: function() {
11874
- return ShareablesApp;
11875
- }
11876
- });
11877
- Object.defineProperty(exports, "ShareablesCoreProvider", {
11878
- enumerable: true,
11879
- get: function() {
11880
- return ShareablesCoreProvider;
11881
- }
11882
- });
11883
- Object.defineProperty(exports, "ShareablesUIProvider", {
11884
- enumerable: true,
11885
- get: function() {
11886
- return ShareablesUIProvider;
11887
- }
11888
- });
11889
- Object.defineProperty(exports, "toggleFavorite", {
11890
- enumerable: true,
11891
- get: function() {
11892
- return toggleFavorite;
11893
- }
11894
- });
11895
- Object.defineProperty(exports, "useFilePickerApi", {
12022
+ //#region src/screens/ShareablesScreen.tsx
12023
+ /**
12024
+ * Parse the current shareables sub-route from the full slug.
12025
+ *
12026
+ * System nav slugs are "share/products", "share/media", "share/playlists".
12027
+ * Detail pages append an ID: "share/products/123", "share/media/456".
12028
+ *
12029
+ * "share/products" → screen="products", detailId=null
12030
+ * "share/products/123" → screen="products", detailId="123"
12031
+ * "share/media/456" → screen="media", detailId="456"
12032
+ * "share/playlists" → screen="playlists", detailId=null
12033
+ * "share/playlists/789" → screen="playlists", detailId="789"
12034
+ * "share/files" → screen="files", detailId=null
12035
+ * "share" → screen=null (default to products)
12036
+ */
12037
+ function parseShareablesRoute(currentSlug) {
12038
+ const slugWithoutPrefix = currentSlug.replace(/^share\/?/, "");
12039
+ if (!slugWithoutPrefix) return {
12040
+ screen: null,
12041
+ detailId: null,
12042
+ action: null
12043
+ };
12044
+ const parts = slugWithoutPrefix.split("/");
12045
+ return {
12046
+ screen: parts[0] || null,
12047
+ detailId: parts[1] || null,
12048
+ action: parts[2] || null
12049
+ };
12050
+ }
12051
+ function ShareablesScreen({ background, textColor, accentColor, padding, borderRadius, ...divProps }) {
12052
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12053
+ ...divProps,
12054
+ className: `h-full ${divProps.className ?? ""}`,
12055
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_PortalProductsApiProvider.PortalProductsApiProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PortalContentApiProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareablesScreenContent, {}) }) })
12056
+ });
12057
+ }
12058
+ /** Inner component rendered inside providers so hooks can access context. */
12059
+ function ShareablesScreenContent() {
12060
+ const shareablesCtx = usePortalContentContext();
12061
+ const { productsApi: portalProductsApi } = shareablesCtx;
12062
+ const filePickerApi = useFilePickerApi();
12063
+ const { data: account } = require_use_account.useAccount();
12064
+ const { data: store } = require_use_store.useStore();
12065
+ const { currentSlug, navigate } = require_AppNavigationContext.useAppNavigation();
12066
+ const isCustomer = account?.member_type === "customer";
12067
+ const client = require_PortalTenantClientProvider.usePortalTenantClient();
12068
+ const queryClient = (0, _tanstack_react_query.useQueryClient)();
12069
+ const fetchProducts = (0, react.useCallback)(async (search, cursor, limit, sort) => {
12070
+ if (search) return portalProductsApi.searchProducts(search, {
12071
+ cursor,
12072
+ limit
12073
+ });
12074
+ return portalProductsApi.listProducts({
12075
+ cursor,
12076
+ limit,
12077
+ sort
12078
+ });
12079
+ }, [portalProductsApi]);
12080
+ const fetchProduct = (0, react.useCallback)(async (id) => portalProductsApi.getProduct(id), [portalProductsApi]);
12081
+ const { screen, detailId, action } = parseShareablesRoute(currentSlug);
12082
+ const handleNavigate = (0, react.useCallback)((subScreen, id) => {
12083
+ navigate(id ? `share/${subScreen}/${id}` : `share/${subScreen}`);
12084
+ }, [navigate]);
12085
+ const handleBack = (0, react.useCallback)(() => {
12086
+ if (detailId && screen) navigate(`share/${screen}`);
12087
+ else navigate("share/products");
12088
+ }, [
12089
+ navigate,
12090
+ detailId,
12091
+ screen
12092
+ ]);
12093
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareablesCoreProvider, {
12094
+ config: (0, react.useMemo)(() => ({
12095
+ user: account ? { id: account.id } : null,
12096
+ repContext: true
12097
+ }), [account]),
12098
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareablesUIProvider, {
12099
+ config: (0, react.useMemo)(() => ({
12100
+ user: account ? {
12101
+ id: account.id,
12102
+ company: { logo_url: store?.logo_url ?? null }
12103
+ } : void 0,
12104
+ affiliateId: null,
12105
+ basePath: "",
12106
+ navigate: (path) => {
12107
+ const cleanPath = path.replace(/^\//, "");
12108
+ navigate(cleanPath.startsWith("share/") ? cleanPath : `share/${cleanPath}`);
12109
+ },
12110
+ showToast: (opts) => {
12111
+ require_src.fluidToast({
12112
+ title: opts.title,
12113
+ type: opts.type
12114
+ });
12115
+ if (opts.error) console.error("[Shareables]", opts.error);
12116
+ },
12117
+ filePickerApi,
12118
+ onToggleFavorite: async (params) => {
12119
+ const result = await toggleFavorite(client, params.favoriteableId, params.favoriteableType);
12120
+ queryClient.invalidateQueries({ queryKey: require_dist$5.PORTAL_MYSITE_KEYS.favorites() });
12121
+ return result;
12122
+ },
12123
+ onMySiteShare: async (params) => {
12124
+ await toggleFavorite(client, params.relateable_id, params.relateable_type);
12125
+ queryClient.invalidateQueries({ queryKey: require_dist$5.PORTAL_MYSITE_KEYS.favorites() });
12126
+ },
12127
+ onDeletePlaylist: isCustomer ? void 0 : async (playlistId) => {
12128
+ await shareablesCtx.playlistsAdapter.deletePlaylist(playlistId);
12129
+ },
12130
+ mediaProductsApi: isCustomer ? void 0 : shareablesCtx.mediaProductsAdapter,
12131
+ searchProducts: isCustomer ? void 0 : async (query, options) => {
12132
+ const limit = options?.limit ?? 25;
12133
+ const cursor = options?.cursor ?? void 0;
12134
+ const result = query.trim().length > 0 ? await portalProductsApi.searchProducts(query, {
12135
+ cursor,
12136
+ limit
12137
+ }) : await portalProductsApi.listProducts({
12138
+ cursor,
12139
+ limit
12140
+ });
12141
+ return {
12142
+ products: (result.products ?? []).map((p) => p.id != null ? {
12143
+ id: p.id,
12144
+ name: p.name ?? p.title ?? "Untitled",
12145
+ image_url: p.image_url ?? null,
12146
+ price: p.price ?? null
12147
+ } : null).filter((p) => p !== null),
12148
+ nextCursor: result.meta?.pagination?.next_cursor ?? null
12149
+ };
12150
+ },
12151
+ readOnly: isCustomer,
12152
+ uploadThumbnail: isCustomer ? void 0 : async (blob, filename) => {
12153
+ const formData = new FormData();
12154
+ formData.append("asset[name]", filename);
12155
+ formData.append("asset[file]", blob, filename);
12156
+ const url = (await client.requestWithFormData("/api/content/dam/assets", formData)).asset?.default_variant_url;
12157
+ if (!url) throw new Error("Thumbnail upload succeeded but no URL returned");
12158
+ return url;
12159
+ }
12160
+ }), [
12161
+ account,
12162
+ store,
12163
+ navigate,
12164
+ filePickerApi,
12165
+ isCustomer,
12166
+ shareablesCtx.playlistsAdapter,
12167
+ shareablesCtx.mediaProductsAdapter,
12168
+ portalProductsApi,
12169
+ client,
12170
+ queryClient
12171
+ ]),
12172
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareablesApp, {
12173
+ screen,
12174
+ detailId,
12175
+ action,
12176
+ companyLogoUrl: void 0,
12177
+ countryCode: void 0,
12178
+ fetchProducts,
12179
+ fetchProduct,
12180
+ onNavigate: handleNavigate,
12181
+ onBack: handleBack
12182
+ })
12183
+ })
12184
+ });
12185
+ }
12186
+ const shareablesScreenPropertySchema = {
12187
+ widgetType: "ShareablesScreen",
12188
+ displayName: "Shareables Screen",
12189
+ tabsConfig: [{
12190
+ id: "styling",
12191
+ label: "Styling"
12192
+ }],
12193
+ fields: []
12194
+ };
12195
+ //#endregion
12196
+ Object.defineProperty(exports, "ShareablesScreen", {
11896
12197
  enumerable: true,
11897
12198
  get: function() {
11898
- return useFilePickerApi;
12199
+ return ShareablesScreen;
11899
12200
  }
11900
12201
  });
11901
- Object.defineProperty(exports, "usePortalContentContext", {
12202
+ Object.defineProperty(exports, "shareablesScreenPropertySchema", {
11902
12203
  enumerable: true,
11903
12204
  get: function() {
11904
- return usePortalContentContext;
12205
+ return shareablesScreenPropertySchema;
11905
12206
  }
11906
12207
  });
11907
12208
 
11908
- //# sourceMappingURL=PortalContentApiProvider-RXBp8FNj.cjs.map
12209
+ //# sourceMappingURL=ShareablesScreen-DwnMBftJ.cjs.map