@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
@@ -513,6 +513,32 @@ function ShareProductCard({ product, mediaCount }) {
513
513
  //#region ../../shareables/ui/src/components/screens/ProductsScreen.tsx
514
514
  const PAGE_SIZE$4 = 24;
515
515
  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";
516
+ const SORT_OPTIONS$1 = [
517
+ {
518
+ label: "Newest",
519
+ value: "created_at_desc"
520
+ },
521
+ {
522
+ label: "Oldest",
523
+ value: "created_at_asc"
524
+ },
525
+ {
526
+ label: "Title A–Z",
527
+ value: "title_asc"
528
+ },
529
+ {
530
+ label: "Title Z–A",
531
+ value: "title_desc"
532
+ },
533
+ {
534
+ label: "Price: Low to High",
535
+ value: "price_asc"
536
+ },
537
+ {
538
+ label: "Price: High to Low",
539
+ value: "price_desc"
540
+ }
541
+ ];
516
542
  function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNavigate }) {
517
543
  const client = useShareablesClient();
518
544
  require_ScreenHeaderContext.useScreenHeaderBreadcrumbs((0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Breadcrumb, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.BreadcrumbList, {
@@ -524,6 +550,7 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
524
550
  }) }), []));
525
551
  const [searchTerm, setSearchTerm] = (0, react.useState)("");
526
552
  const [debouncedSearch, setDebouncedSearch] = (0, react.useState)("");
553
+ const [sortValue, setSortValue] = (0, react.useState)("created_at_desc");
527
554
  const observerTarget = (0, react.useRef)(null);
528
555
  (0, react.useEffect)(() => {
529
556
  const timer = setTimeout(() => {
@@ -531,14 +558,16 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
531
558
  }, 300);
532
559
  return () => clearTimeout(timer);
533
560
  }, [searchTerm]);
561
+ const effectiveSort = debouncedSearch ? void 0 : sortValue;
534
562
  const portalQuery = (0, _tanstack_react_query.useInfiniteQuery)({
535
563
  queryKey: [
536
564
  "portal-product-catalog",
537
565
  debouncedSearch || "",
538
- PAGE_SIZE$4
566
+ PAGE_SIZE$4,
567
+ effectiveSort
539
568
  ],
540
569
  queryFn: async ({ pageParam }) => {
541
- return fetchPortalProducts(debouncedSearch, pageParam, PAGE_SIZE$4);
570
+ return fetchPortalProducts(debouncedSearch, pageParam, PAGE_SIZE$4, effectiveSort);
542
571
  },
543
572
  getNextPageParam: (lastPage) => lastPage.meta?.pagination?.next_cursor ?? void 0,
544
573
  initialPageParam: void 0,
@@ -637,7 +666,10 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
637
666
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
638
667
  searchValue: searchTerm,
639
668
  onSearchChange: setSearchTerm,
640
- placeholder: "Search products..."
669
+ placeholder: "Search products...",
670
+ sortOptions: SORT_OPTIONS$1,
671
+ sortValue,
672
+ onSortChange: setSortValue
641
673
  })
642
674
  })
643
675
  }),
