@fluid-app/portal-sdk 0.1.187 → 0.1.188

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 (27) hide show
  1. package/dist/{PortalContentApiProvider-BPq6U0Pu.mjs → PortalContentApiProvider-CmjXGFMQ.mjs} +77 -44
  2. package/dist/PortalContentApiProvider-CmjXGFMQ.mjs.map +1 -0
  3. package/dist/{PortalContentApiProvider-Cho3MNVB.cjs → PortalContentApiProvider-DMeTMGV6.cjs} +77 -44
  4. package/dist/PortalContentApiProvider-DMeTMGV6.cjs.map +1 -0
  5. package/dist/{ProductsScreen-C53oBRqs.mjs → ProductsScreen-BdBUnVyp.mjs} +2 -4
  6. package/dist/{ProductsScreen-DHXjR5xp.mjs → ProductsScreen-C2G3onZB.mjs} +5 -4
  7. package/dist/ProductsScreen-C2G3onZB.mjs.map +1 -0
  8. package/dist/{ProductsScreen-CwEKSaBQ.cjs → ProductsScreen-CRO01qDT.cjs} +2 -2
  9. package/dist/{ProductsScreen-DNBwds9n.cjs → ProductsScreen-Pt4U6VS2.cjs} +5 -4
  10. package/dist/ProductsScreen-Pt4U6VS2.cjs.map +1 -0
  11. package/dist/{ShareablesScreen-DkjlhWOe.cjs → ShareablesScreen-BZWek2TC.cjs} +3 -2
  12. package/dist/{ShareablesScreen-COyR9r9k.mjs → ShareablesScreen-CVByD83o.mjs} +9 -5
  13. package/dist/ShareablesScreen-CVByD83o.mjs.map +1 -0
  14. package/dist/{ShareablesScreen-DCgI9TZU.cjs → ShareablesScreen-DGix4SDY.cjs} +9 -5
  15. package/dist/ShareablesScreen-DGix4SDY.cjs.map +1 -0
  16. package/dist/{ShareablesScreen-CPR_1tsg.mjs → ShareablesScreen-KEjm-lKr.mjs} +3 -4
  17. package/dist/index.cjs +7 -7
  18. package/dist/index.d.cts.map +1 -1
  19. package/dist/index.d.mts.map +1 -1
  20. package/dist/index.mjs +7 -7
  21. package/package.json +20 -20
  22. package/dist/PortalContentApiProvider-BPq6U0Pu.mjs.map +0 -1
  23. package/dist/PortalContentApiProvider-Cho3MNVB.cjs.map +0 -1
  24. package/dist/ProductsScreen-DHXjR5xp.mjs.map +0 -1
  25. package/dist/ProductsScreen-DNBwds9n.cjs.map +0 -1
  26. package/dist/ShareablesScreen-COyR9r9k.mjs.map +0 -1
  27. package/dist/ShareablesScreen-DCgI9TZU.cjs.map +0 -1
@@ -511,6 +511,32 @@ function ShareProductCard({ product, mediaCount }) {
511
511
  //#region ../../shareables/ui/src/components/screens/ProductsScreen.tsx
512
512
  const PAGE_SIZE$4 = 24;
513
513
  const GRID_CLASS$3 = "grid grid-cols-1 gap-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4";
514
+ const SORT_OPTIONS$1 = [
515
+ {
516
+ label: "Newest",
517
+ value: "created_at_desc"
518
+ },
519
+ {
520
+ label: "Oldest",
521
+ value: "created_at_asc"
522
+ },
523
+ {
524
+ label: "Title A–Z",
525
+ value: "title_asc"
526
+ },
527
+ {
528
+ label: "Title Z–A",
529
+ value: "title_desc"
530
+ },
531
+ {
532
+ label: "Price: Low to High",
533
+ value: "price_asc"
534
+ },
535
+ {
536
+ label: "Price: High to Low",
537
+ value: "price_desc"
538
+ }
539
+ ];
514
540
  function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNavigate }) {
515
541
  const client = useShareablesClient();
516
542
  useScreenHeaderBreadcrumbs(useMemo(() => /* @__PURE__ */ jsx(Breadcrumb, { children: /* @__PURE__ */ jsx(BreadcrumbList, {
@@ -522,6 +548,7 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
522
548
  }) }), []));
523
549
  const [searchTerm, setSearchTerm] = useState("");
524
550
  const [debouncedSearch, setDebouncedSearch] = useState("");
551
+ const [sortValue, setSortValue] = useState("created_at_desc");
525
552
  const observerTarget = useRef(null);
526
553
  useEffect(() => {
527
554
  const timer = setTimeout(() => {
@@ -529,14 +556,16 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
529
556
  }, 300);
530
557
  return () => clearTimeout(timer);
531
558
  }, [searchTerm]);
559
+ const effectiveSort = debouncedSearch ? void 0 : sortValue;
532
560
  const portalQuery = useInfiniteQuery({
533
561
  queryKey: [
534
562
  "portal-product-catalog",
535
563
  debouncedSearch || "",
536
- PAGE_SIZE$4
564
+ PAGE_SIZE$4,
565
+ effectiveSort
537
566
  ],
538
567
  queryFn: async ({ pageParam }) => {
539
- return fetchPortalProducts(debouncedSearch, pageParam, PAGE_SIZE$4);
568
+ return fetchPortalProducts(debouncedSearch, pageParam, PAGE_SIZE$4, effectiveSort);
540
569
  },
541
570
  getNextPageParam: (lastPage) => lastPage.meta?.pagination?.next_cursor ?? void 0,
542
571
  initialPageParam: void 0,
@@ -635,7 +664,10 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
635
664
  children: /* @__PURE__ */ jsx(SearchSort, {
636
665
  searchValue: searchTerm,
637
666
  onSearchChange: setSearchTerm,
638
- placeholder: "Search products..."
667
+ placeholder: "Search products...",
668
+ sortOptions: SORT_OPTIONS$1,
669
+ sortValue,
670
+ onSortChange: setSortValue
639
671
  })
640
672
  })
641
673
  }),
