@fluid-app/portal-sdk 0.1.229 → 0.1.231

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 (57) hide show
  1. package/dist/{FluidProvider-Bl8BC3N1.cjs → FluidProvider-DWNo4QTC.cjs} +7 -5
  2. package/dist/{FluidProvider-Bl8BC3N1.cjs.map → FluidProvider-DWNo4QTC.cjs.map} +1 -1
  3. package/dist/{FluidProvider-1ny2_ye-.mjs → FluidProvider-i69t4zBo.mjs} +7 -5
  4. package/dist/{FluidProvider-1ny2_ye-.mjs.map → FluidProvider-i69t4zBo.mjs.map} +1 -1
  5. package/dist/{MessagingScreen-7VQtzmmg.mjs → MessagingScreen-BbIKoH2L.mjs} +2 -2
  6. package/dist/{MessagingScreen-7VQtzmmg.mjs.map → MessagingScreen-BbIKoH2L.mjs.map} +1 -1
  7. package/dist/{MessagingScreen-BbCJ4ctF.cjs → MessagingScreen-CDx6ryDj.cjs} +2 -2
  8. package/dist/{MessagingScreen-CF2894Tr.cjs → MessagingScreen-Crp-Kl4c.cjs} +2 -2
  9. package/dist/{MessagingScreen-CF2894Tr.cjs.map → MessagingScreen-Crp-Kl4c.cjs.map} +1 -1
  10. package/dist/{OrdersScreen-knd6gnEi.cjs → OrdersScreen-CfnNy52h.cjs} +1 -1
  11. package/dist/{OrdersScreen-YWHy3VBL.mjs → OrdersScreen-DcC_-N8h.mjs} +2 -2
  12. package/dist/{OrdersScreen-YWHy3VBL.mjs.map → OrdersScreen-DcC_-N8h.mjs.map} +1 -1
  13. package/dist/{OrdersScreen-BPrt9kNr.cjs → OrdersScreen-DxQmihvZ.cjs} +2 -2
  14. package/dist/{OrdersScreen-BPrt9kNr.cjs.map → OrdersScreen-DxQmihvZ.cjs.map} +1 -1
  15. package/dist/{PortalProductsApiProvider-BeCWFRtF.mjs → PortalProductsApiProvider-CP1xk872.mjs} +2 -2
  16. package/dist/{PortalProductsApiProvider-BeCWFRtF.mjs.map → PortalProductsApiProvider-CP1xk872.mjs.map} +1 -1
  17. package/dist/{PortalProductsApiProvider-Bb5B1Hv5.cjs → PortalProductsApiProvider-jDoPfaPB.cjs} +2 -2
  18. package/dist/{PortalProductsApiProvider-Bb5B1Hv5.cjs.map → PortalProductsApiProvider-jDoPfaPB.cjs.map} +1 -1
  19. package/dist/{ProfileScreen-BT-SOUnq.cjs → ProfileScreen-B2JEvxsd.cjs} +2 -2
  20. package/dist/{ProfileScreen-DE6Rrw23.cjs → ProfileScreen-BPdHZZXV.cjs} +2 -2
  21. package/dist/{ProfileScreen-DE6Rrw23.cjs.map → ProfileScreen-BPdHZZXV.cjs.map} +1 -1
  22. package/dist/{ProfileScreen-BOvOpIS1.mjs → ProfileScreen-ftzRbWgc.mjs} +2 -2
  23. package/dist/{ProfileScreen-BOvOpIS1.mjs.map → ProfileScreen-ftzRbWgc.mjs.map} +1 -1
  24. package/dist/{ShareablesScreen-DjRtywMv.mjs → ShareablesScreen-BjpwByeL.mjs} +1230 -274
  25. package/dist/ShareablesScreen-BjpwByeL.mjs.map +1 -0
  26. package/dist/{ShareablesScreen-o6frhZUM.cjs → ShareablesScreen-BsICzJuf.cjs} +1229 -273
  27. package/dist/ShareablesScreen-BsICzJuf.cjs.map +1 -0
  28. package/dist/{ShareablesScreen-CTIe6EH0.cjs → ShareablesScreen-iXNQCKSx.cjs} +2 -2
  29. package/dist/{ShopScreen-yZUXE55P.cjs → ShopScreen-DBopix8F.cjs} +3 -3
  30. package/dist/{ShopScreen-yZUXE55P.cjs.map → ShopScreen-DBopix8F.cjs.map} +1 -1
  31. package/dist/{ShopScreen-CJcGSrG4.mjs → ShopScreen-d6e2Bm0N.mjs} +3 -3
  32. package/dist/{ShopScreen-CJcGSrG4.mjs.map → ShopScreen-d6e2Bm0N.mjs.map} +1 -1
  33. package/dist/{ShopScreen-IQ3tqLfP.cjs → ShopScreen-recdiuo_.cjs} +3 -3
  34. package/dist/{SubscriptionsScreen-CISCXowf.cjs → SubscriptionsScreen-BI296E2y.cjs} +1 -1
  35. package/dist/{SubscriptionsScreen-mUaEWHn5.mjs → SubscriptionsScreen-CcaqnqiQ.mjs} +2 -2
  36. package/dist/{SubscriptionsScreen-mUaEWHn5.mjs.map → SubscriptionsScreen-CcaqnqiQ.mjs.map} +1 -1
  37. package/dist/{SubscriptionsScreen-BsOdTfJQ.cjs → SubscriptionsScreen-DkiuXzRX.cjs} +2 -2
  38. package/dist/{SubscriptionsScreen-BsOdTfJQ.cjs.map → SubscriptionsScreen-DkiuXzRX.cjs.map} +1 -1
  39. package/dist/index.cjs +20 -20
  40. package/dist/index.d.cts.map +1 -1
  41. package/dist/index.d.mts.map +1 -1
  42. package/dist/index.mjs +20 -20
  43. package/dist/{portal_tenant-GpShCvG9.cjs → portal_tenant-CxChT6OB.cjs} +17 -1
  44. package/dist/portal_tenant-CxChT6OB.cjs.map +1 -0
  45. package/dist/{portal_tenant-CFngP8OD.mjs → portal_tenant-f_Cs2YmO.mjs} +12 -2
  46. package/dist/portal_tenant-f_Cs2YmO.mjs.map +1 -0
  47. package/dist/{portal_tenant_content-WBAKi5Vl.mjs → portal_tenant_content-CEDc7an2.mjs} +2 -2
  48. package/dist/portal_tenant_content-CEDc7an2.mjs.map +1 -0
  49. package/dist/{portal_tenant_content-Bnr0IyhM.cjs → portal_tenant_content-D60b_KWd.cjs} +2 -2
  50. package/dist/portal_tenant_content-D60b_KWd.cjs.map +1 -0
  51. package/package.json +15 -15
  52. package/dist/ShareablesScreen-DjRtywMv.mjs.map +0 -1
  53. package/dist/ShareablesScreen-o6frhZUM.cjs.map +0 -1
  54. package/dist/portal_tenant-CFngP8OD.mjs.map +0 -1
  55. package/dist/portal_tenant-GpShCvG9.cjs.map +0 -1
  56. package/dist/portal_tenant_content-Bnr0IyhM.cjs.map +0 -1
  57. package/dist/portal_tenant_content-WBAKi5Vl.mjs.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { r as __exportAll, t as useDropzone } from "./es-BkP8gyWU.mjs";
2
- import { A as playlists_list, C as pages_show, D as playlists_items_list, E as playlists_items_add, M as playlists_update, N as shares_create, O as playlists_items_remove, P as shares_list, S as pages_list, T as playlists_destroy, _ as media_products_add, a as content_playlists_by_shares, b as media_show, c as dam_asset_paths_list, d as dam_assets_discard, f as dam_assets_list, g as media_list, h as media_destroy, i as content_pages_by_visits, j as playlists_show, k as playlists_items_reorder, l as dam_assets_create, m as media_create, n as content_media_by_visits, o as content_playlists_by_visits, p as dam_query, r as content_pages_by_shares, s as dam_asset_paths_create, t as content_media_by_shares, u as dam_assets_destroy, v as media_products_list, w as playlists_create, x as media_update, y as media_products_remove } from "./portal_tenant_content-WBAKi5Vl.mjs";
2
+ import { l as enrollment_packs_list, u as enrollment_packs_show } from "./portal_tenant-f_Cs2YmO.mjs";
3
+ import { A as playlists_list, C as pages_show, D as playlists_items_list, E as playlists_items_add, M as playlists_update, N as shares_create, O as playlists_items_remove, P as shares_list, S as pages_list, T as playlists_destroy, _ as media_products_add, a as content_playlists_by_shares, b as media_show, c as dam_asset_paths_list, d as dam_assets_discard, f as dam_assets_list, g as media_list, h as media_destroy, i as content_pages_by_visits, j as playlists_show, k as playlists_items_reorder, l as dam_assets_create, m as media_create, n as content_media_by_visits, o as content_playlists_by_visits, p as dam_query, r as content_pages_by_shares, s as dam_asset_paths_create, t as content_media_by_shares, u as dam_assets_destroy, v as media_products_list, w as playlists_create, x as media_update, y as media_products_remove } from "./portal_tenant_content-CEDc7an2.mjs";
3
4
  import { n as usePortalTenantClient } from "./PortalTenantClientProvider-CjJzBCTL.mjs";
4
5
  import { $ as DropdownMenuSeparator, A as Select, At as Checkbox, B as Form, C as Skeleton, Cn as AlertDialogFooter, Dn as Content, En as Button, Et as CardContent, G as FormMessage, H as FormField, J as DropdownMenuContent, K as Label, L as Input, M as SelectItem, N as SelectTrigger, Nn as useZodForm, P as SelectValue, Pn as cn, S as Slider, Sn as AlertDialogDescription, Tn as AlertDialogTitle, U as FormItem, V as FormControl, W as FormLabel, Y as DropdownMenuItem, _ as Switch, b as fluidToast, bn as AlertDialogCancel, c as Tabs, cn as Breadcrumb, dn as BreadcrumbList, dt as DialogPortal, et as DropdownMenuSub, fn as BreadcrumbPage, ft as DialogTitle, ht as PopoverTrigger, i as TooltipTrigger, it as Dialog, j as SelectContent, k as Separator, l as TabsList, ln as BreadcrumbItem, lt as DialogHeader, mn as Badge, mt as PopoverContent, n as TooltipContent, nt as DropdownMenuSubTrigger, ot as DialogContent, pn as BreadcrumbSeparator, pt as Popover, q as DropdownMenu, r as TooltipProvider, rt as DropdownMenuTrigger, s as Textarea, st as DialogDescription, t as Tooltip, tt as DropdownMenuSubContent, u as TabsTrigger, un as BreadcrumbLink, ut as DialogOverlay, vn as AlertDialog, wn as AlertDialogHeader, wt as Card, xn as AlertDialogContent, y as Spinner, yn as AlertDialogAction } from "./src-CCqVyAdS.mjs";
5
6
  import { n as useScreenHeaderActions, r as useScreenHeaderBreadcrumbs } from "./ScreenHeaderContext-4WYXIqQ5.mjs";
@@ -10,11 +11,11 @@ import { a as useEditor, o as Placeholder, r as EditorContent, t as StarterKit }
10
11
  import { t as SearchSort } from "./SearchSort-BQ-nf9gJ.mjs";
11
12
  import { n as TextAlign, t as Underline } from "./dist-CsNsoBdu.mjs";
12
13
  import { a as verticalListSortingStrategy, c as PointerSensor, d as useSensors, f as CSS, i as useSortable, l as closestCenter, n as arrayMove, o as DndContext, p as PORTAL_MYSITE_KEYS, r as sortableKeyboardCoordinates, s as KeyboardSensor, t as SortableContext, u as useSensor } from "./sortable.esm-BSpvRpWg.mjs";