@@ -1168,7 +1200,7 @@ function ProductDetailScreen({ productId, countryCode, fetchProduct: fetchPortal
1168
1200
  const legacyProduct = legacyProductResponse?.product;
1169
1201
  const product = portalProduct || legacyProduct;
1170
1202
  const displayTitle = portalProduct?.name || legacyProduct?.title || "";
1171
- const displayImage = portalProduct?.images?.[0]?.url || legacyProduct?.image_url || "";
1203
+ const productImage = portalProduct?.images?.[0]?.url || legacyProduct?.image_url || "";
1172
1204
  const displayDescription = portalProduct?.description || legacyProduct?.description || legacyProduct?.stripped || "";
1173
1205
  require_ScreenHeaderContext.useScreenHeaderBreadcrumbs((0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Breadcrumb, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.BreadcrumbList, {
1174
1206
  className: "text-lg",
@@ -1224,17 +1256,17 @@ function ProductDetailScreen({ productId, countryCode, fetchProduct: fetchPortal
1224
1256
  }));
1225
1257
  const hasMedia = (productMediaResponse?.media?.length || 0) > 0;
1226
1258
  const handleDownload = (0, react.useCallback)(() => {
1227
- if (!displayImage) {
1259
+ if (!productImage) {
1228
1260
  showToast({
1229
1261
  title: "No downloadable asset available",
1230
1262
  type: "error"
1231
1263
  });
1232
1264
  return;
1233
1265
  }
1234
- if (onFileDownload) onFileDownload(displayImage, displayTitle || "product");
1235
- else window.open(displayImage, "_blank");
1266
+ if (onFileDownload) onFileDownload(productImage, displayTitle || "product");
1267
+ else window.open(productImage, "_blank");
1236
1268
  }, [
1237
- displayImage,
1269
+ productImage,
1238
1270
  displayTitle,
1239
1271
  onFileDownload,
1240
1272
  showToast
@@ -1261,8 +1293,24 @@ function ProductDetailScreen({ productId, countryCode, fetchProduct: fetchPortal
1261
1293
  className: "aspect-square w-full md:aspect-auto md:h-full",
1262
1294
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1263
1295
  className: "relative h-full overflow-hidden rounded-2xl",
1264
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SharePageImageDisplay, {
1265
- displayImage,
1296
+ children: !productImage ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1297
+ className: "bg-muted flex h-full w-full flex-col items-center justify-center rounded-2xl",
1298
+ children: [
1299
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1300
+ className: "mb-2 text-gray-400",
1301
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Image, { className: "mx-auto h-12 w-12" })
1302
+ }),
1303
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1304
+ className: "mb-1 text-sm text-gray-500",
1305
+ children: "No Product Image"
1306
+ }),
1307
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1308
+ className: "text-xs text-gray-400",
1309
+ children: "This product does not have any associated media"
1310
+ })
1311
+ ]
1312
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SharePageImageDisplay, {
1313
+ displayImage: productImage,
1266
1314
  displayTitle,
1267
1315
  isVideo: false,
1268
1316
  badgeLabel: "Product"
@@ -1305,7 +1353,7 @@ function ProductDetailScreen({ productId, countryCode, fetchProduct: fetchPortal
1305
1353
  })
1306
1354
  ]
1307
1355
  }),
1308
- displayImage && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.Button, {
1356
+ productImage && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.Button, {
1309
1357
  onClick: handleDownload,
1310
1358
  className: "bg-foreground text-background hover:bg-foreground/70 flex h-10 w-full items-center justify-between rounded-lg px-4 transition-all",
1311
1359
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -11367,36 +11415,25 @@ const SHAREABLE_TYPE_MAP = {
11367
11415
  page: "page"
11368
11416
  };
11369
11417
  /**
11370
- * Workaround for a backend bug: the BFF sometimes returns share URLs with an
11371
- * unresolved `HOST` placeholder (e.g. `http://HOST/s/abc123`) because Rails'
11372
- * `default_url_options[:host]` is not populated in that code path. Rewrite to
11373
- * the current browser origin so the link is actually clickable.
11418
+ * Build a direct page URL on the company app for a given shareable.
11374
11419
  *
11375
- * Remove once the backend template is fixed.
11376
- */
11377
- function normalizeShareUrl(url) {
11378
- if (!url) return url;
11379
- if (!/^https?:\/\/HOST(\/|$)/i.test(url)) return url;
11380
- if (typeof window === "undefined") return url;
11381
- return url.replace(/^https?:\/\/HOST/i, window.location.origin);
11382
- }
11383
- /**
11384
- * Build a URL on the company (tenant) app from the current portal origin.
11385
11420
  * Portal runs at `<tenant>.portal.fluid.app`; the company app is at
11386
- * `<tenant>.fluid.app`. Strip the `.portal` segment to cross over. In dev
11387
- * the origin is usually localhost, which is left untouched — the resulting
11388
- * URL won't resolve in-browser but the structure is right for testing.
11421
+ * `<tenant>.fluid.app`. Strip the `.portal` segment to get the company
11422
+ * origin, then append the type-specific path.
11389
11423
  */
11390
- function buildCompanyAppUrl(path) {
11391
- if (typeof window === "undefined") return null;
11392
- try {
11393
- const url = new URL(window.location.origin);
11394
- url.host = url.host.replace(/\.portal\./, ".");
11395
- url.pathname = path;
11396
- return url.toString();
11397
- } catch {
11398
- return null;
11399
- }
11424
+ const SHARE_PATH_BY_TYPE = {
11425
+ product: "/home/products",
11426
+ media: "/home/media",
11427
+ library: "/home/libraries",
11428
+ page: "/home/pages"
11429
+ };
11430
+ function buildShareUrl(shareableType, shareUrl) {
11431
+ const basePath = SHARE_PATH_BY_TYPE[shareableType];
11432
+ if (!basePath) throw new Error(`Cannot build share URL for type "${shareableType}"`);
11433
+ if (typeof window === "undefined") throw new Error(`Cannot build share URL in a non-browser environment (type: "${shareableType}")`);
11434
+ const token = shareUrl.split("/s/")[1];
11435
+ if (!token) throw new Error(`Share URL missing expected /s/ token segment: "${shareUrl}"`);
11436
+ return `${window.location.origin.replace(/\.portal\./, ".")}${basePath}/${token}`;
11400
11437
  }
11401
11438
  function createShareAdapter(client) {
11402
11439
  const portAdapter = createRawSharesAdapter(client);
@@ -11404,11 +11441,7 @@ function createShareAdapter(client) {
11404
11441
  if (!input.relateableId) throw new Error("Cannot create share link without a relateableId");
11405
11442
  const shareableType = SHAREABLE_TYPE_MAP[input.relateableType];
11406
11443
  if (!shareableType) throw new Error(`Unknown shareable type: "${input.relateableType}"`);
11407
- if (shareableType === "media") {
11408
- const directUrl = buildCompanyAppUrl(`/home/media/${input.relateableId}`);
11409
- if (directUrl) return directUrl;
11410
- }
11411
- return normalizeShareUrl((await portAdapter.createShare({
11444
+ return buildShareUrl(shareableType, (await portAdapter.createShare({
11412
11445
  shareable_type: shareableType,
11413
11446
  shareable_id: input.relateableId
11414
11447
  })).share.url);
@@ -11681,4 +11714,4 @@ Object.defineProperty(exports, "usePortalContentContext", {
11681
11714
  }
11682
11715
  });
11683
11716
 
11684
- //# sourceMappingURL=PortalContentApiProvider-Cho3MNVB.cjs.map
11717
+ //# sourceMappingURL=PortalContentApiProvider-DMeTMGV6.cjs.map