@@ -1166,7 +1198,7 @@ function ProductDetailScreen({ productId, countryCode, fetchProduct: fetchPortal
1166
1198
  const legacyProduct = legacyProductResponse?.product;
1167
1199
  const product = portalProduct || legacyProduct;
1168
1200
  const displayTitle = portalProduct?.name || legacyProduct?.title || "";
1169
- const displayImage = portalProduct?.images?.[0]?.url || legacyProduct?.image_url || "";
1201
+ const productImage = portalProduct?.images?.[0]?.url || legacyProduct?.image_url || "";
1170
1202
  const displayDescription = portalProduct?.description || legacyProduct?.description || legacyProduct?.stripped || "";
1171
1203
  useScreenHeaderBreadcrumbs(useMemo(() => /* @__PURE__ */ jsx(Breadcrumb, { children: /* @__PURE__ */ jsxs(BreadcrumbList, {
1172
1204
  className: "text-lg",
@@ -1222,17 +1254,17 @@ function ProductDetailScreen({ productId, countryCode, fetchProduct: fetchPortal
1222
1254
  }));
1223
1255
  const hasMedia = (productMediaResponse?.media?.length || 0) > 0;
1224
1256
  const handleDownload = useCallback(() => {
1225
- if (!displayImage) {
1257
+ if (!productImage) {
1226
1258
  showToast({
1227
1259
  title: "No downloadable asset available",
1228
1260
  type: "error"
1229
1261
  });
1230
1262
  return;
1231
1263
  }
1232
- if (onFileDownload) onFileDownload(displayImage, displayTitle || "product");
1233
- else window.open(displayImage, "_blank");
1264
+ if (onFileDownload) onFileDownload(productImage, displayTitle || "product");
1265
+ else window.open(productImage, "_blank");
1234
1266
  }, [
1235
- displayImage,
1267
+ productImage,
1236
1268
  displayTitle,
1237
1269
  onFileDownload,
1238
1270
  showToast
@@ -1259,8 +1291,24 @@ function ProductDetailScreen({ productId, countryCode, fetchProduct: fetchPortal
1259
1291
  className: "aspect-square w-full md:aspect-auto md:h-full",
1260
1292
  children: /* @__PURE__ */ jsx("div", {
1261
1293
  className: "relative h-full overflow-hidden rounded-2xl",
1262
- children: /* @__PURE__ */ jsx(SharePageImageDisplay, {
1263
- displayImage,
1294
+ children: !productImage ? /* @__PURE__ */ jsxs("div", {
1295
+ className: "bg-muted flex h-full w-full flex-col items-center justify-center rounded-2xl",
1296
+ children: [
1297
+ /* @__PURE__ */ jsx("div", {
1298
+ className: "mb-2 text-gray-400",
1299
+ children: /* @__PURE__ */ jsx(Image, { className: "mx-auto h-12 w-12" })
1300
+ }),
1301
+ /* @__PURE__ */ jsx("div", {
1302
+ className: "mb-1 text-sm text-gray-500",
1303
+ children: "No Product Image"
1304
+ }),
1305
+ /* @__PURE__ */ jsx("div", {
1306
+ className: "text-xs text-gray-400",
1307
+ children: "This product does not have any associated media"
1308
+ })
1309
+ ]
1310
+ }) : /* @__PURE__ */ jsx(SharePageImageDisplay, {
1311
+ displayImage: productImage,
1264
1312
  displayTitle,
1265
1313
  isVideo: false,
1266
1314
  badgeLabel: "Product"
@@ -1303,7 +1351,7 @@ function ProductDetailScreen({ productId, countryCode, fetchProduct: fetchPortal
1303
1351
  })
1304
1352
  ]
1305
1353
  }),
1306
- displayImage && /* @__PURE__ */ jsxs(Button, {
1354
+ productImage && /* @__PURE__ */ jsxs(Button, {
1307
1355
  onClick: handleDownload,
1308
1356
  className: "bg-foreground text-background hover:bg-foreground/70 flex h-10 w-full items-center justify-between rounded-lg px-4 transition-all",
1309
1357
  children: [/* @__PURE__ */ jsx("span", {
@@ -11362,36 +11410,25 @@ const SHAREABLE_TYPE_MAP = {
11362
11410
  page: "page"
11363
11411
  };
11364
11412
  /**
11365
- * Workaround for a backend bug: the BFF sometimes returns share URLs with an
11366
- * unresolved `HOST` placeholder (e.g. `http://HOST/s/abc123`) because Rails'
11367
- * `default_url_options[:host]` is not populated in that code path. Rewrite to
11368
- * the current browser origin so the link is actually clickable.
11413
+ * Build a direct page URL on the company app for a given shareable.
11369
11414
  *
11370
- * Remove once the backend template is fixed.
11371
- */
11372
- function normalizeShareUrl(url) {
11373
- if (!url) return url;
11374
- if (!/^https?:\/\/HOST(\/|$)/i.test(url)) return url;
11375
- if (typeof window === "undefined") return url;
11376
- return url.replace(/^https?:\/\/HOST/i, window.location.origin);
11377
- }
11378
- /**
11379
- * Build a URL on the company (tenant) app from the current portal origin.
11380
11415
  * Portal runs at `<tenant>.portal.fluid.app`; the company app is at
11381
- * `<tenant>.fluid.app`. Strip the `.portal` segment to cross over. In dev
11382
- * the origin is usually localhost, which is left untouched — the resulting
11383
- * URL won't resolve in-browser but the structure is right for testing.
11416
+ * `<tenant>.fluid.app`. Strip the `.portal` segment to get the company
11417
+ * origin, then append the type-specific path.
11384
11418
  */
11385
- function buildCompanyAppUrl(path) {
11386
- if (typeof window === "undefined") return null;
11387
- try {
11388
- const url = new URL(window.location.origin);
11389
- url.host = url.host.replace(/\.portal\./, ".");
11390
- url.pathname = path;
11391
- return url.toString();
11392
- } catch {
11393
- return null;
11394
- }
11419
+ const SHARE_PATH_BY_TYPE = {
11420
+ product: "/home/products",
11421
+ media: "/home/media",
11422
+ library: "/home/libraries",
11423
+ page: "/home/pages"
11424
+ };
11425
+ function buildShareUrl(shareableType, shareUrl) {
11426
+ const basePath = SHARE_PATH_BY_TYPE[shareableType];
11427
+ if (!basePath) throw new Error(`Cannot build share URL for type "${shareableType}"`);
11428
+ if (typeof window === "undefined") throw new Error(`Cannot build share URL in a non-browser environment (type: "${shareableType}")`);
11429
+ const token = shareUrl.split("/s/")[1];
11430
+ if (!token) throw new Error(`Share URL missing expected /s/ token segment: "${shareUrl}"`);
11431
+ return `${window.location.origin.replace(/\.portal\./, ".")}${basePath}/${token}`;
11395
11432
  }
11396
11433
  function createShareAdapter(client) {
11397
11434
  const portAdapter = createRawSharesAdapter(client);
@@ -11399,11 +11436,7 @@ function createShareAdapter(client) {
11399
11436
  if (!input.relateableId) throw new Error("Cannot create share link without a relateableId");
11400
11437
  const shareableType = SHAREABLE_TYPE_MAP[input.relateableType];
11401
11438
  if (!shareableType) throw new Error(`Unknown shareable type: "${input.relateableType}"`);
11402
- if (shareableType === "media") {
11403
- const directUrl = buildCompanyAppUrl(`/home/media/${input.relateableId}`);
11404
- if (directUrl) return directUrl;
11405
- }
11406
- return normalizeShareUrl((await portAdapter.createShare({
11439
+ return buildShareUrl(shareableType, (await portAdapter.createShare({
11407
11440
  shareable_type: shareableType,
11408
11441
  shareable_id: input.relateableId
11409
11442
  })).share.url);
@@ -11629,4 +11662,4 @@ function PortalContentApiProvider({ children }) {
11629
11662
  //#endregion
11630
11663
  export { ShareablesApp as a, ShareablesCoreProvider as c, ProductsApp as i, usePortalContentContext as n, useFilePickerApi as o, toggleFavorite as r, ShareablesUIProvider as s, PortalContentApiProvider as t };
11631
11664
 
11632
- //# sourceMappingURL=PortalContentApiProvider-BPq6U0Pu.mjs.map
11665
+ //# sourceMappingURL=PortalContentApiProvider-CmjXGFMQ.mjs.map