13
- import { o as usePortalProductsApi, t as PortalProductsApiProvider } from "./PortalProductsApiProvider-BeCWFRtF.mjs";
14
+ import { o as usePortalProductsApi, t as PortalProductsApiProvider } from "./PortalProductsApiProvider-CP1xk872.mjs";
14
15
  import React, { PureComponent, createContext, createRef, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
15
16
  import { keepPreviousData, useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
16
17
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
17
- import { AlertTriangleIcon, AlignCenter, AlignJustify, AlignLeft, AlignRight, ArrowRightIcon, ArrowUpDownIcon, ArrowUpIcon, ArrowUpRight, Camera, Check, CheckIcon, ChevronDownIcon, CirclePlay, CloudIcon, Copy, CropIcon, Download, DownloadIcon, EllipsisVerticalIcon, FileIcon, FileImage, FileText, Filter, FolderIcon, FolderPlusIcon, Globe, GripVertical, Heart, HelpCircle, Image, ImageIcon, ImagesIcon, LaptopIcon, LayersIcon, LayoutGrid, LayoutGridIcon, LinkIcon, List, ListIcon, ListMusic, ListOrdered, LoaderIcon, Mail, Maximize, Menu, MinusIcon, MoreHorizontal, MoreVertical, MoveHorizontalIcon, Package, Pause, Pencil, Phone, Play, Plus, PlusIcon, RotateCwIcon, Search, SearchIcon, ShoppingBag, ShoppingCart, SlidersHorizontalIcon, Trash2, Trash2Icon, TypeIcon, Upload, UserIcon, Video, VideoIcon, X, XIcon } from "lucide-react";
18
+ import { AlertTriangleIcon, AlignCenter, AlignJustify, AlignLeft, AlignRight, ArrowRightIcon, ArrowUpDownIcon, ArrowUpIcon, ArrowUpRight, Camera, Check, CheckIcon, ChevronDownIcon, CirclePlay, CloudIcon, Copy, CropIcon, Download, DownloadIcon, EllipsisVerticalIcon, FileIcon, FileImage, FileText, FileTextIcon, Filter, FolderIcon, FolderPlusIcon, Globe, GraduationCapIcon, GripVertical, Heart, HelpCircle, Image, ImageIcon, ImagesIcon, LaptopIcon, LayersIcon, LayoutGrid, LayoutGridIcon, LinkIcon, List, ListIcon, ListMusic, ListOrdered, LoaderIcon, Mail, Maximize, Menu, MinusIcon, MoreHorizontal, MoreVertical, MoveHorizontalIcon, Package, PackageIcon, Pause, Pencil, Phone, Play, Plus, PlusIcon, RotateCwIcon, Search, SearchIcon, ShoppingBag, ShoppingCart, SlidersHorizontalIcon, Trash2, Trash2Icon, TypeIcon, Upload, UserIcon, Video, VideoIcon, X, XIcon } from "lucide-react";
18
19
  import { createPortal } from "react-dom";
19
20
  import * as z$1 from "zod";
20
21
  import { z } from "zod";
@@ -722,7 +723,7 @@ function useInfiniteListSentinel({ hasNextPage, isFetchingNextPage, fetchNextPag
722
723
  }
723
724
  //#endregion
724
725
  //#region ../../shareables/ui/src/components/screens/ProductsScreen.tsx
725
- const PAGE_SIZE$5 = 24;
726
+ const PAGE_SIZE$6 = 24;
726
727
  const SORT_OPTIONS$1 = [
727
728
  {
728
729
  label: "Newest",
@@ -774,11 +775,11 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
774
775
  queryKey: [
775
776
  "portal-product-catalog",
776
777
  debouncedSearch || "",
777
- PAGE_SIZE$5,
778
+ PAGE_SIZE$6,
778
779
  effectiveSort
779
780
  ],
780
781
  queryFn: async ({ pageParam }) => {
781
- return fetchPortalProducts(debouncedSearch, pageParam, PAGE_SIZE$5, effectiveSort);
782
+ return fetchPortalProducts(debouncedSearch, pageParam, PAGE_SIZE$6, effectiveSort);
782
783
  },
783
784
  getNextPageParam: (lastPage) => lastPage.meta?.pagination?.next_cursor ?? void 0,
784
785
  initialPageParam: void 0,
@@ -794,7 +795,7 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
794
795
  if (!client) throw new Error("Unreachable: client is null");
795
796
  return (await listProducts(client, {
796
797
  page: pageParam,
797
- per_page: PAGE_SIZE$5,
798
+ per_page: PAGE_SIZE$6,
798
799
  search_query: debouncedSearch || void 0,
799
800
  sorting: {
800
801
  id: "title",
@@ -805,7 +806,7 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
805
806
  published_stores: ["rep"]
806
807
  })).products;
807
808
  },
808
- getNextPageParam: (lastPage, allPages) => lastPage.length === PAGE_SIZE$5 ? allPages.length + 1 : void 0,
809
+ getNextPageParam: (lastPage, allPages) => lastPage.length === PAGE_SIZE$6 ? allPages.length + 1 : void 0,
809
810
  initialPageParam: 1,
810
811
  enabled: !fetchPortalProducts && !!client
811
812
  });
@@ -1667,7 +1668,7 @@ function OwnerFilterTabs({ value, onValueChange, myLabel = "Mine" }) {
1667
1668
  }
1668
1669
  //#endregion
1669
1670
  //#region ../../shareables/ui/src/components/screens/MediaListingScreen.tsx
1670
- const PAGE_SIZE$4 = 24;
1671
+ const PAGE_SIZE$5 = 24;
1671
1672
  function getMediaKindLabel(kind) {
1672
1673
  switch (kind) {
1673
1674
  case "video": return "Video";
@@ -1767,7 +1768,7 @@ function MediaListingScreen(_props) {
1767
1768
  "filter[ownership]": ownerFilter,
1768
1769
  "filter[content_format]": bffKind,
1769
1770
  "page[cursor]": pageParam,
1770
- "page[limit]": PAGE_SIZE$4,
1771
+ "page[limit]": PAGE_SIZE$5,
1771
1772
  sort: bffSort
1772
1773
  });
1773
1774
  },
@@ -2162,8 +2163,6 @@ z.object({
2162
2163
  timestamp: z.string()
2163
2164
  })
2164
2165
  });
2165
- //#endregion
2166
- //#region ../../file-picker/core/src/schemas/file-picker-config.ts
2167
2166
  const filePickerConfigSchema = z.object({
2168
2167
  accept: z.array(z.string()).optional(),
2169
2168
  maxFiles: z.number().min(1).optional().default(1),
@@ -2176,6 +2175,9 @@ const filePickerConfigSchema = z.object({
2176
2175
  "computer",
2177
2176
  "dam",
2178
2177
  "media",
2178
+ "pages",
2179
+ "products",
2180
+ "enrollment_packs",
2179
2181
  "url",
2180
2182
  "unsplash",
2181
2183
  "google-drive",
@@ -2183,7 +2185,8 @@ const filePickerConfigSchema = z.object({
2183
2185
  "facebook",
2184
2186
  "tiktok",
2185
2187
  "dropbox"
2186
- ])).optional()
2188
+ ])).optional(),
2189
+ unifiedSelection: z.boolean().optional().default(false)
2187
2190
  });
