@fluid-app/portal-sdk 0.1.227 → 0.1.229

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.
@@ -9,7 +9,7 @@ require("./es-nxOxb57F.cjs");
9
9
  require("./SearchSort-Hwga1dIi.cjs");
10
10
  require("./dist-5XPflEEG.cjs");
11
11
  require("./dist-FHf4OHgt.cjs");
12
- const require_ShareablesScreen = require("./ShareablesScreen-AMlPuFFk.cjs");
12
+ const require_ShareablesScreen = require("./ShareablesScreen-o6frhZUM.cjs");
13
13
  require("./PortalProductsApiProvider-Bb5B1Hv5.cjs");
14
14
  exports.ShareablesScreen = require_ShareablesScreen.ShareablesScreen;
15
15
  exports.shareablesScreenPropertySchema = require_ShareablesScreen.shareablesScreenPropertySchema;
@@ -44,12 +44,13 @@ function useRepContext() {
44
44
  const shareablesKeys = {
45
45
  media: {
46
46
  all: ["media"],
47
- list: (search, sortDesc, repContext) => [
47
+ list: (search, sortDesc, repContext, ownership) => [
48
48
  "media",
49
49
  "list",
50
50
  search,
51
51
  sortDesc,
52
- repContext
52
+ repContext,
53
+ ownership
53
54
  ],
54
55
  detail: (id, repContext) => [
55
56
  "media",
@@ -689,6 +690,37 @@ function ToggleButton({ active, label, onClick, children }) {
689
690
  });
690
691
  }
691
692
  //#endregion
693
+ //#region ../../shareables/ui/src/hooks/use-infinite-list-sentinel.ts
694
+ /**
695
+ * Wires a sentinel `<div>` to TanStack Query infinite-pagination state.
696
+ *
697
+ * Returns a ref the caller attaches to a 1px sentinel element rendered below
698
+ * the list. When the sentinel scrolls into view (with a 200px root margin)
699
+ * and the query has a next page, isn't already fetching, and hasn't errored,
700
+ * `fetchNextPage()` is invoked.
701
+ */
702
+ function useInfiniteListSentinel({ hasNextPage, isFetchingNextPage, fetchNextPage, error }) {
703
+ const sentinelRef = useRef(null);
704
+ useEffect(() => {
705
+ const target = sentinelRef.current;
706
+ if (!target) return;
707
+ const observer = new IntersectionObserver((entries) => {
708
+ if (entries[0]?.isIntersecting && hasNextPage && !isFetchingNextPage && !error) fetchNextPage();
709
+ }, {
710
+ threshold: 0,
711
+ rootMargin: "200px"
712
+ });
713
+ observer.observe(target);
714
+ return () => observer.disconnect();
715
+ }, [
716
+ fetchNextPage,
717
+ hasNextPage,
718
+ isFetchingNextPage,
719
+ error
720
+ ]);
721
+ return sentinelRef;
722
+ }
723
+ //#endregion
692
724
  //#region ../../shareables/ui/src/components/screens/ProductsScreen.tsx
693
725
  const PAGE_SIZE$5 = 24;
694
726
  const SORT_OPTIONS$1 = [
@@ -731,7 +763,6 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
731
763
  const [debouncedSearch, setDebouncedSearch] = useState("");
732
764
  const [sortValue, setSortValue] = useState("created_at_desc");
733
765
  const [viewMode, setViewMode] = useState("grid");
734
- const observerTarget = useRef(null);
735
766
  useEffect(() => {
736
767
  const timer = setTimeout(() => {
737
768
  setDebouncedSearch(searchTerm);
@@ -780,23 +811,12 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
780
811
  });
781
812
  const usePortal = !!fetchPortalProducts;
782
813
  const { data, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage, error } = usePortal ? portalQuery : legacyQuery;
783
- const handleIntersect = useCallback((entries) => {
784
- if (entries[0]?.isIntersecting && hasNextPage && !isFetchingNextPage) fetchNextPage();
785
- }, [
814
+ const sentinelRef = useInfiniteListSentinel({
786
815
  hasNextPage,
787
816
  isFetchingNextPage,
788
- fetchNextPage
789
- ]);
790
- useEffect(() => {
791
- const target = observerTarget.current;
792
- if (!target) return;
793
- const observer = new IntersectionObserver(handleIntersect, {
794
- threshold: .1,
795
- rootMargin: "200px"
796
- });
797
- observer.observe(target);
798
- return () => observer.disconnect();
799
- }, [handleIntersect]);
817
+ fetchNextPage,
818
+ error
819
+ });
800
820
  const products = useMemo(() => {
801
821
  if (!data) return [];
802
822
  if (usePortal) return data?.pages.flatMap((page) => (page.products ?? []).map((p) => ({
@@ -812,11 +832,16 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
812
832
  media_count: void 0
813
833
  })) ?? [];
814
834
  }, [data, usePortal]);
835
+ const footer = /* @__PURE__ */ jsxs(Fragment$1, { children: [isFetchingNextPage && /* @__PURE__ */ jsx("div", {
836
+ className: "flex justify-center py-4",
837
+ children: /* @__PURE__ */ jsx("div", { className: "border-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" })
838
+ }), error && /* @__PURE__ */ jsx("p", {
839
+ className: "bg-destructive/10 text-destructive rounded-lg px-3 py-2",
840
+ children: "Failed to load products. Please try again."
841
+ })] });
815
842
  return /* @__PURE__ */ jsx(ShareableListLayout, {
816
843
  isLoading,
817
- error,
818
- errorMessage: "Failed to load products. Please try again.",
819
- isEmpty: products.length === 0,
844
+ isEmpty: !error && products.length === 0 && !isFetchingNextPage && !hasNextPage,
820
845
  emptyMessage: debouncedSearch ? "No products match your search." : "No products available.",
821
846
  filters: /* @__PURE__ */ jsxs("div", {
822
847
  className: "flex items-center justify-end gap-2",
@@ -836,11 +861,8 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
836
861
  })]
837
862
  }),
838
863
  loadingFilterShape: "search-view",
839
- footer: isFetchingNextPage && /* @__PURE__ */ jsx("div", {
840
- className: "flex justify-center py-4",
841
- children: /* @__PURE__ */ jsx("div", { className: "border-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" })
842
- }),
843
- sentinelRef: observerTarget,
864
+ footer,
865
+ sentinelRef,
844
866
  children: viewMode === "grid" ? /* @__PURE__ */ jsx("div", {
845
867
  className: SHAREABLE_GRID_CLASS,
846
868
  children: products.map((product) => /* @__PURE__ */ jsx(ShareProductCard, {
@@ -1633,7 +1655,7 @@ function OwnerFilterTabs({ value, onValueChange, myLabel = "Mine" }) {
1633
1655
  children: "All"
1634
1656
  }),
1635
1657
  /* @__PURE__ */ jsx(TabsTrigger, {
1636
- value: "my",
1658
+ value: "mine",
1637
1659
  children: myLabel
1638
1660
  }),
1639
1661
  /* @__PURE__ */ jsx(TabsTrigger, {
@@ -1709,7 +1731,6 @@ function MediaListingScreen(_props) {
1709
1731
  }, 300);
1710
1732
  return () => clearTimeout(timer);
1711
1733
  }, [searchTerm]);
1712
- const observerTarget = useRef(null);
1713
1734
  const { mutate: deleteMedia, isPending: isDeleting } = useMutation({
1714
1735
  mutationFn: (id) => api.media.deleteMedia(id),
1715
1736
  onSuccess: () => {
@@ -1717,7 +1738,7 @@ function MediaListingScreen(_props) {
1717
1738
  title: "Media deleted",
1718
1739
  type: "success"
1719
1740
  });
1720
- queryClient.invalidateQueries({ queryKey: shareablesKeys.media.list(debouncedSearch, sortValue === "title_desc", repContext) });
1741
+ queryClient.invalidateQueries({ queryKey: shareablesKeys.media.all });
1721
1742
  setPendingDeleteId(null);
1722
1743
  },
1723
1744
  onError: (error) => {
@@ -1736,13 +1757,14 @@ function MediaListingScreen(_props) {
1736
1757
  const bffKind = kindFilter === "all" ? void 0 : kindFilter;
1737
1758
  const { data, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage, error } = useInfiniteQuery({
1738
1759
  queryKey: [
1739
- ...shareablesKeys.media.list(debouncedSearch, sortValue === "title_desc", repContext),
1760
+ ...shareablesKeys.media.list(debouncedSearch, sortValue === "title_desc", repContext, ownerFilter),
1740
1761
  sortValue,
1741
1762
  kindFilter
1742
1763
  ],
1743
1764
  queryFn: async ({ pageParam }) => {
1744
1765
  return await api.media.list({
1745
1766
  "filter[title]": debouncedSearch || void 0,
1767
+ "filter[ownership]": ownerFilter,
1746
1768
  "filter[content_format]": bffKind,
1747
1769
  "page[cursor]": pageParam,
1748
1770
  "page[limit]": PAGE_SIZE$4,
@@ -1753,24 +1775,13 @@ function MediaListingScreen(_props) {
1753
1775
  initialPageParam: void 0,
1754
1776
  placeholderData: keepPreviousData
1755
1777
  });
1756
- const allItems = useMemo(() => data?.pages.flatMap((p) => p.media) ?? [], [data?.pages]);
1757
- const filteredItems = ownerFilter === "all" ? allItems : ownerFilter === "my" ? allItems.filter((item) => item.owner_type === "user") : allItems.filter((item) => item.owner_type === "company");
1758
- useEffect(() => {
1759
- const target = observerTarget.current;
1760
- if (!target) return;
1761
- const observer = new IntersectionObserver((entries) => {
1762
- if (entries[0]?.isIntersecting && hasNextPage && !isFetchingNextPage) fetchNextPage();
1763
- }, {
1764
- threshold: 0,
1765
- rootMargin: "200px"
1766
- });
1767
- observer.observe(target);
1768
- return () => observer.disconnect();
1769
- }, [
1770
- fetchNextPage,
1778
+ const filteredItems = useMemo(() => data?.pages.flatMap((p) => p.media) ?? [], [data?.pages]);
1779
+ const sentinelRef = useInfiniteListSentinel({
1771
1780
  hasNextPage,
1772
- isFetchingNextPage
1773
- ]);
1781
+ isFetchingNextPage,
1782
+ fetchNextPage,
1783
+ error
1784
+ });
1774
1785
  const filterBar = /* @__PURE__ */ jsxs("div", {
1775
1786
  className: "flex items-center gap-3",
1776
1787
  children: [/* @__PURE__ */ jsx(OwnerFilterTabs, {
@@ -1867,7 +1878,7 @@ function MediaListingScreen(_props) {
1867
1878
  }),
1868
1879
  filters: filterBar,
1869
1880
  footer,
1870
- sentinelRef: observerTarget,
1881
+ sentinelRef,
1871
1882
  loadingFilterShape: "search-view",
1872
1883
  children: viewMode === "grid" ? /* @__PURE__ */ jsx("div", {
1873
1884
  className: SHAREABLE_GRID_CLASS,
@@ -9069,7 +9080,7 @@ function PlaylistsListingScreen(_props) {
9069
9080
  const allPlaylists = useMemo(() => data?.pages.flatMap((page) => page.playlists) ?? [], [data?.pages]);
9070
9081
  const filteredPlaylists = useMemo(() => {
9071
9082
  if (ownerFilter === "all" || !user?.id) return allPlaylists;
9072
- if (ownerFilter === "my") return allPlaylists.filter((p) => p.user_id === user.id);
9083
+ if (ownerFilter === "mine") return allPlaylists.filter((p) => p.user_id === user.id);
9073
9084
  return allPlaylists.filter((p) => p.user_id !== user.id);
9074
9085
  }, [
9075
9086
  allPlaylists,
@@ -10821,7 +10832,6 @@ function FilesListingScreen({ onNavigate }) {
10821
10832
  }) }), []));
10822
10833
  const [searchTerm, setSearchTerm] = useState("");
10823
10834
  const [debouncedSearch, setDebouncedSearch] = useState("");
10824
- const observerTarget = useRef(null);
10825
10835
  useEffect(() => {
10826
10836
  const timer = setTimeout(() => {
10827
10837
  setDebouncedSearch(searchTerm);
@@ -10844,28 +10854,22 @@ function FilesListingScreen({ onNavigate }) {
10844
10854
  initialPageParam: 1
10845
10855
  });
10846
10856
  const files = useMemo(() => data?.pages.flatMap((page) => page.file_resources) ?? [], [data?.pages]);
10847
- const handleIntersect = useCallback((entries) => {
10848
- if (entries[0]?.isIntersecting && hasNextPage && !isFetchingNextPage) fetchNextPage();
10849
- }, [
10857
+ const sentinelRef = useInfiniteListSentinel({
10850
10858
  hasNextPage,
10851
10859
  isFetchingNextPage,
10852
- fetchNextPage
10853
- ]);
10854
- useEffect(() => {
10855
- const target = observerTarget.current;
10856
- if (!target) return;
10857
- const observer = new IntersectionObserver(handleIntersect, {
10858
- threshold: .1,
10859
- rootMargin: "200px"
10860
- });
10861
- observer.observe(target);
10862
- return () => observer.disconnect();
10863
- }, [handleIntersect]);
10860
+ fetchNextPage,
10861
+ error
10862
+ });
10863
+ const footer = /* @__PURE__ */ jsxs(Fragment$1, { children: [isFetchingNextPage && /* @__PURE__ */ jsx("div", {
10864
+ className: "flex justify-center py-4",
10865
+ children: /* @__PURE__ */ jsx("div", { className: "border-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" })
10866
+ }), error && /* @__PURE__ */ jsx("p", {
10867
+ className: "bg-destructive/10 text-destructive rounded-lg px-3 py-2",
10868
+ children: "Failed to load files. Please try again."
10869
+ })] });
10864
10870
  return /* @__PURE__ */ jsx(ShareableListLayout, {
10865
10871
  isLoading,
10866
- error,
10867
- errorMessage: "Failed to load files. Please try again.",
10868
- isEmpty: files.length === 0,
10872
+ isEmpty: !error && files.length === 0 && !isFetchingNextPage && !hasNextPage,
10869
10873
  emptyMessage: debouncedSearch ? `No files match "${debouncedSearch}". Try a different search term.` : "No files available.",
10870
10874
  filters: /* @__PURE__ */ jsx("div", {
10871
10875
  className: "flex justify-end",
@@ -10878,11 +10882,8 @@ function FilesListingScreen({ onNavigate }) {
10878
10882
  })
10879
10883
  })
10880
10884
  }),
10881
- footer: isFetchingNextPage && /* @__PURE__ */ jsx("div", {
10882
- className: "flex justify-center py-4",
10883
- children: /* @__PURE__ */ jsx("div", { className: "border-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" })
10884
- }),
10885
- sentinelRef: observerTarget,
10885
+ footer,
10886
+ sentinelRef,
10886
10887
  children: /* @__PURE__ */ jsx("div", {
10887
10888
  className: SHAREABLE_GRID_CLASS,
10888
10889
  children: files.map((file) => {
@@ -11378,6 +11379,7 @@ function createRawMediaAdapter(client) {
11378
11379
  "page[cursor]": params?.cursor,
11379
11380
  "page[limit]": params?.limit,
11380
11381
  "filter[title]": params?.["filter[title]"],
11382
+ "filter[ownership]": params?.["filter[ownership]"],
11381
11383
  "filter[content_format]": params?.["filter[content_format]"],
11382
11384
  sort: params?.sort
11383
11385
  });
@@ -11550,6 +11552,7 @@ function createMediaAdapter(client) {
11550
11552
  cursor: options?.["page[cursor]"],
11551
11553
  limit: options?.["page[limit]"],
11552
11554
  "filter[title]": options?.["filter[title]"],
11555
+ "filter[ownership]": options?.["filter[ownership]"],
11553
11556
  "filter[content_format]": options?.["filter[content_format]"],
11554
11557
  sort: options?.sort
11555
11558
  });
@@ -11560,7 +11563,7 @@ function createMediaAdapter(client) {
11560
11563
  },
11561
11564
  getMedia: async (options) => {
11562
11565
  const pageNumber = options?.page ?? 1;
11563
- const filterKey = `${options?.search_query ?? ""}|${options?.sorted_by ?? ""}`;
11566
+ const filterKey = `${options?.search_query ?? ""}|${options?.sorted_by ?? ""}|${options?.ownership ?? ""}`;
11564
11567
  if (filterKey !== lastFilterKey) {
11565
11568
  cursorByPage.clear();
11566
11569
  lastFilterKey = filterKey;
@@ -11570,10 +11573,13 @@ function createMediaAdapter(client) {
11570
11573
  let bffSort;
11571
11574
  if (rawSort === "title_asc") bffSort = "title_asc";
11572
11575
  else if (rawSort === "title_desc") bffSort = "title_desc";
11576
+ const ownership = options?.ownership;
11577
+ const bffOwnership = ownership === "all" || ownership === "mine" || ownership === "company" ? ownership : void 0;
11573
11578
  const response = await portAdapter.listMedia({
11574
11579
  cursor,
11575
11580
  limit: options?.per_page,
11576
11581
  "filter[title]": options?.search_query,
11582
+ "filter[ownership]": bffOwnership,
11577
11583
  sort: bffSort
11578
11584
  });
11579
11585
  const nextCursor = response.meta.pagination?.next_cursor;
@@ -12499,4 +12505,4 @@ const shareablesScreenPropertySchema = {
12499
12505
  //#endregion
12500
12506
  export { ShareablesScreen_exports as n, shareablesScreenPropertySchema as r, ShareablesScreen as t };
12501
12507
 
12502
- //# sourceMappingURL=ShareablesScreen-CNARhXTE.mjs.map
12508
+ //# sourceMappingURL=ShareablesScreen-DjRtywMv.mjs.map