2188
2191
  const DAM_TYPE_FILTER_OPTIONS = [
2189
2192
  {
@@ -2908,7 +2911,7 @@ const FilePickerContext = createContext(null);
2908
2911
  function FilePickerProvider({ children, value }) {
2909
2912
  return /* @__PURE__ */ jsx(FilePickerContext.Provider, {
2910
2913
  value,
2911
- children
2914
+ children: /* @__PURE__ */ jsx(FilePickerSelectionProvider, { children })
2912
2915
  });
2913
2916
  }
2914
2917
  function useFilePickerContext() {
@@ -2916,6 +2919,37 @@ function useFilePickerContext() {
2916
2919
  if (!ctx) throw new Error("useFilePickerContext must be used within a FilePickerProvider");
2917
2920
  return ctx;
2918
2921
  }
2922
+ const FilePickerSelectionReadContext = createContext(null);
2923
+ const FilePickerSelectionWriteContext = createContext(null);
2924
+ function FilePickerSelectionProvider({ children }) {
2925
+ return /* @__PURE__ */ jsx(FilePickerSelectionReadContext.Provider, {
2926
+ value: null,
2927
+ children: /* @__PURE__ */ jsx(FilePickerSelectionWriteContext.Provider, {
2928
+ value: null,
2929
+ children
2930
+ })
2931
+ });
2932
+ }
2933
+ function FilePickerSelectionScope({ state, api, children }) {
2934
+ return /* @__PURE__ */ jsx(FilePickerSelectionReadContext.Provider, {
2935
+ value: state,
2936
+ children: /* @__PURE__ */ jsx(FilePickerSelectionWriteContext.Provider, {
2937
+ value: api,
2938
+ children
2939
+ })
2940
+ });
2941
+ }
2942
+ /**
2943
+ * Returns the unified selection state when the active picker has unified
2944
+ * selection enabled, otherwise null. Tabs use this as the signal to switch
2945
+ * between unified and per-method behavior.
2946
+ */
2947
+ function useFilePickerSelection() {
2948
+ return {
2949
+ state: useContext(FilePickerSelectionReadContext),
2950
+ api: useContext(FilePickerSelectionWriteContext)
2951
+ };
2952
+ }
2919
2953
  //#endregion
2920
2954
  //#region ../../file-picker/ui/src/utils/brand-icons.tsx
2921
2955
  function GoogleIcon({ className }) {
@@ -4006,6 +4040,9 @@ const FilePickerSidebar = ({ currentStep, activeMethod, onMethodChange, methods
4006
4040
  children: methods.filter((method) => [
4007
4041
  "dam",
4008
4042
  "media",
4043
+ "pages",
4044
+ "products",
4045
+ "enrollment_packs",
4009
4046
  "upload",
4010
4047
  "url",
4011
4048
  "unsplash"
@@ -4445,9 +4482,19 @@ const MediaTab = ({ config, onSelectionChange, onMediaDataChange, selectedMediaI
4445
4482
  upload_status: "ready"
4446
4483
  };
4447
4484
  }, []);
4485
+ const { state: unifiedState, api: unifiedApi } = useFilePickerSelection();
4486
+ const isUnified = unifiedState !== null && unifiedApi !== null;
4448
4487
  const handleMediaClick = useCallback((_e, id, _index) => {
4449
4488
  const mediaId = parseInt(id.replace(/^media_/, ""), 10);
4450
4489
  if (Number.isNaN(mediaId)) return;
4490
+ if (isUnified) {
4491
+ const media = allMediaItems.find((m) => m.id === mediaId);
4492
+ if (!media) return;
4493
+ const result = convertToFilePickerResult(media);
4494
+ if (unifiedApi.isSelected(result.asset_code)) unifiedApi.remove(result.asset_code);
4495
+ else unifiedApi.add(result);
4496
+ return;
4497
+ }
4451
4498
  const isSelected = selectedMediaIds.includes(mediaId);
4452
4499
  let newSelectedIds;
4453
4500
  if (isSelected) newSelectedIds = selectedMediaIds.filter((id) => id !== mediaId);
@@ -4459,6 +4506,8 @@ const MediaTab = ({ config, onSelectionChange, onMediaDataChange, selectedMediaI
4459
4506
  const filePickerResults = newSelectedIds.map((id) => idToMedia.get(id)).filter((m) => m != null).map(convertToFilePickerResult);
4460
4507
  onMediaDataChange?.(filePickerResults);
4461
4508
  }, [
4509
+ isUnified,
4510
+ unifiedApi,
4462
4511
  selectedMediaIds,
4463
4512
  config.maxFiles,
4464
4513
  allMediaItems,
@@ -4467,8 +4516,12 @@ const MediaTab = ({ config, onSelectionChange, onMediaDataChange, selectedMediaI
4467
4516
  onMediaDataChange
4468
4517
  ]);
4469
4518
  React.useEffect(() => {
4470
- onSelectionChange?.(selectedMediaIds.length);
4471
- }, [selectedMediaIds.length, onSelectionChange]);
4519
+ if (!isUnified) onSelectionChange?.(selectedMediaIds.length);
4520
+ }, [
4521
+ isUnified,
4522
+ selectedMediaIds.length,
4523
+ onSelectionChange
4524
+ ]);
4472
4525
  const sortedMediaItems = useMemo(() => {
4473
4526
  if (!sortOption || !allMediaItems.length) return allMediaItems;
4474
4527
  const option = SORT_OPTIONS.find((o) => o.id === sortOption);
@@ -4507,9 +4560,17 @@ const MediaTab = ({ config, onSelectionChange, onMediaDataChange, selectedMediaI
4507
4560
  const libraryItems = useMemo(() => {
4508
4561
  return sortedMediaItems.map((media) => {
4509
4562
  const id = `media_${media.id}`;
4510
- const indexInSelection = selectedMediaIds.indexOf(media.id);
4511
- const isSelected = indexInSelection >= 0;
4512
- const selectionIndex = isSelected ? indexInSelection + 1 : 0;
4563
+ let isSelected;
4564
+ let selectionIndex;
4565
+ if (isUnified) {
4566
+ const idx = unifiedState.items.findIndex((r) => r.asset_code === id);
4567
+ isSelected = idx >= 0;
4568
+ selectionIndex = isSelected ? idx + 1 : 0;
4569
+ } else {
4570
+ const indexInSelection = selectedMediaIds.indexOf(media.id);
4571
+ isSelected = indexInSelection >= 0;
4572
+ selectionIndex = isSelected ? indexInSelection + 1 : 0;
4573
+ }
4513
4574
  return {
4514
4575
  id,
4515
4576
  name: media.title ?? "",
@@ -4519,7 +4580,12 @@ const MediaTab = ({ config, onSelectionChange, onMediaDataChange, selectedMediaI
4519
4580
  raw: media
4520
4581
  };
4521
4582
  });
4522
- }, [sortedMediaItems, selectedMediaIds]);
4583
+ }, [
4584
+ sortedMediaItems,
4585
+ selectedMediaIds,
4586
+ isUnified,
4587
+ unifiedState
4588
+ ]);
4523
4589
  const handleMediaDoubleClick = useCallback((_e, _id, index) => {
4524
4590
  const media = sortedMediaItems[index];
4525
4591
  if (media) onPreviewMediaChange?.(media);
@@ -4642,6 +4708,330 @@ const MediaTab = ({ config, onSelectionChange, onMediaDataChange, selectedMediaI
4642
4708
  });
4643
4709
  };
4644
4710
  //#endregion
4711
+ //#region ../../file-picker/ui/src/components/ContentBrowserTab.tsx
4712
+ const PAGE_SIZE$4 = 30;
4713
+ function ContentBrowserTab({ contentKind, assetCodePrefix, labelPlural, source, getId, getLabel, getImageUrl, getSubtitle, fallbackIcon: FallbackIcon, config, selectedIds, onSelectedIdsChange, onSelectedDataChange, onSelectionCountChange, thumbnailSize = 100, viewMode = "grid", showNamesOnMedia = true }) {
4714
+ const supportsSearch = source.supportsSearch !== false;
4715
+ const [searchQuery, setSearchQuery] = useState("");
4716
+ const [debouncedQuery, setDebouncedQuery] = useState("");
4717
+ const [items, setItems] = useState([]);
4718
+ const [cursor, setCursor] = useState(null);
4719
+ const [loadingMore, setLoadingMore] = useState(false);
4720
+ useEffect(() => {
4721
+ const t = setTimeout(() => setDebouncedQuery(searchQuery), 250);
4722
+ return () => clearTimeout(t);
4723
+ }, [searchQuery]);
4724
+ const { data: firstPage, isLoading, error } = useQuery({
4725
+ queryKey: useMemo(() => [
4726
+ contentKind,
4727
+ "list",
4728
+ debouncedQuery
4729
+ ], [contentKind, debouncedQuery]),
4730
+ queryFn: () => source.list({
4731
+ search: debouncedQuery,
4732
+ cursor: null,
4733
+ limit: PAGE_SIZE$4
4734
+ }),
4735
+ staleTime: 300 * 1e3
4736
+ });
4737
+ useEffect(() => {
4738
+ if (!firstPage) return;
4739
+ setItems(firstPage.items);
4740
+ setCursor(firstPage.nextCursor);
4741
+ }, [firstPage]);
4742
+ const debouncedQueryRef = useRef(debouncedQuery);
4743
+ useEffect(() => {
4744
+ debouncedQueryRef.current = debouncedQuery;
4745
+ }, [debouncedQuery]);
4746
+ const { toast } = useFilePickerContext();
4747
+ const loadMore = useCallback(async () => {
4748
+ if (!cursor) return;
4749
+ const requestQuery = debouncedQuery;
4750
+ try {
4751
+ setLoadingMore(true);
4752
+ const next = await source.list({
4753
+ search: requestQuery,
4754
+ cursor,
4755
+ limit: PAGE_SIZE$4
4756
+ });
4757
+ if (requestQuery !== debouncedQueryRef.current) return;
4758
+ setItems((prev) => {
4759
+ const ids = new Set(prev.map(getId));
4760
+ const merged = [...prev];
4761
+ for (const it of next.items) if (!ids.has(getId(it))) merged.push(it);
4762
+ return merged;
4763
+ });
4764
+ setCursor(next.nextCursor);
4765
+ } catch (err) {
4766
+ toast.error(`Failed to load more ${labelPlural}`, err);
4767
+ } finally {
4768
+ setLoadingMore(false);
4769
+ }
4770
+ }, [
4771
+ cursor,
4772
+ debouncedQuery,
4773
+ source,
4774
+ getId,
4775
+ labelPlural,
4776
+ toast
4777
+ ]);
4778
+ const { state: unifiedState, api: unifiedApi } = useFilePickerSelection();
4779
+ const isUnified = unifiedState !== null && unifiedApi !== null;
4780
+ const toResult = useCallback((item) => {
4781
+ const id = getId(item);
4782
+ const label = getLabel(item);
4783
+ const image = getImageUrl(item) ?? "";
4784
+ return {
4785
+ asset_id: id,
4786
+ asset_code: `${assetCodePrefix}${id}`,
4787
+ file_path: image,
4788
+ file_url: image,
4789
+ ...image ? { thumbnail_url: image } : {},
4790
+ metadata: {
4791
+ file_name: label,
4792
+ mime_type: ""
4793
+ },
4794
+ upload_status: "ready"
4795
+ };
4796
+ }, [
4797
+ assetCodePrefix,
4798
+ getId,
4799
+ getLabel,
4800
+ getImageUrl
4801
+ ]);
4802
+ const isSelected = useCallback((id) => {
4803
+ if (isUnified) return unifiedState.items.some((r) => r.asset_code === `${assetCodePrefix}${id}`);
4804
+ return selectedIds.includes(id);
4805
+ }, [
4806
+ isUnified,
4807
+ unifiedState,
4808
+ assetCodePrefix,
4809
+ selectedIds
4810
+ ]);
4811
+ const selectionIndex = useCallback((id) => {
4812
+ if (isUnified) {
4813
+ const code = `${assetCodePrefix}${id}`;
4814
+ return unifiedState.items.findIndex((r) => r.asset_code === code) + 1;
4815
+ }
4816
+ return selectedIds.indexOf(id) + 1;
4817
+ }, [
4818
+ isUnified,
4819
+ unifiedState,
4820
+ assetCodePrefix,
4821
+ selectedIds
4822
+ ]);
4823
+ const handleClick = useCallback((_e, gridId) => {
4824
+ const numericId = Number.parseInt(gridId.startsWith(assetCodePrefix) ? gridId.slice(assetCodePrefix.length) : gridId, 10);
4825
+ if (Number.isNaN(numericId)) return;
4826
+ const item = items.find((it) => getId(it) === numericId);
4827
+ if (!item) return;
4828
+ const result = toResult(item);
4829
+ if (isUnified) {
4830
+ if (unifiedApi.isSelected(result.asset_code)) unifiedApi.remove(result.asset_code);
4831
+ else unifiedApi.add(result);
4832
+ return;
4833
+ }
4834
+ const already = selectedIds.includes(numericId);
4835
+ let nextIds;
4836
+ if (already) nextIds = selectedIds.filter((x) => x !== numericId);
4837
+ else if (config.maxFiles === 1) nextIds = [numericId];
4838
+ else if (config.maxFiles !== void 0 && selectedIds.length >= config.maxFiles) return;
4839
+ else nextIds = [...selectedIds, numericId];
4840
+ onSelectedIdsChange(nextIds);
4841
+ const idToItem = new Map(items.map((it) => [getId(it), it]));
4842
+ onSelectedDataChange(nextIds.map((id) => idToItem.get(id)).filter((it) => it != null).map(toResult));
4843
+ }, [
4844
+ items,
4845
+ assetCodePrefix,
4846
+ isUnified,
4847
+ unifiedApi,
4848
+ selectedIds,
4849
+ config.maxFiles,
4850
+ onSelectedIdsChange,
4851
+ onSelectedDataChange,
4852
+ toResult,
4853
+ getId
4854
+ ]);
4855
+ useEffect(() => {
4856
+ if (!isUnified) onSelectionCountChange?.(selectedIds.length);
4857
+ }, [
4858
+ isUnified,
4859
+ selectedIds.length,
4860
+ onSelectionCountChange
4861
+ ]);
4862
+ const renderThumbnail = useCallback((item) => {
4863
+ const url = getImageUrl(item);
4864
+ if (url) return /* @__PURE__ */ jsx("img", {
4865
+ src: url,
4866
+ alt: getLabel(item),
4867
+ width: 200,
4868
+ height: 150,
4869
+ className: "h-full w-full object-cover"
4870
+ });
4871
+ return /* @__PURE__ */ jsx("div", {
4872
+ className: "flex h-full w-full items-center justify-center bg-gray-100",
4873
+ children: /* @__PURE__ */ jsx(FallbackIcon, { className: "h-8 w-8 text-gray-400" })
4874
+ });
4875
+ }, [
4876
+ FallbackIcon,
4877
+ getImageUrl,
4878
+ getLabel
4879
+ ]);
4880
+ const libraryItems = useMemo(() => items.map((item) => {
4881
+ const id = getId(item);
4882
+ const idx = selectionIndex(id);
4883
+ return {
4884
+ id: `${assetCodePrefix}${id}`,
4885
+ name: getLabel(item),
4886
+ subtitle: getSubtitle?.(item) ?? void 0,
4887
+ isSelected: isSelected(id),
4888
+ selectionIndex: idx,
4889
+ raw: item
4890
+ };
4891
+ }), [
4892
+ items,
4893
+ assetCodePrefix,
4894
+ isSelected,
4895
+ selectionIndex,
4896
+ getId,
4897
+ getLabel,
4898
+ getSubtitle
4899
+ ]);
4900
+ if (error) return /* @__PURE__ */ jsxs("div", {
4901
+ className: "flex flex-col items-center justify-center py-12",
4902
+ children: [/* @__PURE__ */ jsxs("p", {
4903
+ className: "text-sm text-red-600",
4904
+ children: ["Failed to load ", labelPlural]
4905
+ }), /* @__PURE__ */ jsx("p", {
4906
+ className: "mt-1 text-xs text-gray-500",
4907
+ children: "Please try again later"
4908
+ })]
4909
+ });
4910
+ return /* @__PURE__ */ jsxs("div", {
4911
+ className: "space-y-4",
4912
+ children: [supportsSearch && /* @__PURE__ */ jsxs("div", {
4913
+ className: "relative",
4914
+ children: [/* @__PURE__ */ jsx(Input, {
4915
+ type: "text",
4916
+ placeholder: `Search ${labelPlural}...`,
4917
+ value: searchQuery,
4918
+ onChange: (e) => setSearchQuery(e.target.value),
4919
+ className: "h-9"
4920
+ }), /* @__PURE__ */ jsx("div", {
4921
+ className: "absolute top-1/2 right-3 -translate-y-1/2",
4922
+ children: /* @__PURE__ */ jsx(SearchIcon, { className: "h-4 w-4 text-gray-400" })
4923
+ })]
4924
+ }), isLoading ? /* @__PURE__ */ jsx("div", {
4925
+ className: "flex items-center justify-center py-12",
4926
+ children: /* @__PURE__ */ jsxs("div", {
4927
+ className: "text-center",
4928
+ children: [/* @__PURE__ */ jsx(LoaderIcon, { className: "mx-auto mb-2 h-8 w-8 animate-spin text-blue-600" }), /* @__PURE__ */ jsxs("p", {
4929
+ className: "text-sm text-gray-500",
4930
+ children: [
4931
+ "Loading ",
4932
+ labelPlural,
4933
+ "..."
4934
+ ]
4935
+ })]
4936
+ })
4937
+ }) : libraryItems.length === 0 ? /* @__PURE__ */ jsxs("div", {
4938
+ className: "flex flex-col items-center justify-center py-12",
4939
+ children: [
4940
+ /* @__PURE__ */ jsx("div", {
4941
+ className: "mb-4 rounded-full bg-gray-100 p-3",
4942
+ children: /* @__PURE__ */ jsx(FallbackIcon, { className: "h-6 w-6 text-gray-400" })
4943
+ }),
4944
+ /* @__PURE__ */ jsxs("h3", {
4945
+ className: "mb-1 text-sm font-medium text-gray-900",
4946
+ children: [
4947
+ "No ",
4948
+ labelPlural,
4949
+ " found"
4950
+ ]
4951
+ }),
4952
+ /* @__PURE__ */ jsx("p", {
4953
+ className: "text-xs text-gray-500",
4954
+ children: debouncedQuery ? "Try adjusting your search terms" : `No ${labelPlural} available`
4955
+ })
4956
+ ]
4957
+ }) : /* @__PURE__ */ jsxs("div", {
4958
+ className: "space-y-4",
4959
+ children: [/* @__PURE__ */ jsx(LibraryAssetGrid, {
4960
+ items: libraryItems,
4961
+ viewMode,
4962
+ thumbnailSize,
4963
+ showNamesOnMedia,
4964
+ renderThumbnail,
4965
+ onClick: handleClick
4966
+ }), cursor && /* @__PURE__ */ jsx("div", {
4967
+ className: "flex justify-center",
4968
+ children: /* @__PURE__ */ jsx(Button, {
4969
+ variant: "secondary",
4970
+ size: "sm",
4971
+ onClick: loadMore,
4972
+ disabled: loadingMore,
4973
+ children: loadingMore ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(LoaderIcon, { className: "mr-2 h-3 w-3 animate-spin" }), "Loading..."] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ChevronDownIcon, { className: "mr-2 h-3 w-3" }), "Load more"] })
4974
+ })
4975
+ })]
4976
+ })]
4977
+ });
4978
+ }
4979
+ //#endregion
4980
+ //#region ../../file-picker/ui/src/components/PagesTab.tsx
4981
+ const PagesTab = (props) => {
4982
+ const { shareablesClient } = useFilePickerContext();
4983
+ const source = shareablesClient?.pages;
4984
+ if (!source) return null;
4985
+ return /* @__PURE__ */ jsx(ContentBrowserTab, {
4986
+ contentKind: "pages",
4987
+ assetCodePrefix: "page_",
4988
+ labelPlural: "pages",
4989
+ source,
4990
+ getId: (p) => p.id,
4991
+ getLabel: (p) => p.title || `Page #${p.id}`,
4992
+ getImageUrl: (p) => p.image_url ?? null,
4993
+ fallbackIcon: FileTextIcon,
4994
+ ...props
4995
+ });
4996
+ };
4997
+ //#endregion
4998
+ //#region ../../file-picker/ui/src/components/ProductsTab.tsx
4999
+ const ProductsTab = (props) => {
5000
+ const { shareablesClient } = useFilePickerContext();
5001
+ const source = shareablesClient?.products;
5002
+ if (!source) return null;
5003
+ return /* @__PURE__ */ jsx(ContentBrowserTab, {
5004
+ contentKind: "products",
5005
+ assetCodePrefix: "product_",
5006
+ labelPlural: "products",
5007
+ source,
5008
+ getId: (p) => p.id,
5009
+ getLabel: (p) => p.name || `Product #${p.id}`,
5010
+ getImageUrl: (p) => p.image_url ?? null,
5011
+ getSubtitle: (p) => p.price ? `$${p.price}` : void 0,
5012
+ fallbackIcon: PackageIcon,
5013
+ ...props
5014
+ });
5015
+ };
5016
+ //#endregion
5017
+ //#region ../../file-picker/ui/src/components/EnrollmentPacksTab.tsx
5018
+ const EnrollmentPacksTab = (props) => {
5019
+ const { shareablesClient } = useFilePickerContext();
5020
+ const source = shareablesClient?.enrollment_packs;
5021
+ if (!source) return null;
5022
+ return /* @__PURE__ */ jsx(ContentBrowserTab, {
5023
+ contentKind: "enrollment_packs",
5024
+ assetCodePrefix: "enrollment_pack_",
5025
+ labelPlural: "enrollment packs",
5026
+ source,
5027
+ getId: (p) => p.id,
5028
+ getLabel: (p) => p.title || `Enrollment Pack #${p.id}`,
5029
+ getImageUrl: (p) => p.image_url ?? null,
5030
+ fallbackIcon: GraduationCapIcon,
5031
+ ...props
5032
+ });
5033
+ };
5034
+ //#endregion
4645
5035
  //#region ../../file-picker/ui/src/hooks/use-unsplash-picker.ts
4646
5036
  const useUnsplashPicker = (options) => {
4647
5037
  const { controlledSearchQuery, onControlledSearchQueryChange } = options ?? {};
@@ -6012,7 +6402,7 @@ const ComputerUpload = ({ config, onFilesSelected, enableShareableOption = false
6012
6402
  };
6013
6403
  //#endregion
6014
6404
  //#region ../../file-picker/ui/src/components/FilePickerContent.tsx
6015
- const FilePickerContent = ({ activeMethod, config, damTypeFilter, sortOption, onFilesSelected, onSingleFileSelected, enableShareableOption, shareableEnabled, onShareableChange, damLibraryRef, onDamConfirmAndMaybeCreate, selectedMediaIds, onMediaIdsChange, onMediaSelectionChange, onMediaDataChange, onDamSelectionChange, onDamSearchingChange, skipCropper = false, damSearchQuery = "", onDamSearchChange, mediaSearchQuery, onMediaSearchChange, unsplashSearchQuery, onUnsplashSearchChange, onUnsplashSearchingChange, onUnsplashUploadingChange, thumbnailSize = 100, viewMode = "grid", showNamesOnMedia = true, onDamFoldersChange, previewContainer, previewMedia, onPreviewMediaChange, previewAsset, onPreviewAssetChange, uploadSelectionCount }) => {
6405
+ const FilePickerContent = ({ activeMethod, config, damTypeFilter, sortOption, onFilesSelected, onSingleFileSelected, enableShareableOption, shareableEnabled, onShareableChange, damLibraryRef, onDamConfirmAndMaybeCreate, selectedMediaIds, onMediaIdsChange, onMediaSelectionChange, onMediaDataChange, selectedPageIds, onPageIdsChange, onPageSelectionChange, onPageDataChange, selectedProductIds, onProductIdsChange, onProductSelectionChange, onProductDataChange, selectedEnrollmentPackIds, onEnrollmentPackIdsChange, onEnrollmentPackSelectionChange, onEnrollmentPackDataChange, onDamSelectionChange, onDamSearchingChange, skipCropper = false, damSearchQuery = "", onDamSearchChange, mediaSearchQuery, onMediaSearchChange, unsplashSearchQuery, onUnsplashSearchChange, onUnsplashSearchingChange, onUnsplashUploadingChange, thumbnailSize = 100, viewMode = "grid", showNamesOnMedia = true, onDamFoldersChange, previewContainer, previewMedia, onPreviewMediaChange, previewAsset, onPreviewAssetChange, uploadSelectionCount }) => {
6016
6406
  const damConfig = React.useMemo(() => ({
6017
6407
  ...config,
6018
6408
  fileTypeFilter: damTypeFilter ? [damTypeFilter] : config.fileTypeFilter
@@ -6076,6 +6466,36 @@ const FilePickerContent = ({ activeMethod, config, damTypeFilter, sortOption, on
6076
6466
  previewMedia,
6077
6467
  onPreviewMediaChange
6078
6468
  }),
6469
+ activeMethod === "pages" && /* @__PURE__ */ jsx(PagesTab, {
6470
+ config,
6471
+ selectedIds: selectedPageIds ?? [],
6472
+ onSelectedIdsChange: onPageIdsChange ?? (() => {}),
6473
+ onSelectedDataChange: onPageDataChange ?? (() => {}),
6474
+ onSelectionCountChange: onPageSelectionChange,
6475
+ thumbnailSize,
6476
+ viewMode,
6477
+ showNamesOnMedia
6478
+ }),
6479
+ activeMethod === "products" && /* @__PURE__ */ jsx(ProductsTab, {
6480
+ config,
6481
+ selectedIds: selectedProductIds ?? [],
6482
+ onSelectedIdsChange: onProductIdsChange ?? (() => {}),
6483
+ onSelectedDataChange: onProductDataChange ?? (() => {}),
6484
+ onSelectionCountChange: onProductSelectionChange,
6485
+ thumbnailSize,
6486
+ viewMode,
6487
+ showNamesOnMedia
6488
+ }),
6489
+ activeMethod === "enrollment_packs" && /* @__PURE__ */ jsx(EnrollmentPacksTab, {
6490
+ config,
6491
+ selectedIds: selectedEnrollmentPackIds ?? [],
6492
+ onSelectedIdsChange: onEnrollmentPackIdsChange ?? (() => {}),
6493
+ onSelectedDataChange: onEnrollmentPackDataChange ?? (() => {}),
6494
+ onSelectionCountChange: onEnrollmentPackSelectionChange,
6495
+ thumbnailSize,
6496
+ viewMode,
6497
+ showNamesOnMedia
6498
+ }),
6079
6499
  activeMethod === "unsplash" && /* @__PURE__ */ jsx(UnsplashPicker, {
6080
6500
  config,
6081
6501
  onFileSelected: onSingleFileSelected,
@@ -6528,6 +6948,16 @@ const FilePicker = ({ config: configInput = {}, onFilesSelected, onClose, open,
6528
6948
  const [damFolders, setDamFolders] = useState([]);
6529
6949
  const [selectedMediaIds, setSelectedMediaIds] = useState([]);
6530
6950
  const [selectedMediaData, setSelectedMediaData] = useState([]);
6951
+ const [selectedPageIds, setSelectedPageIds] = useState([]);
6952
+ const [selectedPageData, setSelectedPageData] = useState([]);
6953
+ const [pageSelectionCount, setPageSelectionCount] = useState(0);
6954
+ const [selectedProductIds, setSelectedProductIds] = useState([]);
6955
+ const [selectedProductData, setSelectedProductData] = useState([]);
6956
+ const [productSelectionCount, setProductSelectionCount] = useState(0);
6957
+ const [selectedEnrollmentPackIds, setSelectedEnrollmentPackIds] = useState([]);
6958
+ const [selectedEnrollmentPackData, setSelectedEnrollmentPackData] = useState([]);
6959
+ const [enrollmentPackSelectionCount, setEnrollmentPackSelectionCount] = useState(0);
6960
+ const [unifiedItems, setUnifiedItems] = useState([]);
6531
6961
  const damLibraryRef = useRef(null);
6532
6962
  const [previewContainer, setPreviewContainer] = useState(null);
6533
6963
  const [previewAsset, setPreviewAsset] = useState(null);
@@ -6548,26 +6978,47 @@ const FilePicker = ({ config: configInput = {}, onFilesSelected, onClose, open,
6548
6978
  setMediaSelectionCount(0);
6549
6979
  setSelectedMediaIds([]);
6550
6980
  setSelectedMediaData([]);
6981
+ setSelectedPageIds([]);
6982
+ setSelectedPageData([]);
6983
+ setPageSelectionCount(0);
6984
+ setSelectedProductIds([]);
6985
+ setSelectedProductData([]);
6986
+ setProductSelectionCount(0);
6987
+ setSelectedEnrollmentPackIds([]);
6988
+ setSelectedEnrollmentPackData([]);
6989
+ setEnrollmentPackSelectionCount(0);
6990
+ setUnifiedItems([]);
6551
6991
  setDamFilters(defaultFilters);
6552
6992
  setSortOption(void 0);
6553
6993
  damLibraryRef.current?.clearSelection?.();
6554
6994
  setPreviewAsset(null);
6555
6995
  }, [defaultTab]);
6556
6996
  const handleMethodChange = useCallback((newMethod) => {
6557
- setSelectedResults([]);
6558
- setDamSelectionCount(0);
6559
- setDamSelectedFiles([]);
6560
- setDamVariantCounts({});
6561
- setDamSearchQuery("");
6562
- setUnsplashSearchQuery("");
6563
- setUnsplashSearching(false);
6564
- setIsUnsplashUploading(false);
6565
- setMediaSelectionCount(0);
6566
- setSelectedMediaIds([]);
6567
- setSelectedMediaData([]);
6568
- damLibraryRef.current?.clearSelection?.();
6997
+ if (!config.unifiedSelection) {
6998
+ setSelectedResults([]);
6999
+ setDamSelectionCount(0);
7000
+ setDamSelectedFiles([]);
7001
+ setDamVariantCounts({});
7002
+ setDamSearchQuery("");
7003
+ setUnsplashSearchQuery("");
7004
+ setUnsplashSearching(false);
7005
+ setIsUnsplashUploading(false);
7006
+ setMediaSelectionCount(0);
7007
+ setSelectedMediaIds([]);
7008
+ setSelectedMediaData([]);
7009
+ setSelectedPageIds([]);
7010
+ setSelectedPageData([]);
7011
+ setPageSelectionCount(0);
7012
+ setSelectedProductIds([]);
7013
+ setSelectedProductData([]);
7014
+ setProductSelectionCount(0);
7015
+ setSelectedEnrollmentPackIds([]);
7016
+ setSelectedEnrollmentPackData([]);
7017
+ setEnrollmentPackSelectionCount(0);
7018
+ damLibraryRef.current?.clearSelection?.();
7019
+ }
6569
7020
  setActiveMethod(newMethod);
6570
- }, []);
7021
+ }, [config.unifiedSelection]);
6571
7022
  const handleFilesSelected = useCallback((results) => {
6572
7023
  const validResults = results.filter((result) => result.upload_status !== "error");
6573
7024
  if (config.maxFiles === 1) setSelectedResults(validResults.slice(0, 1));
@@ -6610,8 +7061,9 @@ const FilePicker = ({ config: configInput = {}, onFilesSelected, onClose, open,
6610
7061
  onFilesSelected(results);
6611
7062
  onClose?.();
6612
7063
  }, [onFilesSelected, onClose]);
7064
+ const { shareablesClient, toast } = useFilePickerContext();
6613
7065
  const methods = useMemo(() => {
6614
- const allMethods = [
7066
+ const filteredBySource = [
6615
7067
  {
6616
7068
  id: "dam",
6617
7069
  label: "Library",
@@ -6624,6 +7076,24 @@ const FilePicker = ({ config: configInput = {}, onFilesSelected, onClose, open,
6624
7076
  icon: ImagesIcon,
6625
7077
  description: "Choose from existing media"
6626
7078
  }] : [],
7079
+ {
7080
+ id: "pages",
7081
+ label: "Pages",
7082
+ icon: FileTextIcon,
7083
+ description: "Choose from existing pages"
7084
+ },
7085
+ {
7086
+ id: "products",
7087
+ label: "Products",
7088
+ icon: PackageIcon,
7089
+ description: "Choose from existing products"
7090
+ },
7091
+ {
7092
+ id: "enrollment_packs",
7093
+ label: "Enrollment Packs",
7094
+ icon: GraduationCapIcon,
7095
+ description: "Choose from existing enrollment packs"
7096
+ },
6627
7097
  {
6628
7098
  id: "upload",
6629
7099
  label: "Local Files",
@@ -6672,11 +7142,275 @@ const FilePicker = ({ config: configInput = {}, onFilesSelected, onClose, open,
6672
7142
  icon: DropboxIcon,
6673
7143
  description: "Import from Dropbox"
6674
7144
  }
6675
- ];
6676
- if (config.allowedMethods && config.allowedMethods.length > 0) return allMethods.filter((method) => config.allowedMethods.includes(method.id));
6677
- return allMethods;
6678
- }, [showMediaTab, config.allowedMethods]);
7145
+ ].filter((m) => {
7146
+ if (m.id === "pages") return shareablesClient?.pages != null;
7147
+ if (m.id === "products") return shareablesClient?.products != null;
7148
+ if (m.id === "enrollment_packs") return shareablesClient?.enrollment_packs != null;
7149
+ return true;
7150
+ });
7151
+ if (config.allowedMethods && config.allowedMethods.length > 0) return filteredBySource.filter((method) => config.allowedMethods.includes(method.id));
7152
+ return filteredBySource;
7153
+ }, [
7154
+ showMediaTab,
7155
+ config.allowedMethods,
7156
+ shareablesClient
7157
+ ]);
6679
7158
  const showPreview = previewAsset !== null;
7159
+ const unifiedSelectionState = useMemo(() => ({ items: unifiedItems }), [unifiedItems]);
7160
+ const unifiedItemsRef = useRef(unifiedItems);
7161
+ useEffect(() => {
7162
+ unifiedItemsRef.current = unifiedItems;
7163
+ }, [unifiedItems]);
7164
+ const unifiedApi = useMemo(() => ({
7165
+ add: (item) => {
7166
+ const current = unifiedItemsRef.current;
7167
+ if (current.some((r) => r.asset_code === item.asset_code)) return;
7168
+ if (config.maxFiles && current.length >= config.maxFiles) {
7169
+ toast.error(`You can select up to ${config.maxFiles} items at a time.`);
7170
+ return;
7171
+ }
7172
+ setUnifiedItems((prev) => {
7173
+ if (prev.some((r) => r.asset_code === item.asset_code)) return prev;
7174
+ if (config.maxFiles && prev.length >= config.maxFiles) return prev;
7175
+ return [...prev, item];
7176
+ });
7177
+ },
7178
+ remove: (assetCode) => {
7179
+ setUnifiedItems((prev) => prev.filter((r) => r.asset_code !== assetCode));
7180
+ },
7181
+ clear: () => setUnifiedItems([]),
7182
+ isSelected: (assetCode) => unifiedItemsRef.current.some((r) => r.asset_code === assetCode),
7183
+ selectionIndex: (assetCode) => unifiedItemsRef.current.findIndex((r) => r.asset_code === assetCode) + 1
7184
+ }), [config.maxFiles, toast]);
7185
+ const body = /* @__PURE__ */ jsxs("div", {
7186
+ className: "flex flex-1 overflow-y-auto",
7187
+ children: [/* @__PURE__ */ jsx(FilePickerSidebar, {
7188
+ currentStep: "select",
7189
+ activeMethod,
7190
+ onMethodChange: handleMethodChange,
7191
+ methods
7192
+ }), /* @__PURE__ */ jsxs("div", {
7193
+ className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden",
7194
+ children: [/* @__PURE__ */ jsx(FilePickerHeader, {
7195
+ currentStep: "select",
7196
+ activeMethod,
7197
+ methods,
7198
+ onClose: () => {
7199
+ resetPicker();
7200
+ onClose?.();
7201
+ },
7202
+ damSearchQuery: activeMethod === "dam" ? damSearchQuery : mediaSearchQuery,
7203
+ onDamSearchChange: activeMethod === "dam" ? setDamSearchQuery : setMediaSearchQuery,
7204
+ damSearching,
7205
+ thumbnailSize,
7206
+ onThumbnailSizeChange: handleThumbnailSizeChange,
7207
+ viewMode,
7208
+ onViewModeChange: handleViewModeChange,
7209
+ showNamesOnMedia,
7210
+ onShowNamesOnMediaChange: setShowNamesOnMedia,
7211
+ hasSelectedFiles: damSelectionCount > 0,
7212
+ damFolders,
7213
+ onAddToNewFolder: () => damLibraryRef.current?.openAddFolderModal(),
7214
+ onAddToExistingFolder: (folderPath) => damLibraryRef.current?.addToExistingFolder?.(folderPath),
7215
+ filters: damFilters,
7216
+ onFiltersChange: setDamFilters,
7217
+ onFiltersClear: () => setDamFilters(defaultFilters),
7218
+ sortOption,
7219
+ onSortChange: setSortOption,
7220
+ unsplashSearchQuery,
7221
+ onUnsplashSearchChange: setUnsplashSearchQuery,
7222
+ unsplashSearching,
7223
+ isUnsplashUploading
7224
+ }), /* @__PURE__ */ jsxs("div", {
7225
+ className: "flex min-h-0 min-w-0 flex-1 overflow-hidden",
7226
+ children: [
7227
+ /* @__PURE__ */ jsx("div", {
7228
+ className: "min-h-0 min-w-0 flex-1 overflow-y-auto",
7229
+ children: /* @__PURE__ */ jsx(FilePickerContent, {
7230
+ activeMethod,
7231
+ config,
7232
+ damTypeFilter: damFilters.type ? damFilters.type : void 0,
7233
+ sortOption,
7234
+ onFilesSelected: handleFilesSelected,
7235
+ onUploadConfirmAndMaybeCreate: handleUploadConfirm,
7236
+ onSingleFileSelected: handleSingleFileSelected,
7237
+ damLibraryRef,
7238
+ onDamConfirmAndMaybeCreate: handleDamConfirm,
7239
+ selectedMediaIds,
7240
+ onMediaIdsChange: setSelectedMediaIds,
7241
+ onMediaSelectionChange: handleMediaSelectionChange,
7242
+ onMediaDataChange: handleMediaDataChange,
7243
+ selectedPageIds,
7244
+ onPageIdsChange: setSelectedPageIds,
7245
+ onPageSelectionChange: setPageSelectionCount,
7246
+ onPageDataChange: setSelectedPageData,
7247
+ selectedProductIds,
7248
+ onProductIdsChange: setSelectedProductIds,
7249
+ onProductSelectionChange: setProductSelectionCount,
7250
+ onProductDataChange: setSelectedProductData,
7251
+ selectedEnrollmentPackIds,
7252
+ onEnrollmentPackIdsChange: setSelectedEnrollmentPackIds,
7253
+ onEnrollmentPackSelectionChange: setEnrollmentPackSelectionCount,
7254
+ onEnrollmentPackDataChange: setSelectedEnrollmentPackData,
7255
+ onDamSelectionChange: handleDamSelectionChange,
7256
+ onDamSearchingChange: setDamSearching,
7257
+ skipCropper,
7258
+ damSearchQuery,
7259
+ onDamSearchChange: setDamSearchQuery,
7260
+ mediaSearchQuery,
7261
+ onMediaSearchChange: setMediaSearchQuery,
7262
+ unsplashSearchQuery,
7263
+ onUnsplashSearchChange: setUnsplashSearchQuery,
7264
+ onUnsplashSearchingChange: setUnsplashSearching,
7265
+ onUnsplashUploadingChange: setIsUnsplashUploading,
7266
+ thumbnailSize,
7267
+ viewMode,
7268
+ showNamesOnMedia,
7269
+ onDamFoldersChange: setDamFolders,
7270
+ previewContainer,
7271
+ previewAsset,
7272
+ onPreviewAssetChange: setPreviewAsset,
7273
+ uploadSelectionCount: activeMethod === "upload" || activeMethod === "url" || activeMethod === "unsplash" ? selectedResults.length : void 0
7274
+ })
7275
+ }),
7276
+ activeMethod === "dam" && /* @__PURE__ */ jsx(SelectionPanel, {
7277
+ selectedFiles: damSelectedFiles,
7278
+ onRemoveFile: (assetCode) => {
7279
+ damLibraryRef.current?.deselectAssetByCode?.(assetCode);
7280
+ },
7281
+ onClear: () => {
7282
+ damLibraryRef.current?.clearSelection();
7283
+ setDamSelectionCount(0);
7284
+ setDamSelectedFiles([]);
7285
+ setDamVariantCounts({});
7286
+ },
7287
+ onConfirm: () => {
7288
+ damLibraryRef.current?.confirmAndClose();
7289
+ },
7290
+ isVisible: damSelectionCount > 0,
7291
+ hasVariants: (assetCode) => (damVariantCounts[assetCode] ?? 0) > 1,
7292
+ getAssetWithVariants: (assetCode) => damLibraryRef.current?.getAssetWithVariants?.(assetCode) ?? null,
7293
+ onVariantChange: (assetCode, variantId) => {
7294
+ damLibraryRef.current?.setVariantForAsset?.(assetCode, variantId);
7295
+ }
7296
+ }),
7297
+ !config.unifiedSelection && activeMethod === "media" && /* @__PURE__ */ jsx(SelectionPanel, {
7298
+ selectedFiles: selectedMediaData,
7299
+ onRemoveFile: (assetCode) => {
7300
+ const id = parseInt(assetCode.replace(/^media_/, ""), 10);
7301
+ if (!Number.isNaN(id)) {
7302
+ setSelectedMediaIds((prev) => prev.filter((mediaId) => mediaId !== id));
7303
+ setSelectedMediaData((prev) => prev.filter((r) => r.asset_code !== assetCode));
7304
+ }
7305
+ },
7306
+ onClear: () => {
7307
+ setSelectedMediaIds([]);
7308
+ setSelectedMediaData([]);
7309
+ setMediaSelectionCount(0);
7310
+ },
7311
+ onConfirm: () => {
7312
+ onFilesSelected(selectedMediaData);
7313
+ onClose?.();
7314
+ },
7315
+ isVisible: mediaSelectionCount > 0,
7316
+ hasVariants: () => false
7317
+ }),
7318
+ !config.unifiedSelection && activeMethod === "pages" && /* @__PURE__ */ jsx(SelectionPanel, {
7319
+ selectedFiles: selectedPageData,
7320
+ onRemoveFile: (assetCode) => {
7321
+ const id = parseInt(assetCode.replace(/^page_/, ""), 10);
7322
+ if (!Number.isNaN(id)) {
7323
+ setSelectedPageIds((prev) => prev.filter((pageId) => pageId !== id));
7324
+ setSelectedPageData((prev) => prev.filter((r) => r.asset_code !== assetCode));
7325
+ }
7326
+ },
7327
+ onClear: () => {
7328
+ setSelectedPageIds([]);
7329
+ setSelectedPageData([]);
7330
+ setPageSelectionCount(0);
7331
+ },
7332
+ onConfirm: () => {
7333
+ onFilesSelected(selectedPageData);
7334
+ onClose?.();
7335
+ },
7336
+ isVisible: pageSelectionCount > 0,
7337
+ hasVariants: () => false
7338
+ }),
7339
+ !config.unifiedSelection && activeMethod === "products" && /* @__PURE__ */ jsx(SelectionPanel, {
7340
+ selectedFiles: selectedProductData,
7341
+ onRemoveFile: (assetCode) => {
7342
+ const id = parseInt(assetCode.replace(/^product_/, ""), 10);
7343
+ if (!Number.isNaN(id)) {
7344
+ setSelectedProductIds((prev) => prev.filter((productId) => productId !== id));
7345
+ setSelectedProductData((prev) => prev.filter((r) => r.asset_code !== assetCode));
7346
+ }
7347
+ },
7348
+ onClear: () => {
7349
+ setSelectedProductIds([]);
7350
+ setSelectedProductData([]);
7351
+ setProductSelectionCount(0);
7352
+ },
7353
+ onConfirm: () => {
7354
+ onFilesSelected(selectedProductData);
7355
+ onClose?.();
7356
+ },
7357
+ isVisible: productSelectionCount > 0,
7358
+ hasVariants: () => false
7359
+ }),
7360
+ !config.unifiedSelection && activeMethod === "enrollment_packs" && /* @__PURE__ */ jsx(SelectionPanel, {
7361
+ selectedFiles: selectedEnrollmentPackData,
7362
+ onRemoveFile: (assetCode) => {
7363
+ const id = parseInt(assetCode.replace(/^enrollment_pack_/, ""), 10);
7364
+ if (!Number.isNaN(id)) {
7365
+ setSelectedEnrollmentPackIds((prev) => prev.filter((packId) => packId !== id));
7366
+ setSelectedEnrollmentPackData((prev) => prev.filter((r) => r.asset_code !== assetCode));
7367
+ }
7368
+ },
7369
+ onClear: () => {
7370
+ setSelectedEnrollmentPackIds([]);
7371
+ setSelectedEnrollmentPackData([]);
7372
+ setEnrollmentPackSelectionCount(0);
7373
+ },
7374
+ onConfirm: () => {
7375
+ onFilesSelected(selectedEnrollmentPackData);
7376
+ onClose?.();
7377
+ },
7378
+ isVisible: enrollmentPackSelectionCount > 0,
7379
+ hasVariants: () => false
7380
+ }),
7381
+ !config.unifiedSelection && (activeMethod === "upload" || activeMethod === "url" || activeMethod === "unsplash") && /* @__PURE__ */ jsx(SelectionPanel, {
7382
+ selectedFiles: selectedResults,
7383
+ onRemoveFile: (assetCode) => {
7384
+ setSelectedResults((prev) => prev.filter((r) => r.asset_code !== assetCode));
7385
+ },
7386
+ onClear: () => {
7387
+ setSelectedResults([]);
7388
+ },
7389
+ onConfirm: () => {
7390
+ handleUploadConfirm(selectedResults);
7391
+ },
7392
+ isVisible: selectedResults.length > 0,
7393
+ hasVariants: () => false
7394
+ }),
7395
+ config.unifiedSelection && /* @__PURE__ */ jsx(SelectionPanel, {
7396
+ selectedFiles: unifiedItems,
7397
+ onRemoveFile: (assetCode) => {
7398
+ setUnifiedItems((prev) => prev.filter((r) => r.asset_code !== assetCode));
7399
+ },
7400
+ onClear: () => {
7401
+ setUnifiedItems([]);
7402
+ },
7403
+ onConfirm: () => {
7404
+ onFilesSelected(unifiedItems);
7405
+ onClose?.();
7406
+ },
7407
+ isVisible: unifiedItems.length > 0,
7408
+ hasVariants: () => false
7409
+ })
7410
+ ]
7411
+ })]
7412
+ })]
7413
+ });
6680
7414
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [typeof document !== "undefined" && createPortal(/* @__PURE__ */ jsx("div", {
6681
7415
  ref: setPreviewContainer,
6682
7416
  className: "fixed inset-0",
@@ -6698,145 +7432,11 @@ const FilePicker = ({ config: configInput = {}, onFilesSelected, onClose, open,
6698
7432
  children: [/* @__PURE__ */ jsx(DialogTitle, {
6699
7433
  className: "sr-only",
6700
7434
  children: "File Picker"
6701
- }), /* @__PURE__ */ jsxs("div", {
6702
- className: "flex flex-1 overflow-y-auto",
6703
- children: [/* @__PURE__ */ jsx(FilePickerSidebar, {
6704
- currentStep: "select",
6705
- activeMethod,
6706
- onMethodChange: handleMethodChange,
6707
- methods
6708
- }), /* @__PURE__ */ jsxs("div", {
6709
- className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden",
6710
- children: [/* @__PURE__ */ jsx(FilePickerHeader, {
6711
- currentStep: "select",
6712
- activeMethod,
6713
- methods,
6714
- onClose: () => {
6715
- resetPicker();
6716
- onClose?.();
6717
- },
6718
- damSearchQuery: activeMethod === "dam" ? damSearchQuery : mediaSearchQuery,
6719
- onDamSearchChange: activeMethod === "dam" ? setDamSearchQuery : setMediaSearchQuery,
6720
- damSearching,
6721
- thumbnailSize,
6722
- onThumbnailSizeChange: handleThumbnailSizeChange,
6723
- viewMode,
6724
- onViewModeChange: handleViewModeChange,
6725
- showNamesOnMedia,
6726
- onShowNamesOnMediaChange: setShowNamesOnMedia,
6727
- hasSelectedFiles: damSelectionCount > 0,
6728
- damFolders,
6729
- onAddToNewFolder: () => damLibraryRef.current?.openAddFolderModal(),
6730
- onAddToExistingFolder: (folderPath) => damLibraryRef.current?.addToExistingFolder?.(folderPath),
6731
- filters: damFilters,
6732
- onFiltersChange: setDamFilters,
6733
- onFiltersClear: () => setDamFilters(defaultFilters),
6734
- sortOption,
6735
- onSortChange: setSortOption,
6736
- unsplashSearchQuery,
6737
- onUnsplashSearchChange: setUnsplashSearchQuery,
6738
- unsplashSearching,
6739
- isUnsplashUploading
6740
- }), /* @__PURE__ */ jsxs("div", {
6741
- className: "flex min-h-0 min-w-0 flex-1 overflow-hidden",
6742
- children: [
6743
- /* @__PURE__ */ jsx("div", {
6744
- className: "min-h-0 min-w-0 flex-1 overflow-y-auto",
6745
- children: /* @__PURE__ */ jsx(FilePickerContent, {
6746
- activeMethod,
6747
- config,
6748
- damTypeFilter: damFilters.type ? damFilters.type : void 0,
6749
- sortOption,
6750
- onFilesSelected: handleFilesSelected,
6751
- onUploadConfirmAndMaybeCreate: handleUploadConfirm,
6752
- onSingleFileSelected: handleSingleFileSelected,
6753
- damLibraryRef,
6754
- onDamConfirmAndMaybeCreate: handleDamConfirm,
6755
- selectedMediaIds,
6756
- onMediaIdsChange: setSelectedMediaIds,
6757
- onMediaSelectionChange: handleMediaSelectionChange,
6758
- onMediaDataChange: handleMediaDataChange,
6759
- onDamSelectionChange: handleDamSelectionChange,
6760
- onDamSearchingChange: setDamSearching,
6761
- skipCropper,
6762
- damSearchQuery,
6763
- onDamSearchChange: setDamSearchQuery,
6764
- mediaSearchQuery,
6765
- onMediaSearchChange: setMediaSearchQuery,
6766
- unsplashSearchQuery,
6767
- onUnsplashSearchChange: setUnsplashSearchQuery,
6768
- onUnsplashSearchingChange: setUnsplashSearching,
6769
- onUnsplashUploadingChange: setIsUnsplashUploading,
6770
- thumbnailSize,
6771
- viewMode,
6772
- showNamesOnMedia,
6773
- onDamFoldersChange: setDamFolders,
6774
- previewContainer,
6775
- previewAsset,
6776
- onPreviewAssetChange: setPreviewAsset,
6777
- uploadSelectionCount: activeMethod === "upload" || activeMethod === "url" || activeMethod === "unsplash" ? selectedResults.length : void 0
6778
- })
6779
- }),
6780
- activeMethod === "dam" && /* @__PURE__ */ jsx(SelectionPanel, {
6781
- selectedFiles: damSelectedFiles,
6782
- onRemoveFile: (assetCode) => {
6783
- damLibraryRef.current?.deselectAssetByCode?.(assetCode);
6784
- },
6785
- onClear: () => {
6786
- damLibraryRef.current?.clearSelection();
6787
- setDamSelectionCount(0);
6788
- setDamSelectedFiles([]);
6789
- setDamVariantCounts({});
6790
- },
6791
- onConfirm: () => {
6792
- damLibraryRef.current?.confirmAndClose();
6793
- },
6794
- isVisible: damSelectionCount > 0,
6795
- hasVariants: (assetCode) => (damVariantCounts[assetCode] ?? 0) > 1,
6796
- getAssetWithVariants: (assetCode) => damLibraryRef.current?.getAssetWithVariants?.(assetCode) ?? null,
6797
- onVariantChange: (assetCode, variantId) => {
6798
- damLibraryRef.current?.setVariantForAsset?.(assetCode, variantId);
6799
- }
6800
- }),
6801
- activeMethod === "media" && /* @__PURE__ */ jsx(SelectionPanel, {
6802
- selectedFiles: selectedMediaData,
6803
- onRemoveFile: (assetCode) => {
6804
- const id = parseInt(assetCode.replace(/^media_/, ""), 10);
6805
- if (!Number.isNaN(id)) {
6806
- setSelectedMediaIds((prev) => prev.filter((mediaId) => mediaId !== id));
6807
- setSelectedMediaData((prev) => prev.filter((r) => r.asset_code !== assetCode));
6808
- }
6809
- },
6810
- onClear: () => {
6811
- setSelectedMediaIds([]);
6812
- setSelectedMediaData([]);
6813
- setMediaSelectionCount(0);
6814
- },
6815
- onConfirm: () => {
6816
- onFilesSelected(selectedMediaData);
6817
- onClose?.();
6818
- },
6819
- isVisible: mediaSelectionCount > 0,
6820
- hasVariants: () => false
6821
- }),
6822
- (activeMethod === "upload" || activeMethod === "url" || activeMethod === "unsplash") && /* @__PURE__ */ jsx(SelectionPanel, {
6823
- selectedFiles: selectedResults,
6824
- onRemoveFile: (assetCode) => {
6825
- setSelectedResults((prev) => prev.filter((r) => r.asset_code !== assetCode));
6826
- },
6827
- onClear: () => {
6828
- setSelectedResults([]);
6829
- },
6830
- onConfirm: () => {
6831
- handleUploadConfirm(selectedResults);
6832
- },
6833
- isVisible: selectedResults.length > 0,
6834
- hasVariants: () => false
6835
- })
6836
- ]
6837
- })]
6838
- })]
6839
- })]
7435
+ }), config.unifiedSelection ? /* @__PURE__ */ jsx(FilePickerSelectionScope, {
7436
+ state: unifiedSelectionState,
7437
+ api: unifiedApi,
7438
+ children: body
7439
+ }) : body]
6840
7440
  })
6841
7441
  })] });
6842
7442
  };
@@ -9672,13 +10272,14 @@ function PlaylistDetailScreen({ playlistId, onNavigate }) {
9672
10272
  }) })
9673
10273
  ]
9674
10274
  }) }), [displayTitle, navigate]));
9675
- const selectedPlaylistItem = playlist?.items?.[selectedPlaylistItemIndex];
10275
+ const taggedProducts = playlist?.items?.filter((item) => item.relateable_type === "Product" || item.relateable_type === "EnrollmentPack").map((item) => item.relateable).filter((p) => !!p) || [];
10276
+ const playableItems = playlist?.items?.filter((item) => item.relateable_type === "Medium" || item.relateable_type === "Page") ?? [];
10277
+ const selectedPlaylistItem = playableItems[selectedPlaylistItemIndex] ?? playableItems[0];
9676
10278
  const displayImage = selectedPlaylistItem?.image_url ?? selectedPlaylistItem?.relateable?.image_url ?? selectedPlaylistItem?.relateable?.compressed_image_url ?? DEFAULT_IMAGE$2;
9677
10279
  const displayDescription = playlist?.description || playlist?.search_engine_optimizer?.description || "";
9678
10280
  const selectedKind = selectedPlaylistItem?.kind ?? selectedPlaylistItem?.relateable?.kind;
9679
10281
  const displayVideo = selectedKind === "video" ? selectedPlaylistItem?.video_url ?? selectedPlaylistItem?.relateable?.video_url ?? void 0 : void 0;
9680
10282
  const isVideo = selectedKind === "video" && !!displayVideo;
9681
- const taggedProducts = playlist?.items?.filter((item) => item.relateable_type === "Product").map((item) => item.relateable).filter((p) => !!p) || [];
9682
10283
  return /* @__PURE__ */ jsxs(ShareableDetailLayout, {
9683
10284
  isLoading,
9684
10285
  notFound: !playlist,
@@ -9710,7 +10311,7 @@ function PlaylistDetailScreen({ playlistId, onNavigate }) {
9710
10311
  products: taggedProducts,
9711
10312
  onProductClick: (productId) => onNavigate?.("product", String(productId))
9712
10313
  }), /* @__PURE__ */ jsx(PlaylistItemsList, {
9713
- items: playlist?.items || [],
10314
+ items: playableItems,
9714
10315
  onSelectItem: setSelectedPlaylistItemIndex,
9715
10316
  selectedItemIndex: selectedPlaylistItemIndex,
9716
10317
  onNavigateToItem: (itemId, relateableType) => {
@@ -10231,19 +10832,42 @@ function SortableTable({ items, setItems, onDeleteItem, isDeletePending, enableR
10231
10832
  //#endregion
10232
10833
  //#region ../../shareables/ui/src/components/playlists/form/PlaylistItemsSection.tsx
10233
10834
  const REORDER_DEBOUNCE_MS = 500;
10234
- const PLAYLIST_CONTENT_TYPES = new Set([
10235
- "Medium",
10236
- "Page",
10237
- "Product",
10238
- "EnrollmentPack"
10239
- ]);
10835
+ const CONTENT_TYPES = [
10836
+ {
10837
+ prefix: "media_",
10838
+ relateableType: "Medium",
10839
+ section: "primary"
10840
+ },
10841
+ {
10842
+ prefix: "page_",
10843
+ relateableType: "Page",
10844
+ section: "primary"
10845
+ },
10846
+ {
10847
+ prefix: "product_",
10848
+ relateableType: "Product",
10849
+ section: "tagged"
10850
+ },
10851
+ {
10852
+ prefix: "enrollment_pack_",
10853
+ relateableType: "EnrollmentPack",
10854
+ section: "tagged"
10855
+ }
10856
+ ];
10857
+ const PRIMARY_CONTENT_TYPES = new Set(CONTENT_TYPES.filter((c) => c.section === "primary").map((c) => c.relateableType));
10858
+ const TAGGED_CONTENT_TYPES = new Set(CONTENT_TYPES.filter((c) => c.section === "tagged").map((c) => c.relateableType));
10859
+ new Set(CONTENT_TYPES.map((c) => c.relateableType));
10860
+ function deriveRelateableType(assetCode) {
10861
+ for (const entry of CONTENT_TYPES) if (assetCode.startsWith(entry.prefix)) return entry.relateableType;
10862
+ return null;
10863
+ }
10240
10864
  function computeOrderedItems(items) {
10241
10865
  const required = [];
10242
10866
  const optional = [];
10243
10867
  items.forEach((item) => {
10244
10868
  const type = item.relateable_type;
10245
- if (type === "Medium" || type === "Page") required.push(item);
10246
- else if (type === "Product" || type === "EnrollmentPack") optional.push(item);
10869
+ if (type && PRIMARY_CONTENT_TYPES.has(type)) required.push(item);
10870
+ else if (type && TAGGED_CONTENT_TYPES.has(type)) optional.push(item);
10247
10871
  });
10248
10872
  const result = [];
10249
10873
  required.forEach((item, index) => {
@@ -10260,22 +10884,36 @@ function computeOrderedItems(items) {
10260
10884
  });
10261
10885
  return result;
10262
10886
  }
10887
+ const SECTIONS = {
10888
+ primary: {
10889
+ heading: "Playlist Items",
10890
+ description: "Manage the media and pages in your playlist. At least one is required.",
10891
+ allowedMethods: ["media", "pages"],
10892
+ allowedRelateableTypes: PRIMARY_CONTENT_TYPES
10893
+ },
10894
+ tagged: {
10895
+ heading: "Tagged Products",
10896
+ description: "Manage the products and enrollments in your playlist. These items will show as recommended items in the cart.",
10897
+ allowedMethods: ["products", "enrollment_packs"],
10898
+ allowedRelateableTypes: TAGGED_CONTENT_TYPES
10899
+ }
10900
+ };
10263
10901
  function PlaylistItemsSection({ playlistId }) {
10264
- const { showToast, filePickerApi } = useShareablesUI();
10902
+ const { showToast, filePickerApi, pickerSources } = useShareablesUI();
10265
10903
  const api = useShareablesApi();
10266
- const [filePickerOpen, setFilePickerOpen] = useState(false);
10904
+ const [openSection, setOpenSection] = useState(null);
10267
10905
  const { items: contextItems, updateItems, addItem, removeItem } = usePlaylistItems();
10268
10906
  const tableItems = contextItems;
10269
- const { contentItems, tailItems } = useMemo(() => {
10270
- const content = [];
10271
- const tail = [];
10907
+ const { primaryItems, taggedItems } = useMemo(() => {
10908
+ const primary = [];
10909
+ const tagged = [];
10272
10910
  tableItems.forEach((item) => {
10273
- if (item.relateable_type && PLAYLIST_CONTENT_TYPES.has(item.relateable_type)) content.push(item);
10274
- else tail.push(item);
10911
+ if (item.relateable_type && PRIMARY_CONTENT_TYPES.has(item.relateable_type)) primary.push(item);
10912
+ else if (item.relateable_type && TAGGED_CONTENT_TYPES.has(item.relateable_type)) tagged.push(item);
10275
10913
  });
10276
10914
  return {
10277
- contentItems: content,
10278
- tailItems: tail
10915
+ primaryItems: primary,
10916
+ taggedItems: tagged
10279
10917
  };
10280
10918
  }, [tableItems]);
10281
10919
  const addItemMutation = useAddItemToPlaylistMutation({ onError: (error) => {
@@ -10307,8 +10945,8 @@ function PlaylistItemsSection({ playlistId }) {
10307
10945
  if (reorderTimerRef.current) clearTimeout(reorderTimerRef.current);
10308
10946
  }, []);
10309
10947
  const canPersistReorder = !!api.playlists.reorderPlaylistItems;
10310
- const mergeAndOrder = useCallback((reorderedContent) => {
10311
- const ordered = computeOrderedItems([...reorderedContent, ...tailItems]);
10948
+ const mergeAndOrder = useCallback((reordered, whichSection) => {
10949
+ const ordered = computeOrderedItems(whichSection === "primary" ? [...reordered, ...taggedItems] : [...primaryItems, ...reordered]);
10312
10950
  if (playlistId && canPersistReorder && reorderTimerRef.current === null && reorderRollbackRef.current === null) reorderRollbackRef.current = tableItems;
10313
10951
  updateItems(ordered);
10314
10952
  if (!playlistId || !canPersistReorder) return;
@@ -10339,7 +10977,8 @@ function PlaylistItemsSection({ playlistId }) {
10339
10977
  });
10340
10978
  }, REORDER_DEBOUNCE_MS);
10341
10979
  }, [
10342
- tailItems,
10980
+ primaryItems,
10981
+ taggedItems,
10343
10982
  tableItems,
10344
10983
  updateItems,
10345
10984
  playlistId,
@@ -10354,22 +10993,23 @@ function PlaylistItemsSection({ playlistId }) {
10354
10993
  itemIds: [itemId]
10355
10994
  });
10356
10995
  };
10357
- const handleFilePickerResults = async (results) => {
10358
- setFilePickerOpen(false);
10359
- const mediaResults = results.filter((r) => r.asset_code.startsWith("media_"));
10360
- if (mediaResults.length === 0) {
10996
+ const buildResultsHandler = useCallback((section) => async (results) => {
10997
+ setOpenSection(null);
10998
+ if (results.length === 0) {
10361
10999
  showToast({
10362
- title: "No media items selected",
11000
+ title: "No items selected",
10363
11001
  type: "warning"
10364
11002
  });
10365
11003
  return;
10366
11004
  }
10367
11005
  let nextOrder = tableItems.length + 1;
10368
- for (const result of mediaResults) {
10369
- const label = result.metadata?.file_name?.replace(/\.[^/.]+$/, "") || `Medium #${result.asset_id}`;
11006
+ for (const result of results) {
11007
+ const relateableType = deriveRelateableType(result.asset_code);
11008
+ if (!relateableType) continue;
11009
+ if (!section.allowedRelateableTypes.has(relateableType)) continue;
10370
11010
  const relateableId = result.asset_id;
10371
- const relateableType = "Medium";
10372
- if (tableItems.some((existingItem) => existingItem.relateable_type === relateableType && existingItem.relateable?.id === relateableId)) {
11011
+ const label = result.metadata?.file_name || `${relateableType} #${relateableId}`;
11012
+ if (tableItems.some((existing) => existing.relateable_type === relateableType && existing.relateable?.id === relateableId)) {
10373
11013
  showToast({
10374
11014
  title: "This item is already in the playlist",
10375
11015
  type: "error"
@@ -10404,7 +11044,13 @@ function PlaylistItemsSection({ playlistId }) {
10404
11044
  } catch {}
10405
11045
  else addItem(newItem);
10406
11046
  }
10407
- };
11047
+ }, [
11048
+ tableItems,
11049
+ playlistId,
11050
+ addItemMutation,
11051
+ addItem,
11052
+ showToast
11053
+ ]);
10408
11054
  const filePickerContextValue = useMemo(() => {
10409
11055
  if (!filePickerApi) return null;
10410
11056
  return {
@@ -10420,16 +11066,75 @@ function PlaylistItemsSection({ playlistId }) {
10420
11066
  loading: () => "",
10421
11067
  dismiss: () => {}
10422
11068
  },
10423
- shareablesClient: { media: { list: (filters) => api.media.getMedia(filters ?? {}) } }
11069
+ shareablesClient: {
11070
+ media: { list: (filters) => api.media.getMedia(filters ?? {}) },
11071
+ ...pickerSources?.pages ? { pages: pickerSources.pages } : {},
11072
+ ...pickerSources?.products ? { products: pickerSources.products } : {},
11073
+ ...pickerSources?.enrollment_packs ? { enrollment_packs: pickerSources.enrollment_packs } : {}
11074
+ }
10424
11075
  };
10425
11076
  }, [
10426
11077
  filePickerApi,
10427
11078
  showToast,
10428
- api
11079
+ api,
11080
+ pickerSources
10429
11081
  ]);
11082
+ const pickerAvailable = !!filePickerApi && !!filePickerContextValue;
10430
11083
  return /* @__PURE__ */ jsxs("div", {
11084
+ className: "space-y-8",
11085
+ children: [
11086
+ /* @__PURE__ */ jsx(PlaylistItemsSubsection, {
11087
+ section: SECTIONS.primary,
11088
+ items: primaryItems,
11089
+ onAdd: () => setOpenSection("primary"),
11090
+ onReorder: (reordered) => mergeAndOrder(reordered, "primary"),
11091
+ onDeleteItem: handleDeleteItem,
11092
+ isPending: addItemMutation.isPending,
11093
+ isDeletePending: removeItemMutation.isPending,
11094
+ disableAdd: !pickerAvailable
11095
+ }),
11096
+ /* @__PURE__ */ jsx(PlaylistItemsSubsection, {
11097
+ section: SECTIONS.tagged,
11098
+ items: taggedItems,
11099
+ onAdd: () => setOpenSection("tagged"),
11100
+ onReorder: (reordered) => mergeAndOrder(reordered, "tagged"),
11101
+ onDeleteItem: handleDeleteItem,
11102
+ isPending: addItemMutation.isPending,
11103
+ isDeletePending: removeItemMutation.isPending,
11104
+ disableAdd: !pickerAvailable
11105
+ }),
11106
+ pickerAvailable && /* @__PURE__ */ jsx(FilePickerApiProvider, {
11107
+ api: filePickerApi,
11108
+ children: /* @__PURE__ */ jsxs(FilePickerProvider, {
11109
+ value: filePickerContextValue,
11110
+ children: [/* @__PURE__ */ jsx(FilePicker, {
11111
+ open: openSection === "primary",
11112
+ onClose: () => setOpenSection(null),
11113
+ onFilesSelected: (selected) => void buildResultsHandler(SECTIONS.primary)(selected),
11114
+ config: {
11115
+ maxFiles: 50,
11116
+ allowedMethods: SECTIONS.primary.allowedMethods,
11117
+ unifiedSelection: true
11118
+ }
11119
+ }), /* @__PURE__ */ jsx(FilePicker, {
11120
+ open: openSection === "tagged",
11121
+ onClose: () => setOpenSection(null),
11122
+ onFilesSelected: (selected) => void buildResultsHandler(SECTIONS.tagged)(selected),
11123
+ config: {
11124
+ maxFiles: 50,
11125
+ allowedMethods: SECTIONS.tagged.allowedMethods,
11126
+ unifiedSelection: true
11127
+ }
11128
+ })]
11129
+ })
11130
+ })
11131
+ ]
11132
+ });
11133
+ }
11134
+ function PlaylistItemsSubsection({ section, items, onAdd, onReorder, onDeleteItem, isPending, isDeletePending, disableAdd = false }) {
11135
+ return /* @__PURE__ */ jsx("div", {
10431
11136
  className: "border-border bg-card rounded-lg border p-4",
10432
- children: [/* @__PURE__ */ jsxs("div", {
11137
+ children: /* @__PURE__ */ jsxs("div", {
10433
11138
  className: "space-y-4",
10434
11139
  children: [/* @__PURE__ */ jsxs("div", {
10435
11140
  className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between",
@@ -10437,49 +11142,31 @@ function PlaylistItemsSection({ playlistId }) {
10437
11142
  className: "min-w-0",
10438
11143
  children: [/* @__PURE__ */ jsx("h3", {
10439
11144
  className: "text-md text-foreground font-semibold",
10440
- children: "Content"
10441
- }), /* @__PURE__ */ jsxs("p", {
11145
+ children: section.heading
11146
+ }), /* @__PURE__ */ jsx("p", {
10442
11147
  className: "text-muted-foreground text-sm",
10443
- children: [
10444
- "Use ",
10445
- /* @__PURE__ */ jsx("strong", { children: "Add content" }),
10446
- " to open the file picker and choose media from your library. Drag rows to reorder."
10447
- ]
11148
+ children: section.description
10448
11149
  })]
10449
11150
  }), /* @__PURE__ */ jsx("div", {
10450
11151
  className: "flex shrink-0 flex-wrap items-center justify-end gap-2",
10451
11152
  children: /* @__PURE__ */ jsxs(Button, {
10452
11153
  type: "button",
10453
- disabled: addItemMutation.isPending || !filePickerApi,
11154
+ disabled: isPending || disableAdd,
10454
11155
  variant: "default",
10455
11156
  size: "sm",
10456
11157
  className: "flex min-w-25 items-center gap-2",
10457
- onClick: () => setFilePickerOpen(true),
10458
- children: [/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }), "Add content"]
11158
+ onClick: onAdd,
11159
+ children: [/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }), "Add Item"]
10459
11160
  })
10460
11161
  })]
10461
11162
  }), /* @__PURE__ */ jsx(SortableTable, {
10462
- items: contentItems,
10463
- setItems: (reordered) => mergeAndOrder(reordered),
10464
- onDeleteItem: handleDeleteItem,
10465
- isDeletePending: removeItemMutation.isPending,
11163
+ items,
11164
+ setItems: (reordered) => onReorder(reordered),
11165
+ onDeleteItem,
11166
+ isDeletePending,
10466
11167
  enableReordering: true
10467
11168
  })]
10468
- }), filePickerContextValue && filePickerApi && /* @__PURE__ */ jsx(FilePickerApiProvider, {
10469
- api: filePickerApi,
10470
- children: /* @__PURE__ */ jsx(FilePickerProvider, {
10471
- value: filePickerContextValue,
10472
- children: /* @__PURE__ */ jsx(FilePicker, {
10473
- open: filePickerOpen,
10474
- onFilesSelected: (selected) => void handleFilePickerResults(selected),
10475
- onClose: () => setFilePickerOpen(false),
10476
- config: {
10477
- maxFiles: 50,
10478
- allowedMethods: ["media"]
10479
- }
10480
- })
10481
- })
10482
- })]
11169
+ })
10483
11170
  });
10484
11171
  }
10485
11172
  //#endregion
@@ -11390,22 +12077,25 @@ function createRawMediaAdapter(client) {
11390
12077
  },
11391
12078
  createMedia: async (body) => {
11392
12079
  const response = await media_create(client, { media: body });
12080
+ if (!response.media) throw new Error("Media create response missing media");
11393
12081
  return {
11394
- media: mapMedia(response.media ?? {}),
12082
+ media: mapMedia(response.media),
11395
12083
  meta: mapMediaMeta(response.meta)
11396
12084
  };
11397
12085
  },
11398
12086
  getMedia: async (id) => {
11399
12087
  const response = await media_show(client, id);
12088
+ if (!response.media) throw new Error("Media show response missing media");
11400
12089
  return {
11401
- media: mapMedia(response.media ?? {}),
12090
+ media: mapMedia(response.media),
11402
12091
  meta: mapMediaMeta(response.meta)
11403
12092
  };
11404
12093
  },
11405
12094
  updateMedia: async (id, body) => {
11406
12095
  const response = await media_update(client, id, { media: body });
12096
+ if (!response.media) throw new Error("Media update response missing media");
11407
12097
  return {
11408
- media: mapMedia(response.media ?? {}),
12098
+ media: mapMedia(response.media),
11409
12099
  meta: mapMediaMeta(response.meta)
11410
12100
  };
11411
12101
  },
@@ -11669,15 +12359,12 @@ function mapPlaylist(raw) {
11669
12359
  }
11670
12360
  function mapPlaylistItem(raw) {
11671
12361
  return {
11672
- id: raw.id ?? 0,
11673
- media_id: raw.media_id ?? 0,
11674
- position: raw.position ?? null,
11675
- title: raw.title,
11676
- image_url: raw.image_url ?? null,
11677
- media_type: raw.media_type,
11678
- video_url: raw.video_url ?? null,
11679
- duration: raw.duration ?? null,
11680
- created_at: raw.created_at ?? ""
12362
+ id: raw.id,
12363
+ content_type: raw.content_type,
12364
+ content_id: raw.content_id,
12365
+ position: raw.position,
12366
+ created_at: raw.created_at,
12367
+ content: raw.content
11681
12368
  };
11682
12369
  }
11683
12370
  function mapPlaylistsMeta(raw) {
@@ -11746,8 +12433,10 @@ function createRawPlaylistsAdapter(client) {
11746
12433
  },
11747
12434
  addPlaylistItem: async (playlistId, body) => {
11748
12435
  const response = await playlists_items_add(client, playlistId, { item: body });
12436
+ const rawItem = response.playlist_item;
12437
+ if (!rawItem) throw new Error("Playlist item add response missing playlist_item");
11749
12438
  return {
11750
- playlist_item: mapPlaylistItem(response.playlist_item ?? {}),
12439
+ playlist_item: mapPlaylistItem(rawItem),
11751
12440
  meta: mapPlaylistsMeta(response.meta)
11752
12441
  };
11753
12442
  },
@@ -11757,9 +12446,157 @@ function createRawPlaylistsAdapter(client) {
11757
12446
  playlist_item: { id: response.playlist_item?.id ?? 0 },
11758
12447
  meta: mapPlaylistsMeta(response.meta)
11759
12448
  };
12449
+ },
12450
+ reorderPlaylistItems: async (playlistId, body) => {
12451
+ const response = await playlists_items_reorder(client, playlistId, body);
12452
+ return {
12453
+ playlist_id: response.playlist_id ?? playlistId,
12454
+ meta: mapPlaylistsMeta(response.meta)
12455
+ };
11760
12456
  }
11761
12457
  };
11762
12458
  }
12459
+ const CONTENT_TYPE_TO_RELATEABLE = {
12460
+ media: "Medium",
12461
+ page: "Page",
12462
+ product: "Product",
12463
+ enrollment_pack: "EnrollmentPack"
12464
+ };
12465
+ const RELATEABLE_TO_CONTENT_TYPE = {
12466
+ Medium: "media",
12467
+ Media: "media",
12468
+ media: "media",
12469
+ Page: "page",
12470
+ page: "page",
12471
+ Product: "product",
12472
+ product: "product",
12473
+ EnrollmentPack: "enrollment_pack",
12474
+ enrollment_pack: "enrollment_pack"
12475
+ };
12476
+ function firstImageUrl(images) {
12477
+ return images?.[0]?.url ?? null;
12478
+ }
12479
+ function toShareablePlaylistItem(item) {
12480
+ const relateableType = CONTENT_TYPE_TO_RELATEABLE[item.content_type];
12481
+ const base = {
12482
+ id: item.id,
12483
+ order: item.position ?? void 0,
12484
+ relateable_type: relateableType,
12485
+ relateable: { id: item.content_id }
12486
+ };
12487
+ switch (item.content_type) {
12488
+ case "media": {
12489
+ const c = item.content;
12490
+ const isVideo = c.content_format === "video";
12491
+ const isPdf = c.content_format === "pdf";
12492
+ base.title = c.title ?? "Untitled";
12493
+ base.image_url = isVideo || isPdf ? c.thumbnail_url ?? null : c.url ?? c.thumbnail_url ?? null;
12494
+ base.kind = mediaKindFromType(c.content_format ?? "");
12495
+ base.video_url = isVideo ? c.url ?? null : null;
12496
+ base.duration = null;
12497
+ base.media_format = c.content_format ?? null;
12498
+ base.relateable = {
12499
+ id: c.id,
12500
+ title: c.title,
12501
+ image_url: base.image_url,
12502
+ media_format: c.content_format ?? null,
12503
+ video_url: base.video_url,
12504
+ kind: base.kind,
12505
+ description: {
12506
+ id: null,
12507
+ name: null,
12508
+ body: c.description ?? null,
12509
+ record_type: null,
12510
+ record_id: null,
12511
+ created_at: c.created_at ?? null,
12512
+ updated_at: c.updated_at ?? null,
12513
+ locale: null
12514
+ }
12515
+ };
12516
+ break;
12517
+ }
12518
+ case "page": {
12519
+ const c = item.content;
12520
+ base.title = c.title ?? "Untitled";
12521
+ base.image_url = c.image_url ?? null;
12522
+ base.relateable = {
12523
+ id: c.id,
12524
+ title: c.title,
12525
+ slug: c.slug ?? null,
12526
+ image_url: c.image_url ?? null,
12527
+ status: c.status,
12528
+ description: {
12529
+ id: null,
12530
+ name: null,
12531
+ body: c.description ?? null,
12532
+ record_type: null,
12533
+ record_id: null,
12534
+ created_at: null,
12535
+ updated_at: null,
12536
+ locale: null
12537
+ }
12538
+ };
12539
+ break;
12540
+ }
12541
+ case "product": {
12542
+ const c = item.content;
12543
+ const image = firstImageUrl(c.images);
12544
+ base.title = c.name;
12545
+ base.image_url = image;
12546
+ base.relateable = {
12547
+ id: c.id,
12548
+ title: c.name,
12549
+ slug: c.slug ?? null,
12550
+ price: c.price ?? null,
12551
+ display_price: c.price ?? null,
12552
+ image_url: image,
12553
+ status: c.status ?? null,
12554
+ description: {
12555
+ id: null,
12556
+ name: null,
12557
+ body: c.description ?? null,
12558
+ record_type: null,
12559
+ record_id: null,
12560
+ created_at: c.created_at ?? null,
12561
+ updated_at: null,
12562
+ locale: null
12563
+ },
12564
+ images: (c.images ?? []).map((img) => ({ image_url: img.url ?? null }))
12565
+ };
12566
+ break;
12567
+ }
12568
+ case "enrollment_pack": {
12569
+ const c = item.content;
12570
+ const image = firstImageUrl(c.images);
12571
+ base.title = c.title;
12572
+ base.image_url = image;
12573
+ base.relateable = {
12574
+ id: c.id,
12575
+ title: c.title,
12576
+ slug: c.slug ?? null,
12577
+ canonical_url: c.url ?? null,
12578
+ image_url: image,
12579
+ description: {
12580
+ id: null,
12581
+ name: null,
12582
+ body: c.description ?? null,
12583
+ record_type: null,
12584
+ record_id: null,
12585
+ created_at: null,
12586
+ updated_at: null,
12587
+ locale: null
12588
+ },
12589
+ images: (c.images ?? []).map((img) => ({ image_url: img.url ?? null }))
12590
+ };
12591
+ break;
12592
+ }
12593
+ default: {
12594
+ const _exhaustive = item.content_type;
12595
+ throw new Error(`Unhandled playlist item content_type: ${String(_exhaustive)}`);
12596
+ }
12597
+ }
12598
+ return base;
12599
+ }
11763
12600
  function toBffPlaylist(bff, items) {
11764
12601
  return {
11765
12602
  id: bff.id,
@@ -11820,18 +12657,7 @@ function createPlaylistsAdapter(client) {
11820
12657
  cursor = page.meta.pagination?.next_cursor ?? void 0;
11821
12658
  if (!cursor) break;
11822
12659
  }
11823
- const items = allItems.map((item) => ({
11824
- id: item.id,
11825
- order: item.position ?? void 0,
11826
- relateable_type: "Medium",
11827
- relateable: { id: item.media_id },
11828
- title: item.title ?? "Untitled",
11829
- image_url: item.image_url ?? null,
11830
- kind: mediaKindFromType(item.media_type ?? ""),
11831
- video_url: item.video_url ?? null,
11832
- duration: item.duration ?? null,
11833
- media_format: item.media_type ?? null
11834
- }));
12660
+ const items = allItems.map(toShareablePlaylistItem);
11835
12661
  return {
11836
12662
  playlist: toBffPlaylist(response.playlist, items),
11837
12663
  meta: {
@@ -11867,10 +12693,15 @@ function createPlaylistsAdapter(client) {
11867
12693
  };
11868
12694
  },
11869
12695
  addItemToPlaylist: async (id, data) => {
11870
- await Promise.all(data.items.map((item) => portAdapter.addPlaylistItem(id, {
11871
- media_id: item.relateable_id,
11872
- position: typeof item.order === "number" ? item.order : Number(item.order)
11873
- })));
12696
+ for (const item of data.items) {
12697
+ const contentType = RELATEABLE_TO_CONTENT_TYPE[item.relateable_type];
12698
+ if (!contentType) throw new Error(`Unsupported relateable_type for playlist item: "${item.relateable_type}"`);
12699
+ await portAdapter.addPlaylistItem(id, {
12700
+ content_type: contentType,
12701
+ content_id: item.relateable_id,
12702
+ position: typeof item.order === "number" ? item.order : Number(item.order)
12703
+ });
12704
+ }
11874
12705
  return {
11875
12706
  id,
11876
12707
  title: "",
@@ -11900,7 +12731,7 @@ function createPlaylistsAdapter(client) {
11900
12731
  };
11901
12732
  },
11902
12733
  reorderPlaylistItems: async (playlistId, data) => {
11903
- await playlists_items_reorder(client, playlistId, { items: data.items });
12734
+ await portAdapter.reorderPlaylistItems(playlistId, { items: data.items });
11904
12735
  }
11905
12736
  };
11906
12737
  }
@@ -12028,6 +12859,53 @@ function createRawPagesAdapter(client) {
12028
12859
  }
12029
12860
  };
12030
12861
  }
12862
+ function mapEnrollmentPack(raw) {
12863
+ return {
12864
+ id: raw.id ?? 0,
12865
+ title: raw.title ?? "",
12866
+ slug: raw.slug ?? null,
12867
+ description: raw.description ?? null,
12868
+ url: raw.url ?? null,
12869
+ images: (raw.images ?? []).map((img) => ({
12870
+ url: img.url ?? null,
12871
+ alt: img.alt ?? null
12872
+ }))
12873
+ };
12874
+ }
12875
+ function mapEnrollmentPacksMeta(raw) {
12876
+ return {
12877
+ request_id: raw?.request_id ?? null,
12878
+ timestamp: raw?.timestamp ?? "",
12879
+ pagination: raw?.pagination ? {
12880
+ cursor: raw.pagination.cursor ?? null,
12881
+ limit: raw.pagination.limit,
12882
+ next_cursor: raw.pagination.next_cursor ?? null,
12883
+ prev_cursor: raw.pagination.prev_cursor ?? null
12884
+ } : void 0
12885
+ };
12886
+ }
12887
+ function createRawEnrollmentPacksAdapter(client) {
12888
+ return {
12889
+ listEnrollmentPacks: async (params) => {
12890
+ const response = await enrollment_packs_list(client, {
12891
+ "page[cursor]": params?.cursor,
12892
+ "page[limit]": params?.limit
12893
+ });
12894
+ return {
12895
+ enrollment_packs: (response.enrollment_packs ?? []).filter((p) => typeof p.id === "number").map(mapEnrollmentPack),
12896
+ meta: mapEnrollmentPacksMeta(response.meta)
12897
+ };
12898
+ },
12899
+ getEnrollmentPack: async (id) => {
12900
+ const response = await enrollment_packs_show(client, id);
12901
+ if (!response.enrollment_pack) throw new Error(`EnrollmentPack ${id} not found`);
12902
+ return {
12903
+ enrollment_pack: mapEnrollmentPack(response.enrollment_pack),
12904
+ meta: mapEnrollmentPacksMeta(response.meta)
12905
+ };
12906
+ }
12907
+ };
12908
+ }
12031
12909
  function mapDamAsset(raw) {
12032
12910
  return {
12033
12911
  id: raw.id ?? 0,
@@ -12270,6 +13148,23 @@ function createPortalContentPlaylistsAdapter(client) {
12270
13148
  return createRawPlaylistsAdapter(client);
12271
13149
  }
12272
13150
  /**
13151
+ * Creates a ContentPagesApi (the port-level pages adapter) for screens that
13152
+ * need to list/show pages outside of ShareablesApiProvider — e.g. the
13153
+ * playlist editor's content picker. Mirrors createPortalContentPlaylistsAdapter.
13154
+ */
13155
+ function createPortalContentPagesAdapter(client) {
13156
+ return createRawPagesAdapter(client);
13157
+ }
13158
+ /**
13159
+ * Creates a ContentEnrollmentPacksApi adapter for screens that need to
13160
+ * list/show enrollment packs outside of ShareablesApiProvider — e.g. the
13161
+ * playlist editor's content picker. Backed by the portal-tenant
13162
+ * `/api/enrollment_packs` endpoint.
13163
+ */
13164
+ function createPortalContentEnrollmentPacksAdapter(client) {
13165
+ return createRawEnrollmentPacksAdapter(client);
13166
+ }
13167
+ /**
12273
13168
  * Toggles a favorite entry on a given shareable (Medium / Playlist /
12274
13169
  * Product / etc.) via the portal-tenant BFF's /favorites/toggle endpoint.
12275
13170
  * Returns the new is_favorited state reported by the backend.
@@ -12302,15 +13197,21 @@ function PortalContentApiProvider({ children }) {
12302
13197
  const productsApi = usePortalProductsApi();
12303
13198
  const contentApi = useMemo(() => createPortalContentDomainApiAdapter(client, productsApi), [client, productsApi]);
12304
13199
  const playlistsAdapter = useMemo(() => createPortalContentPlaylistsAdapter(client), [client]);
13200
+ const pagesAdapter = useMemo(() => createPortalContentPagesAdapter(client), [client]);
13201
+ const enrollmentPacksAdapter = useMemo(() => createPortalContentEnrollmentPacksAdapter(client), [client]);
12305
13202
  const mediaProductsAdapter = useMemo(() => createPortalTenantMediaProductsAdapter(client), [client]);
12306
13203
  const filePickerApi = useMemo(() => createFilePickerApiAdapter(client), [client]);
12307
13204
  const ctx = useMemo(() => ({
12308
13205
  productsApi,
12309
13206
  playlistsAdapter,
13207
+ pagesAdapter,
13208
+ enrollmentPacksAdapter,
12310
13209
  mediaProductsAdapter
12311
13210
  }), [
12312
13211
  productsApi,
12313
13212
  playlistsAdapter,
13213
+ pagesAdapter,
13214
+ enrollmentPacksAdapter,
12314
13215
  mediaProductsAdapter
12315
13216
  ]);
12316
13217
  return /* @__PURE__ */ jsx(ContentContext.Provider, {
@@ -12459,6 +13360,59 @@ function ShareablesScreenContent() {
12459
13360
  };
12460
13361
  },
12461
13362
  readOnly: isCustomer,
13363
+ pickerSources: isCustomer ? void 0 : {
13364
+ pages: { list: async ({ search, cursor, limit }) => {
13365
+ const response = await shareablesCtx.pagesAdapter.listPages({
13366
+ cursor: cursor ?? void 0,
13367
+ limit,
13368
+ "filter[title]": search && search.trim().length > 0 ? search : void 0
13369
+ });
13370
+ return {
13371
+ items: response.pages.map((p) => ({
13372
+ id: p.id,
13373
+ title: p.title ?? `Page #${p.id}`,
13374
+ image_url: p.image_url ?? null
13375
+ })),
13376
+ nextCursor: response.meta.pagination?.next_cursor ?? null
13377
+ };
13378
+ } },
13379
+ products: { list: async ({ search, cursor, limit }) => {
13380
+ const trimmedSearch = search?.trim() ?? "";
13381
+ const result = trimmedSearch.length > 0 ? await portalProductsApi.searchProducts(trimmedSearch, {
13382
+ cursor: cursor ?? void 0,
13383
+ limit
13384
+ }) : await portalProductsApi.listProducts({
13385
+ cursor: cursor ?? void 0,
13386
+ limit
13387
+ });
13388
+ return {
13389
+ items: (result.products ?? []).map((p) => p.id != null ? {
13390
+ id: p.id,
13391
+ name: p.name ?? "Untitled",
13392
+ image_url: p.images?.[0]?.url ?? null,
13393
+ price: p.price ?? null
13394
+ } : null).filter((p) => p !== null),
13395
+ nextCursor: result.meta?.pagination?.next_cursor ?? null
13396
+ };
13397
+ } },
13398
+ enrollment_packs: {
13399
+ supportsSearch: false,
13400
+ list: async ({ cursor, limit }) => {
13401
+ const response = await shareablesCtx.enrollmentPacksAdapter.listEnrollmentPacks({
13402
+ cursor: cursor ?? void 0,
13403
+ limit
13404
+ });
13405
+ return {
13406
+ items: response.enrollment_packs.map((pack) => ({
13407
+ id: pack.id,
13408
+ title: pack.title || `Enrollment Pack #${pack.id}`,
13409
+ image_url: pack.images[0]?.url ?? null
13410
+ })),
13411
+ nextCursor: response.meta.pagination?.next_cursor ?? null
13412
+ };
13413
+ }
13414
+ }
13415
+ },
12462
13416
  uploadThumbnail: isCustomer ? void 0 : async (blob, filename) => {
12463
13417
  const formData = new FormData();
12464
13418
  formData.append("asset[name]", filename);
@@ -12474,6 +13428,8 @@ function ShareablesScreenContent() {
12474
13428
  filePickerApi,
12475
13429
  isCustomer,
12476
13430
  shareablesCtx.playlistsAdapter,
13431
+ shareablesCtx.pagesAdapter,
13432
+ shareablesCtx.enrollmentPacksAdapter,
12477
13433
  shareablesCtx.mediaProductsAdapter,
12478
13434
  portalProductsApi,
12479
13435
  client,
@@ -12505,4 +13461,4 @@ const shareablesScreenPropertySchema = {
12505
13461
  //#endregion
12506
13462
  export { ShareablesScreen_exports as n, shareablesScreenPropertySchema as r, ShareablesScreen as t };
12507
13463
 
12508
- //# sourceMappingURL=ShareablesScreen-DjRtywMv.mjs.map
13464
+ //# sourceMappingURL=ShareablesScreen-BjpwByeL.mjs.map