@gfed-medusa/sf-lib-products 1.6.2 → 1.7.0

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 (77) hide show
  1. package/dist/components/browse-product-preview/index.d.ts +19 -0
  2. package/dist/components/browse-product-preview/index.d.ts.map +1 -0
  3. package/dist/components/browse-product-preview/index.js +61 -0
  4. package/dist/components/browse-product-preview/index.js.map +1 -0
  5. package/dist/components/image-gallery/index.d.ts +2 -2
  6. package/dist/components/image-gallery/index.js +1 -1
  7. package/dist/components/pagination/index.d.ts +2 -2
  8. package/dist/components/pagination/index.d.ts.map +1 -1
  9. package/dist/components/product-actions/index.d.ts +4 -2
  10. package/dist/components/product-actions/index.d.ts.map +1 -1
  11. package/dist/components/product-actions/index.js +15 -11
  12. package/dist/components/product-actions/index.js.map +1 -1
  13. package/dist/components/product-actions/mobile-actions.d.ts.map +1 -1
  14. package/dist/components/product-actions/mobile-actions.js +23 -26
  15. package/dist/components/product-actions/mobile-actions.js.map +1 -1
  16. package/dist/components/product-onboarding-cta/index.d.ts +2 -2
  17. package/dist/components/product-onboarding-cta/index.d.ts.map +1 -1
  18. package/dist/components/product-price/index.d.ts +2 -2
  19. package/dist/components/product-price/index.d.ts.map +1 -1
  20. package/dist/components/product-tabs/index.d.ts +2 -2
  21. package/dist/components/refinement-list/index.d.ts +5 -3
  22. package/dist/components/refinement-list/index.d.ts.map +1 -1
  23. package/dist/components/refinement-list/index.js +22 -9
  24. package/dist/components/refinement-list/index.js.map +1 -1
  25. package/dist/components/refinement-list/sort-products/index.d.ts +5 -3
  26. package/dist/components/refinement-list/sort-products/index.d.ts.map +1 -1
  27. package/dist/components/refinement-list/sort-products/index.js +17 -1
  28. package/dist/components/refinement-list/sort-products/index.js.map +1 -1
  29. package/dist/components/related-products/index.d.ts +2 -2
  30. package/dist/components/skeleton-product-grid/index.d.ts +2 -2
  31. package/dist/components/skeleton-product-preview/index.d.ts +2 -2
  32. package/dist/components/skeleton-related-products/index.d.ts +2 -2
  33. package/dist/lib/data/products.d.ts +12 -10
  34. package/dist/lib/data/products.d.ts.map +1 -1
  35. package/dist/lib/data/products.js +182 -42
  36. package/dist/lib/data/products.js.map +1 -1
  37. package/dist/lib/gql/fragments/product.d.ts +17 -16
  38. package/dist/lib/gql/fragments/product.d.ts.map +1 -1
  39. package/dist/lib/gql/fragments/product.js +12 -1
  40. package/dist/lib/gql/fragments/product.js.map +1 -1
  41. package/dist/lib/gql/mutations/cart.d.ts +10 -10
  42. package/dist/lib/gql/mutations/cart.d.ts.map +1 -1
  43. package/dist/lib/gql/queries/cart.d.ts +2 -2
  44. package/dist/lib/gql/queries/product.d.ts +14 -13
  45. package/dist/lib/gql/queries/product.d.ts.map +1 -1
  46. package/dist/lib/gql/queries/product.js +30 -2
  47. package/dist/lib/gql/queries/product.js.map +1 -1
  48. package/dist/lib/utils/merge-product-pricing.d.ts +7 -0
  49. package/dist/lib/utils/merge-product-pricing.d.ts.map +1 -0
  50. package/dist/lib/utils/merge-product-pricing.js +20 -0
  51. package/dist/lib/utils/merge-product-pricing.js.map +1 -0
  52. package/dist/templates/paginated-products/index.d.ts +2 -2
  53. package/dist/templates/paginated-products/index.d.ts.map +1 -1
  54. package/dist/templates/paginated-products/index.js +2 -5
  55. package/dist/templates/paginated-products/index.js.map +1 -1
  56. package/dist/templates/product-actions-wrapper/index.d.ts +2 -2
  57. package/dist/templates/product-actions-wrapper/index.d.ts.map +1 -1
  58. package/dist/templates/product-actions-wrapper/index.js +7 -18
  59. package/dist/templates/product-actions-wrapper/index.js.map +1 -1
  60. package/dist/templates/product-info/index.d.ts +2 -2
  61. package/dist/templates/product-info/index.d.ts.map +1 -1
  62. package/dist/templates/product-info/index.js +1 -1
  63. package/dist/templates/product-template/index.js +5 -2
  64. package/dist/templates/product-template/index.js.map +1 -1
  65. package/dist/templates/store-template/index.d.ts +2 -2
  66. package/dist/templates/store-template/index.d.ts.map +1 -1
  67. package/dist/templates/store-template/index.js +12 -6
  68. package/dist/templates/store-template/index.js.map +1 -1
  69. package/dist/types/graphql.d.ts +118 -1
  70. package/dist/types/graphql.d.ts.map +1 -1
  71. package/dist/types/graphql.js +595 -1
  72. package/dist/types/graphql.js.map +1 -1
  73. package/package.json +5 -4
  74. package/dist/lib/utils/sort-products.d.ts +0 -15
  75. package/dist/lib/utils/sort-products.d.ts.map +0 -1
  76. package/dist/lib/utils/sort-products.js +0 -30
  77. package/dist/lib/utils/sort-products.js.map +0 -1
@@ -0,0 +1,19 @@
1
+ import { BrowseProductHitFragment } from "../../types/graphql.js";
2
+ import * as react_jsx_runtime6 from "react/jsx-runtime";
3
+
4
+ //#region src/components/browse-product-preview/index.d.ts
5
+ type BrowseProductPreviewProps = {
6
+ product: BrowseProductHitFragment;
7
+ isFeatured?: boolean;
8
+ imagePriority?: boolean;
9
+ imageFetchPriority?: 'auto' | 'high' | 'low';
10
+ };
11
+ declare const BrowseProductPreview: ({
12
+ product,
13
+ isFeatured,
14
+ imagePriority,
15
+ imageFetchPriority
16
+ }: BrowseProductPreviewProps) => react_jsx_runtime6.JSX.Element;
17
+ //#endregion
18
+ export { BrowseProductPreview };
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/browse-product-preview/index.tsx"],"sourcesContent":[],"mappings":";;;;KAUK,yBAAA;WACM;;EADN,aAAA,CAAA,EAAA,OAAA;EA0CC,kBAAA,CAAA,EAAA,MAiCL,GAAA,MAAA,GAAA,KAAA;CAjC6B;cAAxB,oBAAwB,EAAA,CAAA;EAAA,OAAA;EAAA,UAAA;EAAA,aAAA;EAAA;AAAA,CAAA,EAK3B,yBAL2B,EAAA,GAKF,kBAAA,CAAA,GAAA,CAAA,OALE"}
@@ -0,0 +1,61 @@
1
+ import { LocalizedClientLink } from "@gfed-medusa/sf-lib-common/components/localized-client-link";
2
+ import { PreviewPrice } from "@gfed-medusa/sf-lib-common/components/preview-price";
3
+ import { Thumbnail } from "@gfed-medusa/sf-lib-common/components/thumbnail";
4
+ import { getPercentageDiff } from "@gfed-medusa/sf-lib-common/lib/utils/get-percentage-diff";
5
+ import { convertToLocale } from "@gfed-medusa/sf-lib-common/lib/utils/money";
6
+ import { Text } from "@medusajs/ui";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+
9
+ //#region src/components/browse-product-preview/index.tsx
10
+ const getBrowseProductPrice = (product) => {
11
+ if (typeof product.priceAmount !== "number" || !product.currencyCode || !product.currencyCode.trim()) return null;
12
+ const originalPrice = product.originalPriceAmount ?? product.priceAmount;
13
+ const isSale = typeof originalPrice === "number" && originalPrice > product.priceAmount;
14
+ return {
15
+ calculated_price_number: product.priceAmount,
16
+ calculated_price: convertToLocale({
17
+ amount: product.priceAmount,
18
+ currency_code: product.currencyCode
19
+ }),
20
+ original_price_number: originalPrice,
21
+ original_price: convertToLocale({
22
+ amount: originalPrice,
23
+ currency_code: product.currencyCode
24
+ }),
25
+ currency_code: product.currencyCode,
26
+ price_type: isSale ? "sale" : "default",
27
+ percentage_diff: isSale && originalPrice > 0 ? getPercentageDiff(originalPrice, product.priceAmount) : "0"
28
+ };
29
+ };
30
+ const BrowseProductPreview = ({ product, isFeatured, imagePriority = false, imageFetchPriority }) => {
31
+ const price = getBrowseProductPrice(product);
32
+ return /* @__PURE__ */ jsx(LocalizedClientLink, {
33
+ href: `/products/${product.handle}`,
34
+ className: "group",
35
+ children: /* @__PURE__ */ jsxs("div", {
36
+ "data-testid": "product-wrapper",
37
+ children: [/* @__PURE__ */ jsx(Thumbnail, {
38
+ thumbnail: product.thumbnail,
39
+ images: [],
40
+ size: "full",
41
+ isFeatured,
42
+ imagePriority,
43
+ imageFetchPriority
44
+ }), /* @__PURE__ */ jsxs("div", {
45
+ className: "txt-compact-medium mt-4 flex items-start justify-between gap-x-4",
46
+ children: [/* @__PURE__ */ jsx(Text, {
47
+ className: "text-ui-fg-subtle flex-1",
48
+ "data-testid": "product-title",
49
+ children: product.title
50
+ }), /* @__PURE__ */ jsx("div", {
51
+ className: "flex shrink-0 items-start gap-x-2",
52
+ children: price && /* @__PURE__ */ jsx(PreviewPrice, { price })
53
+ })]
54
+ })]
55
+ })
56
+ });
57
+ };
58
+
59
+ //#endregion
60
+ export { BrowseProductPreview };
61
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/browse-product-preview/index.tsx"],"sourcesContent":["import { LocalizedClientLink } from '@gfed-medusa/sf-lib-common/components/localized-client-link';\nimport { PreviewPrice } from '@gfed-medusa/sf-lib-common/components/preview-price';\nimport { Thumbnail } from '@gfed-medusa/sf-lib-common/components/thumbnail';\nimport { getPercentageDiff } from '@gfed-medusa/sf-lib-common/lib/utils/get-percentage-diff';\nimport { convertToLocale } from '@gfed-medusa/sf-lib-common/lib/utils/money';\nimport type { VariantPrice } from '@gfed-medusa/sf-lib-common/types/prices';\nimport { Text } from '@medusajs/ui';\n\nimport type { BrowseProductHitFragment } from '@/types/graphql';\n\ntype BrowseProductPreviewProps = {\n product: BrowseProductHitFragment;\n isFeatured?: boolean;\n imagePriority?: boolean;\n imageFetchPriority?: 'auto' | 'high' | 'low';\n};\n\nconst getBrowseProductPrice = (\n product: BrowseProductHitFragment\n): VariantPrice | null => {\n if (\n typeof product.priceAmount !== 'number' ||\n !product.currencyCode ||\n !product.currencyCode.trim()\n ) {\n return null;\n }\n\n const originalPrice = product.originalPriceAmount ?? product.priceAmount;\n const isSale =\n typeof originalPrice === 'number' && originalPrice > product.priceAmount;\n\n return {\n calculated_price_number: product.priceAmount,\n calculated_price: convertToLocale({\n amount: product.priceAmount,\n currency_code: product.currencyCode,\n }),\n original_price_number: originalPrice,\n original_price: convertToLocale({\n amount: originalPrice,\n currency_code: product.currencyCode,\n }),\n currency_code: product.currencyCode,\n price_type: isSale ? 'sale' : 'default',\n percentage_diff:\n isSale && originalPrice > 0\n ? getPercentageDiff(originalPrice, product.priceAmount)\n : '0',\n };\n};\n\nconst BrowseProductPreview = ({\n product,\n isFeatured,\n imagePriority = false,\n imageFetchPriority,\n}: BrowseProductPreviewProps) => {\n const price = getBrowseProductPrice(product);\n\n return (\n <LocalizedClientLink href={`/products/${product.handle}`} className=\"group\">\n <div data-testid=\"product-wrapper\">\n <Thumbnail\n thumbnail={product.thumbnail}\n images={[]}\n size=\"full\"\n isFeatured={isFeatured}\n imagePriority={imagePriority}\n imageFetchPriority={imageFetchPriority}\n />\n <div className=\"txt-compact-medium mt-4 flex items-start justify-between gap-x-4\">\n <Text\n className=\"text-ui-fg-subtle flex-1\"\n data-testid=\"product-title\"\n >\n {product.title}\n </Text>\n <div className=\"flex shrink-0 items-start gap-x-2\">\n {price && <PreviewPrice price={price} />}\n </div>\n </div>\n </div>\n </LocalizedClientLink>\n );\n};\n\nexport { BrowseProductPreview };\n"],"mappings":";;;;;;;;;AAiBA,MAAM,yBACJ,YACwB;AACxB,KACE,OAAO,QAAQ,gBAAgB,YAC/B,CAAC,QAAQ,gBACT,CAAC,QAAQ,aAAa,MAAM,CAE5B,QAAO;CAGT,MAAM,gBAAgB,QAAQ,uBAAuB,QAAQ;CAC7D,MAAM,SACJ,OAAO,kBAAkB,YAAY,gBAAgB,QAAQ;AAE/D,QAAO;EACL,yBAAyB,QAAQ;EACjC,kBAAkB,gBAAgB;GAChC,QAAQ,QAAQ;GAChB,eAAe,QAAQ;GACxB,CAAC;EACF,uBAAuB;EACvB,gBAAgB,gBAAgB;GAC9B,QAAQ;GACR,eAAe,QAAQ;GACxB,CAAC;EACF,eAAe,QAAQ;EACvB,YAAY,SAAS,SAAS;EAC9B,iBACE,UAAU,gBAAgB,IACtB,kBAAkB,eAAe,QAAQ,YAAY,GACrD;EACP;;AAGH,MAAM,wBAAwB,EAC5B,SACA,YACA,gBAAgB,OAChB,yBAC+B;CAC/B,MAAM,QAAQ,sBAAsB,QAAQ;AAE5C,QACE,oBAAC;EAAoB,MAAM,aAAa,QAAQ;EAAU,WAAU;YAClE,qBAAC;GAAI,eAAY;cACf,oBAAC;IACC,WAAW,QAAQ;IACnB,QAAQ,EAAE;IACV,MAAK;IACO;IACG;IACK;KACpB,EACF,qBAAC;IAAI,WAAU;eACb,oBAAC;KACC,WAAU;KACV,eAAY;eAEX,QAAQ;MACJ,EACP,oBAAC;KAAI,WAAU;eACZ,SAAS,oBAAC,gBAAoB,QAAS;MACpC;KACF;IACF;GACc"}
@@ -1,5 +1,5 @@
1
1
  import { ProductImage } from "../../types/graphql.js";
2
- import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime5 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/image-gallery/index.d.ts
5
5
  type ImageGalleryProps = {
@@ -7,7 +7,7 @@ type ImageGalleryProps = {
7
7
  };
8
8
  declare const ImageGallery: ({
9
9
  images
10
- }: ImageGalleryProps) => react_jsx_runtime0.JSX.Element;
10
+ }: ImageGalleryProps) => react_jsx_runtime5.JSX.Element;
11
11
  //#endregion
12
12
  export { ImageGallery as default };
13
13
  //# sourceMappingURL=index.d.ts.map
@@ -1,6 +1,6 @@
1
- import Image from "next/image";
2
1
  import { Container } from "@medusajs/ui";
3
2
  import { jsx } from "react/jsx-runtime";
3
+ import Image from "next/image";
4
4
 
5
5
  //#region src/components/image-gallery/index.tsx
6
6
  const ImageGallery = ({ images }) => {
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime0 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime13 from "react/jsx-runtime";
2
2
 
3
3
  //#region src/components/pagination/index.d.ts
4
4
  declare function Pagination({
@@ -9,7 +9,7 @@ declare function Pagination({
9
9
  page: number;
10
10
  totalPages: number;
11
11
  'data-testid'?: string;
12
- }): react_jsx_runtime0.JSX.Element;
12
+ }): react_jsx_runtime13.JSX.Element;
13
13
  //#endregion
14
14
  export { Pagination };
15
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/pagination/index.tsx"],"sourcesContent":[],"mappings":";;;iBAMgB,UAAA;;;iBAGC;;;;EAHD,aAAU,CAAA,EAAA,MAAA;CACxB,CAAA,EAOD,kBAAA,CAAA,GAAA,CAAA,OAPC"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/pagination/index.tsx"],"sourcesContent":[],"mappings":";;;iBAMgB,UAAA;;;iBAGC;;;;EAHD,aAAU,CAAA,EAAA,MAAA;CACxB,CAAA,EAOD,mBAAA,CAAA,GAAA,CAAA,OAPC"}
@@ -1,17 +1,19 @@
1
1
  import { ProductActionsProduct } from "../../types/index.js";
2
- import * as react_jsx_runtime1 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime12 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/product-actions/index.d.ts
5
5
  type ProductActionsProps = {
6
6
  product: ProductActionsProduct;
7
+ regionId?: string;
7
8
  disabled?: boolean;
8
9
  enableMobileActions?: boolean;
9
10
  };
10
11
  declare function ProductActions({
11
12
  product,
13
+ regionId,
12
14
  disabled,
13
15
  enableMobileActions
14
- }: ProductActionsProps): react_jsx_runtime1.JSX.Element;
16
+ }: ProductActionsProps): react_jsx_runtime12.JSX.Element;
15
17
  //#endregion
16
18
  export { ProductActionsProps, ProductActions as default };
17
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/product-actions/index.tsx"],"sourcesContent":[],"mappings":";;;;KAuBY,mBAAA;WACD;;EADC,mBAAA,CAAA,EAAmB,OAAA;AAI7B,CAAA;AAuBA,iBADsB,cAAA,CACtB;EAAA,OAAA;EAAA,QAAA;EAAA;AAAA,CAAA,EAGC,mBAHD,CAAA,EAGoB,kBAAA,CAAA,GAAA,CAAA,OAHpB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/product-actions/index.tsx"],"sourcesContent":[],"mappings":";;;;KAyBY,mBAAA;WACD;;EADC,QAAA,CAAA,EAAA,OAAA;EA2BY,mBAAc,CAAA,EAAA,OAAA;CACpC;AACA,iBAFsB,cAAA,CAEtB;EAAA,OAAA;EAAA,QAAA;EAAA,QAAA;EAAA;AAAA,CAAA,EAGC,mBAHD,CAAA,EAGoB,mBAAA,CAAA,GAAA,CAAA,OAHpB"}
@@ -2,7 +2,9 @@
2
2
 
3
3
  import option_select_default from "./option-select.js";
4
4
  import { addToCart } from "../../lib/data/cart.js";
5
+ import { useProductPrice } from "../../lib/hooks/use-product-price.js";
5
6
  import { useIntersection } from "../../lib/hooks/use-intersection.js";
7
+ import { mergeProductPricing } from "../../lib/utils/merge-product-pricing.js";
6
8
  import ProductPrice from "../product-price/index.js";
7
9
  import mobile_actions_default from "./mobile-actions.js";
8
10
  import { Button } from "@medusajs/ui";
@@ -28,19 +30,21 @@ const optionsAsKeymap = (variantOptions) => {
28
30
  return acc;
29
31
  }, {});
30
32
  };
31
- function ProductActions({ product, disabled, enableMobileActions = true }) {
33
+ function ProductActions({ product, regionId, disabled, enableMobileActions = true }) {
32
34
  const [options, setOptions] = useState({});
33
35
  const [status, setStatus] = useState(AddToCartStatus.IDLE);
34
36
  const countryCode = useParams().countryCode;
37
+ const { product: pricingProduct } = useProductPrice(product.id, regionId);
38
+ const pricedProduct = useMemo(() => mergeProductPricing(product, pricingProduct), [product, pricingProduct]);
35
39
  useEffect(() => {
36
- if (product?.variants && product.variants.length === 1) setOptions(optionsAsKeymap(product.variants[0]?.options || null) ?? {});
37
- }, [product.variants]);
40
+ if (pricedProduct?.variants && pricedProduct.variants.length === 1) setOptions(optionsAsKeymap(pricedProduct.variants[0]?.options || null) ?? {});
41
+ }, [pricedProduct.variants]);
38
42
  const selectedVariant = useMemo(() => {
39
- if (!product.variants || product.variants.length === 0) return;
40
- return product.variants.find((v) => {
43
+ if (!pricedProduct.variants || pricedProduct.variants.length === 0) return;
44
+ return pricedProduct.variants.find((v) => {
41
45
  return isEqual(optionsAsKeymap(v.options), options);
42
46
  });
43
- }, [product.variants, options]);
47
+ }, [pricedProduct.variants, options]);
44
48
  const setOptionValue = (optionId, value) => {
45
49
  setOptions((prev) => ({
46
50
  ...prev,
@@ -48,10 +52,10 @@ function ProductActions({ product, disabled, enableMobileActions = true }) {
48
52
  }));
49
53
  };
50
54
  const isValidVariant = useMemo(() => {
51
- return product.variants?.some((v) => {
55
+ return pricedProduct.variants?.some((v) => {
52
56
  return isEqual(optionsAsKeymap(v.options), options);
53
57
  });
54
- }, [product.variants, options]);
58
+ }, [pricedProduct.variants, options]);
55
59
  const stockStatus = useMemo(() => {
56
60
  if (!selectedVariant) return "unknown";
57
61
  if (!selectedVariant.manageInventory) return "in_stock";
@@ -106,7 +110,7 @@ function ProductActions({ product, disabled, enableMobileActions = true }) {
106
110
  }), /* @__PURE__ */ jsx(Divider, {})]
107
111
  }) }),
108
112
  /* @__PURE__ */ jsx(ProductPrice, {
109
- product,
113
+ product: pricedProduct,
110
114
  variant: selectedVariant
111
115
  }),
112
116
  status === AddToCartStatus.ERROR && /* @__PURE__ */ jsx(ErrorMessage, { error: "Failed adding product to cart. Please try again." }),
@@ -121,10 +125,10 @@ function ProductActions({ product, disabled, enableMobileActions = true }) {
121
125
  className: "h-10 w-full",
122
126
  isLoading: status === AddToCartStatus.ADDING,
123
127
  "data-testid": "add-product-button",
124
- children: !selectedVariant ? "Select size" : !inStock || !isValidVariant ? "Out of stock" : "Add to cart"
128
+ children: !selectedVariant ? "Add to cart" : !inStock || !isValidVariant ? "Out of stock" : "Add to cart"
125
129
  }),
126
130
  enableMobileActions && /* @__PURE__ */ jsx(mobile_actions_default, {
127
- product,
131
+ product: pricedProduct,
128
132
  variant: selectedVariant,
129
133
  options,
130
134
  updateOptions: setOptionValue,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["OptionSelect","MobileActions"],"sources":["../../../src/components/product-actions/index.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\n\nimport { useParams } from 'next/navigation';\n\nimport { isEqual } from 'lodash';\n\nimport { ErrorMessage } from '@gfed-medusa/sf-lib-common/components/error-message';\nimport { mutateCart } from '@gfed-medusa/sf-lib-common/lib/hooks/use-cart';\nimport { Divider } from '@gfed-medusa/sf-lib-ui/components/divider';\nimport { HttpTypes } from '@medusajs/types';\nimport { Button } from '@medusajs/ui';\n\nimport OptionSelect from '@/components/product-actions/option-select';\nimport { addToCart } from '@/lib/data/cart';\nimport { useIntersection } from '@/lib/hooks/use-intersection';\nimport { ProductActionsProduct } from '@/types';\nimport { ProductVariant } from '@/types/graphql';\n\nimport ProductPrice from '../product-price';\nimport MobileActions from './mobile-actions';\n\nexport type ProductActionsProps = {\n product: ProductActionsProduct;\n disabled?: boolean;\n enableMobileActions?: boolean;\n};\n\nenum AddToCartStatus {\n IDLE = 'idle',\n ADDING = 'adding',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\nconst optionsAsKeymap = (\n variantOptions:\n | HttpTypes.StoreProductVariant['options']\n | ProductVariant['options']\n | null\n | undefined\n) => {\n return variantOptions?.reduce((acc: Record<string, string>, varopt: any) => {\n acc[varopt.optionId] = varopt.value;\n return acc;\n }, {});\n};\n\nexport default function ProductActions({\n product,\n disabled,\n enableMobileActions = true,\n}: ProductActionsProps) {\n const [options, setOptions] = useState<Record<string, string | undefined>>(\n {}\n );\n const [status, setStatus] = useState<AddToCartStatus>(AddToCartStatus.IDLE);\n const countryCode = useParams().countryCode as string;\n\n // If there is only 1 variant, preselect the options\n useEffect(() => {\n if (product?.variants && product.variants.length === 1) {\n const variantOptions = optionsAsKeymap(\n product.variants[0]?.options || null\n );\n setOptions(variantOptions ?? {});\n }\n }, [product.variants]);\n\n const selectedVariant = useMemo(() => {\n if (!product.variants || product.variants.length === 0) {\n return;\n }\n\n return product.variants.find((v) => {\n const variantOptions = optionsAsKeymap(v.options);\n return isEqual(variantOptions, options);\n });\n }, [product.variants, options]);\n\n // update the options when a variant is selected\n const setOptionValue = (optionId: string, value: string) => {\n setOptions((prev) => ({\n ...prev,\n [optionId]: value,\n }));\n };\n\n //check if the selected options produce a valid variant\n const isValidVariant = useMemo(() => {\n return product.variants?.some((v) => {\n const variantOptions = optionsAsKeymap(v.options);\n return isEqual(variantOptions, options);\n });\n }, [product.variants, options]);\n\n const stockStatus = useMemo(() => {\n if (!selectedVariant) {\n return 'unknown' as const;\n }\n\n if (!selectedVariant.manageInventory) {\n return 'in_stock' as const;\n }\n\n if (selectedVariant.allowBackorder) {\n return 'in_stock' as const;\n }\n\n const qty = selectedVariant.inventoryQuantity;\n\n if (typeof qty !== 'number') {\n return 'in_stock' as const;\n }\n\n return qty > 0 ? ('in_stock' as const) : ('out_of_stock' as const);\n }, [selectedVariant]);\n\n const inStock = useMemo(() => {\n // If we don't manage inventory, we can always add to cart\n if (selectedVariant && !selectedVariant.manageInventory) {\n return true;\n }\n\n // If we allow back orders on the variant, we can add to cart\n if (selectedVariant?.allowBackorder) {\n return true;\n }\n\n if (selectedVariant?.manageInventory) {\n const qty = selectedVariant.inventoryQuantity;\n if (typeof qty === 'number') {\n return qty > 0;\n }\n // If we don't have a numeric quantity, don't block add-to-cart\n return true;\n }\n\n // Otherwise, we can't add to cart\n return false;\n }, [selectedVariant]);\n\n const actionsRef = useRef<HTMLDivElement>(null);\n\n const inView = useIntersection(actionsRef, '0px');\n\n // add the selected variant to the cart\n const handleAddToCart = async () => {\n if (!selectedVariant?.id) return null;\n\n setStatus(AddToCartStatus.ADDING);\n\n try {\n await addToCart({\n variantId: selectedVariant.id,\n quantity: 1,\n countryCode,\n });\n\n mutateCart();\n\n setStatus(AddToCartStatus.SUCCESS);\n } catch (error) {\n console.log(error);\n setStatus(AddToCartStatus.ERROR);\n }\n };\n\n return (\n <>\n <div className=\"flex flex-col gap-y-2\" ref={actionsRef}>\n <div>\n {(product.variants?.length ?? 0) > 1 && (\n <div className=\"flex flex-col gap-y-4\">\n {(product.options || []).map((option) => {\n return (\n <div key={option.id}>\n <OptionSelect\n option={option}\n current={options[option.id]}\n updateOption={setOptionValue}\n title={option.title ?? ''}\n data-testid=\"product-options\"\n disabled={!!disabled || status === AddToCartStatus.ADDING}\n />\n </div>\n );\n })}\n <Divider />\n </div>\n )}\n </div>\n\n <ProductPrice product={product} variant={selectedVariant} />\n\n {status === AddToCartStatus.ERROR && (\n <ErrorMessage error=\"Failed adding product to cart. Please try again.\" />\n )}\n {status === AddToCartStatus.SUCCESS && (\n <div className=\"text-small-regular pt-2 text-green-700\">\n Successfully added product to cart\n </div>\n )}\n <Button\n onClick={handleAddToCart}\n disabled={\n !inStock ||\n !selectedVariant ||\n !!disabled ||\n status === AddToCartStatus.ADDING ||\n !isValidVariant\n }\n variant=\"primary\"\n className=\"h-10 w-full\"\n isLoading={status === AddToCartStatus.ADDING}\n data-testid=\"add-product-button\"\n >\n {!selectedVariant\n ? 'Select size'\n : !inStock || !isValidVariant\n ? 'Out of stock'\n : 'Add to cart'}\n </Button>\n {enableMobileActions && (\n <MobileActions\n product={product}\n variant={selectedVariant}\n options={options}\n updateOptions={setOptionValue}\n stockStatus={stockStatus}\n handleAddToCart={handleAddToCart}\n isAdding={status === AddToCartStatus.ADDING}\n show={!inView}\n optionsDisabled={!!disabled || status === AddToCartStatus.ADDING}\n />\n )}\n </div>\n </>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA6BA,IAAK,8DAAL;AACE;AACA;AACA;AACA;;EAJG;AAOL,MAAM,mBACJ,mBAKG;AACH,QAAO,gBAAgB,QAAQ,KAA6B,WAAgB;AAC1E,MAAI,OAAO,YAAY,OAAO;AAC9B,SAAO;IACN,EAAE,CAAC;;AAGR,SAAwB,eAAe,EACrC,SACA,UACA,sBAAsB,QACA;CACtB,MAAM,CAAC,SAAS,cAAc,SAC5B,EAAE,CACH;CACD,MAAM,CAAC,QAAQ,aAAa,SAA0B,gBAAgB,KAAK;CAC3E,MAAM,cAAc,WAAW,CAAC;AAGhC,iBAAgB;AACd,MAAI,SAAS,YAAY,QAAQ,SAAS,WAAW,EAInD,YAHuB,gBACrB,QAAQ,SAAS,IAAI,WAAW,KACjC,IAC4B,EAAE,CAAC;IAEjC,CAAC,QAAQ,SAAS,CAAC;CAEtB,MAAM,kBAAkB,cAAc;AACpC,MAAI,CAAC,QAAQ,YAAY,QAAQ,SAAS,WAAW,EACnD;AAGF,SAAO,QAAQ,SAAS,MAAM,MAAM;AAElC,UAAO,QADgB,gBAAgB,EAAE,QAAQ,EAClB,QAAQ;IACvC;IACD,CAAC,QAAQ,UAAU,QAAQ,CAAC;CAG/B,MAAM,kBAAkB,UAAkB,UAAkB;AAC1D,cAAY,UAAU;GACpB,GAAG;IACF,WAAW;GACb,EAAE;;CAIL,MAAM,iBAAiB,cAAc;AACnC,SAAO,QAAQ,UAAU,MAAM,MAAM;AAEnC,UAAO,QADgB,gBAAgB,EAAE,QAAQ,EAClB,QAAQ;IACvC;IACD,CAAC,QAAQ,UAAU,QAAQ,CAAC;CAE/B,MAAM,cAAc,cAAc;AAChC,MAAI,CAAC,gBACH,QAAO;AAGT,MAAI,CAAC,gBAAgB,gBACnB,QAAO;AAGT,MAAI,gBAAgB,eAClB,QAAO;EAGT,MAAM,MAAM,gBAAgB;AAE5B,MAAI,OAAO,QAAQ,SACjB,QAAO;AAGT,SAAO,MAAM,IAAK,aAAwB;IACzC,CAAC,gBAAgB,CAAC;CAErB,MAAM,UAAU,cAAc;AAE5B,MAAI,mBAAmB,CAAC,gBAAgB,gBACtC,QAAO;AAIT,MAAI,iBAAiB,eACnB,QAAO;AAGT,MAAI,iBAAiB,iBAAiB;GACpC,MAAM,MAAM,gBAAgB;AAC5B,OAAI,OAAO,QAAQ,SACjB,QAAO,MAAM;AAGf,UAAO;;AAIT,SAAO;IACN,CAAC,gBAAgB,CAAC;CAErB,MAAM,aAAa,OAAuB,KAAK;CAE/C,MAAM,SAAS,gBAAgB,YAAY,MAAM;CAGjD,MAAM,kBAAkB,YAAY;AAClC,MAAI,CAAC,iBAAiB,GAAI,QAAO;AAEjC,YAAU,gBAAgB,OAAO;AAEjC,MAAI;AACF,SAAM,UAAU;IACd,WAAW,gBAAgB;IAC3B,UAAU;IACV;IACD,CAAC;AAEF,eAAY;AAEZ,aAAU,gBAAgB,QAAQ;WAC3B,OAAO;AACd,WAAQ,IAAI,MAAM;AAClB,aAAU,gBAAgB,MAAM;;;AAIpC,QACE,0CACE,qBAAC;EAAI,WAAU;EAAwB,KAAK;;GAC1C,oBAAC,oBACG,QAAQ,UAAU,UAAU,KAAK,KACjC,qBAAC;IAAI,WAAU;gBACX,QAAQ,WAAW,EAAE,EAAE,KAAK,WAAW;AACvC,YACE,oBAAC,mBACC,oBAACA;MACS;MACR,SAAS,QAAQ,OAAO;MACxB,cAAc;MACd,OAAO,OAAO,SAAS;MACvB,eAAY;MACZ,UAAU,CAAC,CAAC,YAAY,WAAW,gBAAgB;OACnD,IARM,OAAO,GASX;MAER,EACF,oBAAC,YAAU;KACP,GAEJ;GAEN,oBAAC;IAAsB;IAAS,SAAS;KAAmB;GAE3D,WAAW,gBAAgB,SAC1B,oBAAC,gBAAa,OAAM,qDAAqD;GAE1E,WAAW,gBAAgB,WAC1B,oBAAC;IAAI,WAAU;cAAyC;KAElD;GAER,oBAAC;IACC,SAAS;IACT,UACE,CAAC,WACD,CAAC,mBACD,CAAC,CAAC,YACF,WAAW,gBAAgB,UAC3B,CAAC;IAEH,SAAQ;IACR,WAAU;IACV,WAAW,WAAW,gBAAgB;IACtC,eAAY;cAEX,CAAC,kBACE,gBACA,CAAC,WAAW,CAAC,iBACX,iBACA;KACC;GACR,uBACC,oBAACC;IACU;IACT,SAAS;IACA;IACT,eAAe;IACF;IACI;IACjB,UAAU,WAAW,gBAAgB;IACrC,MAAM,CAAC;IACP,iBAAiB,CAAC,CAAC,YAAY,WAAW,gBAAgB;KAC1D;;GAEA,GACL"}
1
+ {"version":3,"file":"index.js","names":["OptionSelect","MobileActions"],"sources":["../../../src/components/product-actions/index.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\n\nimport { useParams } from 'next/navigation';\n\nimport { isEqual } from 'lodash';\n\nimport { ErrorMessage } from '@gfed-medusa/sf-lib-common/components/error-message';\nimport { mutateCart } from '@gfed-medusa/sf-lib-common/lib/hooks/use-cart';\nimport { Divider } from '@gfed-medusa/sf-lib-ui/components/divider';\nimport { HttpTypes } from '@medusajs/types';\nimport { Button } from '@medusajs/ui';\n\nimport OptionSelect from '@/components/product-actions/option-select';\nimport { addToCart } from '@/lib/data/cart';\nimport { useProductPrice } from '@/lib/hooks/use-product-price';\nimport { useIntersection } from '@/lib/hooks/use-intersection';\nimport { mergeProductPricing } from '@/lib/utils/merge-product-pricing';\nimport { ProductActionsProduct } from '@/types';\nimport { ProductVariant } from '@/types/graphql';\n\nimport ProductPrice from '../product-price';\nimport MobileActions from './mobile-actions';\n\nexport type ProductActionsProps = {\n product: ProductActionsProduct;\n regionId?: string;\n disabled?: boolean;\n enableMobileActions?: boolean;\n};\n\nenum AddToCartStatus {\n IDLE = 'idle',\n ADDING = 'adding',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\nconst optionsAsKeymap = (\n variantOptions:\n | HttpTypes.StoreProductVariant['options']\n | ProductVariant['options']\n | null\n | undefined\n) => {\n return variantOptions?.reduce((acc: Record<string, string>, varopt: any) => {\n acc[varopt.optionId] = varopt.value;\n return acc;\n }, {});\n};\n\nexport default function ProductActions({\n product,\n regionId,\n disabled,\n enableMobileActions = true,\n}: ProductActionsProps) {\n const [options, setOptions] = useState<Record<string, string | undefined>>(\n {}\n );\n const [status, setStatus] = useState<AddToCartStatus>(AddToCartStatus.IDLE);\n const countryCode = useParams().countryCode as string;\n const { product: pricingProduct } = useProductPrice(product.id, regionId);\n const pricedProduct = useMemo(\n () => mergeProductPricing(product, pricingProduct),\n [product, pricingProduct]\n );\n\n // If there is only 1 variant, preselect the options\n useEffect(() => {\n if (pricedProduct?.variants && pricedProduct.variants.length === 1) {\n const variantOptions = optionsAsKeymap(\n pricedProduct.variants[0]?.options || null\n );\n setOptions(variantOptions ?? {});\n }\n }, [pricedProduct.variants]);\n\n const selectedVariant = useMemo(() => {\n if (!pricedProduct.variants || pricedProduct.variants.length === 0) {\n return;\n }\n\n return pricedProduct.variants.find((v) => {\n const variantOptions = optionsAsKeymap(v.options);\n return isEqual(variantOptions, options);\n });\n }, [pricedProduct.variants, options]);\n\n // update the options when a variant is selected\n const setOptionValue = (optionId: string, value: string) => {\n setOptions((prev) => ({\n ...prev,\n [optionId]: value,\n }));\n };\n\n //check if the selected options produce a valid variant\n const isValidVariant = useMemo(() => {\n return pricedProduct.variants?.some((v) => {\n const variantOptions = optionsAsKeymap(v.options);\n return isEqual(variantOptions, options);\n });\n }, [pricedProduct.variants, options]);\n\n const stockStatus = useMemo(() => {\n if (!selectedVariant) {\n return 'unknown' as const;\n }\n\n if (!selectedVariant.manageInventory) {\n return 'in_stock' as const;\n }\n\n if (selectedVariant.allowBackorder) {\n return 'in_stock' as const;\n }\n\n const qty = selectedVariant.inventoryQuantity;\n\n if (typeof qty !== 'number') {\n return 'in_stock' as const;\n }\n\n return qty > 0 ? ('in_stock' as const) : ('out_of_stock' as const);\n }, [selectedVariant]);\n\n const inStock = useMemo(() => {\n // If we don't manage inventory, we can always add to cart\n if (selectedVariant && !selectedVariant.manageInventory) {\n return true;\n }\n\n // If we allow back orders on the variant, we can add to cart\n if (selectedVariant?.allowBackorder) {\n return true;\n }\n\n if (selectedVariant?.manageInventory) {\n const qty = selectedVariant.inventoryQuantity;\n if (typeof qty === 'number') {\n return qty > 0;\n }\n // If we don't have a numeric quantity, don't block add-to-cart\n return true;\n }\n\n // Otherwise, we can't add to cart\n return false;\n }, [selectedVariant]);\n\n const actionsRef = useRef<HTMLDivElement>(null);\n\n const inView = useIntersection(actionsRef, '0px');\n\n // add the selected variant to the cart\n const handleAddToCart = async () => {\n if (!selectedVariant?.id) return null;\n\n setStatus(AddToCartStatus.ADDING);\n\n try {\n await addToCart({\n variantId: selectedVariant.id,\n quantity: 1,\n countryCode,\n });\n\n mutateCart();\n\n setStatus(AddToCartStatus.SUCCESS);\n } catch (error) {\n console.log(error);\n setStatus(AddToCartStatus.ERROR);\n }\n };\n\n return (\n <>\n <div className=\"flex flex-col gap-y-2\" ref={actionsRef}>\n <div>\n {(product.variants?.length ?? 0) > 1 && (\n <div className=\"flex flex-col gap-y-4\">\n {(product.options || []).map((option) => {\n return (\n <div key={option.id}>\n <OptionSelect\n option={option}\n current={options[option.id]}\n updateOption={setOptionValue}\n title={option.title ?? ''}\n data-testid=\"product-options\"\n disabled={!!disabled || status === AddToCartStatus.ADDING}\n />\n </div>\n );\n })}\n <Divider />\n </div>\n )}\n </div>\n\n <ProductPrice product={pricedProduct} variant={selectedVariant} />\n\n {status === AddToCartStatus.ERROR && (\n <ErrorMessage error=\"Failed adding product to cart. Please try again.\" />\n )}\n {status === AddToCartStatus.SUCCESS && (\n <div className=\"text-small-regular pt-2 text-green-700\">\n Successfully added product to cart\n </div>\n )}\n <Button\n onClick={handleAddToCart}\n disabled={\n !inStock ||\n !selectedVariant ||\n !!disabled ||\n status === AddToCartStatus.ADDING ||\n !isValidVariant\n }\n variant=\"primary\"\n className=\"h-10 w-full\"\n isLoading={status === AddToCartStatus.ADDING}\n data-testid=\"add-product-button\"\n >\n {!selectedVariant\n ? 'Add to cart'\n : !inStock || !isValidVariant\n ? 'Out of stock'\n : 'Add to cart'}\n </Button>\n {enableMobileActions && (\n <MobileActions\n product={pricedProduct}\n variant={selectedVariant}\n options={options}\n updateOptions={setOptionValue}\n stockStatus={stockStatus}\n handleAddToCart={handleAddToCart}\n isAdding={status === AddToCartStatus.ADDING}\n show={!inView}\n optionsDisabled={!!disabled || status === AddToCartStatus.ADDING}\n />\n )}\n </div>\n </>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"mobile-actions.d.ts","names":[],"sources":["../../../src/components/product-actions/mobile-actions.tsx"],"sourcesContent":[],"mappings":";;;;;KAiBK,kBAAA;WACM;EADN,OAAA,CAAA,EAEO,cAFW;EACZ,OAAA,EAEA,MAFA,CAAA,MAAA,EAAA,MAAA,GAAA,SAAA,CAAA;EACC,aAAA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EACD,WAAA,CAAA,EAAA,SAAA,GAAA,UAAA,GAAA,cAAA;EAAM,eAAA,EAAA,GAAA,GAAA,IAAA;EAuBX,QAAA,CAAA,EAAA,OAoML;;;;cApMK,eAAe,KAAA,CAAM,GAAG"}
1
+ {"version":3,"file":"mobile-actions.d.ts","names":[],"sources":["../../../src/components/product-actions/mobile-actions.tsx"],"sourcesContent":[],"mappings":";;;;;KAiBK,kBAAA;WACM;EADN,OAAA,CAAA,EAEO,cAFW;EACZ,OAAA,EAEA,MAFA,CAAA,MAAA,EAAA,MAAA,GAAA,SAAA,CAAA;EACC,aAAA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EACD,WAAA,CAAA,EAAA,SAAA,GAAA,UAAA,GAAA,cAAA;EAAM,eAAA,EAAA,GAAA,GAAA,IAAA;EAuBX,QAAA,CAAA,EAAA,OAmML;;;;cAnMK,eAAe,KAAA,CAAM,GAAG"}
@@ -27,8 +27,8 @@ const MobileActions = ({ product, variant, options, updateOptions, stockStatus,
27
27
  const selectedPrice = useMemo(() => {
28
28
  if (!price) return null;
29
29
  const { variantPrice, cheapestPrice } = price;
30
- return variantPrice || cheapestPrice || null;
31
- }, [price]);
30
+ return (variant ? variantPrice : cheapestPrice) || null;
31
+ }, [price, variant]);
32
32
  const isSimple = isSimpleProduct(product);
33
33
  const handleUpdateOption = (optionId, value) => {
34
34
  updateOptions(optionId, value);
@@ -53,24 +53,21 @@ const MobileActions = ({ product, variant, options, updateOptions, stockStatus,
53
53
  className: "text-large-regular flex h-full w-full flex-col items-center justify-center gap-y-3 border-t border-gray-200 bg-white p-4",
54
54
  "data-testid": "mobile-actions",
55
55
  children: [/* @__PURE__ */ jsxs("div", {
56
- className: "flex items-center gap-x-2",
57
- children: [
58
- /* @__PURE__ */ jsx("span", {
59
- "data-testid": "mobile-title",
60
- children: product.title
61
- }),
62
- /* @__PURE__ */ jsx("span", { children: "—" }),
63
- selectedPrice ? /* @__PURE__ */ jsxs("div", {
64
- className: "text-ui-fg-base flex items-end gap-x-2",
65
- children: [selectedPrice.price_type === "sale" && /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("span", {
66
- className: "text-small-regular line-through",
67
- children: selectedPrice.original_price
68
- }) }), /* @__PURE__ */ jsx("span", {
69
- className: clx({ "text-ui-fg-interactive": selectedPrice.price_type === "sale" }),
70
- children: selectedPrice.calculated_price
71
- })]
72
- }) : /* @__PURE__ */ jsx("div", { className: "h-5 w-24 animate-pulse bg-gray-100" })
73
- ]
56
+ className: "flex w-full items-start justify-between gap-x-4",
57
+ children: [/* @__PURE__ */ jsx("span", {
58
+ className: "flex-1 text-left",
59
+ "data-testid": "mobile-title",
60
+ children: product.title
61
+ }), selectedPrice ? /* @__PURE__ */ jsxs("div", {
62
+ className: "text-ui-fg-base flex shrink-0 items-start gap-x-2 self-start",
63
+ children: [selectedPrice.price_type === "sale" && /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("span", {
64
+ className: "text-small-regular line-through",
65
+ children: selectedPrice.original_price
66
+ }) }), /* @__PURE__ */ jsxs("span", {
67
+ className: clx({ "text-ui-fg-interactive": selectedPrice.price_type === "sale" }),
68
+ children: [!variant && "From ", selectedPrice.calculated_price]
69
+ })]
70
+ }) : /* @__PURE__ */ jsx("div", { className: "h-5 w-24 shrink-0 self-start animate-pulse bg-gray-100" })]
74
71
  }), /* @__PURE__ */ jsxs("div", {
75
72
  className: clx("grid w-full grid-cols-2 gap-x-4", { "!grid-cols-1": isSimple }),
76
73
  children: [!isSimple && /* @__PURE__ */ jsx(Button, {
@@ -80,7 +77,7 @@ const MobileActions = ({ product, variant, options, updateOptions, stockStatus,
80
77
  "data-testid": "mobile-actions-button",
81
78
  children: /* @__PURE__ */ jsxs("div", {
82
79
  className: "flex w-full items-center justify-between",
83
- children: [/* @__PURE__ */ jsx("span", { children: variant ? Object.values(options).join(" / ") : "Select Options" }), /* @__PURE__ */ jsx(ChevronDown, {})]
80
+ children: [/* @__PURE__ */ jsx("span", { children: variant ? Object.values(options).join(" / ") : "Select Size" }), /* @__PURE__ */ jsx(ChevronDown, {})]
84
81
  })
85
82
  }), /* @__PURE__ */ jsx(Button, {
86
83
  onClick: handleAddToCart,
@@ -88,7 +85,7 @@ const MobileActions = ({ product, variant, options, updateOptions, stockStatus,
88
85
  className: "w-full",
89
86
  isLoading: isAdding,
90
87
  "data-testid": "mobile-cart-button",
91
- children: !variant ? "Select size" : stockStatus === "out_of_stock" ? "Out of stock" : "Add to cart"
88
+ children: stockStatus === "out_of_stock" ? "Out of stock" : "Add to cart"
92
89
  })]
93
90
  })]
94
91
  })
@@ -109,7 +106,7 @@ const MobileActions = ({ product, variant, options, updateOptions, stockStatus,
109
106
  leave: "ease-in duration-200",
110
107
  leaveFrom: "opacity-100",
111
108
  leaveTo: "opacity-0",
112
- children: /* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-gray-700 bg-opacity-75 backdrop-blur-sm" })
109
+ children: /* @__PURE__ */ jsx("div", { className: "fixed inset-0 h-screen bg-black/20 backdrop-blur-sm" })
113
110
  }), /* @__PURE__ */ jsx("div", {
114
111
  className: "fixed inset-x-0 bottom-0",
115
112
  children: /* @__PURE__ */ jsx("div", {
@@ -123,18 +120,18 @@ const MobileActions = ({ product, variant, options, updateOptions, stockStatus,
123
120
  leaveFrom: "opacity-100",
124
121
  leaveTo: "opacity-0",
125
122
  children: /* @__PURE__ */ jsxs(Dialog.Panel, {
126
- className: "flex h-full w-full transform flex-col gap-y-3 overflow-hidden text-left",
123
+ className: "pointer-events-none flex w-full transform flex-col gap-y-3 text-left",
127
124
  "data-testid": "mobile-actions-modal",
128
125
  children: [/* @__PURE__ */ jsx("div", {
129
126
  className: "flex w-full justify-end pr-6",
130
127
  children: /* @__PURE__ */ jsx("button", {
131
128
  onClick: close,
132
- className: "text-ui-fg-base flex h-12 w-12 items-center justify-center rounded-full bg-white",
129
+ className: "text-ui-fg-base pointer-events-auto flex h-12 w-12 items-center justify-center rounded-full bg-white",
133
130
  "data-testid": "close-modal-button",
134
131
  children: /* @__PURE__ */ jsx(X, {})
135
132
  })
136
133
  }), /* @__PURE__ */ jsx("div", {
137
- className: "bg-white px-6 py-12",
134
+ className: "pointer-events-auto bg-white px-6 py-12",
138
135
  children: (product.variants?.length ?? 0) > 1 && /* @__PURE__ */ jsx("div", {
139
136
  className: "flex flex-col gap-y-6",
140
137
  children: (product.options || []).map((option) => {
@@ -1 +1 @@
1
- {"version":3,"file":"mobile-actions.js","names":["MobileActions: React.FC<MobileActionsProps>","Fragment","OptionSelect"],"sources":["../../../src/components/product-actions/mobile-actions.tsx"],"sourcesContent":["import React, { Fragment, useMemo } from 'react';\n\nimport { isEqual } from 'lodash';\n\nimport useToggleState from '@gfed-medusa/sf-lib-common/lib/hooks/use-toggle-state';\nimport { getProductPrice } from '@gfed-medusa/sf-lib-common/lib/utils/get-product-price';\nimport { ChevronDown } from '@gfed-medusa/sf-lib-ui/icons/chevron-down';\nimport { X } from '@gfed-medusa/sf-lib-ui/icons/x';\nimport { Dialog, Transition } from '@headlessui/react';\nimport { Button, clx } from '@medusajs/ui';\n\nimport { isSimpleProduct } from '@/lib/utils/product';\nimport { ProductActionsProduct } from '@/types';\nimport { ProductVariant } from '@/types/graphql';\n\nimport OptionSelect from './option-select';\n\ntype MobileActionsProps = {\n product: ProductActionsProduct;\n variant?: ProductVariant;\n options: Record<string, string | undefined>;\n updateOptions: (title: string, value: string) => void;\n stockStatus?: 'unknown' | 'in_stock' | 'out_of_stock';\n handleAddToCart: () => void;\n isAdding?: boolean;\n show: boolean;\n optionsDisabled: boolean;\n};\n\nconst optionsAsKeymap = (\n variantOptions: ProductVariant['options'] | null | undefined\n) => {\n return variantOptions?.reduce<Record<string, string>>((acc, varopt) => {\n if (!varopt) {\n return acc;\n }\n\n acc[varopt.optionId] = varopt.value;\n\n return acc;\n }, {});\n};\n\nconst MobileActions: React.FC<MobileActionsProps> = ({\n product,\n variant,\n options,\n updateOptions,\n stockStatus,\n handleAddToCart,\n isAdding,\n show,\n optionsDisabled,\n}) => {\n const { state, open, close } = useToggleState();\n\n const price = getProductPrice({\n product,\n variantId: variant?.id,\n });\n\n const selectedPrice = useMemo(() => {\n if (!price) {\n return null;\n }\n const { variantPrice, cheapestPrice } = price;\n\n return variantPrice || cheapestPrice || null;\n }, [price]);\n\n const isSimple = isSimpleProduct(product);\n\n const handleUpdateOption = (optionId: string, value: string) => {\n updateOptions(optionId, value);\n\n const nextOptions = {\n ...options,\n [optionId]: value,\n };\n\n const hasMatchingVariant = (product.variants ?? []).some((productVariant) =>\n isEqual(optionsAsKeymap(productVariant.options), nextOptions)\n );\n\n if (hasMatchingVariant) {\n close();\n }\n };\n\n return (\n <>\n <div\n className={clx('fixed inset-x-0 bottom-0 z-40 lg:hidden', {\n 'pointer-events-none': !show,\n })}\n >\n <Transition\n as={Fragment}\n show={show}\n enter=\"ease-in-out duration-300\"\n enterFrom=\"opacity-0\"\n enterTo=\"opacity-100\"\n leave=\"ease-in duration-300\"\n leaveFrom=\"opacity-100\"\n leaveTo=\"opacity-0\"\n >\n <div\n className=\"text-large-regular flex h-full w-full flex-col items-center justify-center gap-y-3 border-t border-gray-200 bg-white p-4\"\n data-testid=\"mobile-actions\"\n >\n <div className=\"flex items-center gap-x-2\">\n <span data-testid=\"mobile-title\">{product.title}</span>\n <span>—</span>\n {selectedPrice ? (\n <div className=\"text-ui-fg-base flex items-end gap-x-2\">\n {selectedPrice.price_type === 'sale' && (\n <p>\n <span className=\"text-small-regular line-through\">\n {selectedPrice.original_price}\n </span>\n </p>\n )}\n <span\n className={clx({\n 'text-ui-fg-interactive':\n selectedPrice.price_type === 'sale',\n })}\n >\n {selectedPrice.calculated_price}\n </span>\n </div>\n ) : (\n <div className=\"h-5 w-24 animate-pulse bg-gray-100\" />\n )}\n </div>\n <div\n className={clx('grid w-full grid-cols-2 gap-x-4', {\n '!grid-cols-1': isSimple,\n })}\n >\n {!isSimple && (\n <Button\n onClick={open}\n variant=\"secondary\"\n className=\"w-full\"\n data-testid=\"mobile-actions-button\"\n >\n <div className=\"flex w-full items-center justify-between\">\n <span>\n {variant\n ? Object.values(options).join(' / ')\n : 'Select Options'}\n </span>\n <ChevronDown />\n </div>\n </Button>\n )}\n <Button\n onClick={handleAddToCart}\n disabled={!variant || stockStatus === 'out_of_stock'}\n className=\"w-full\"\n isLoading={isAdding}\n data-testid=\"mobile-cart-button\"\n >\n {!variant\n ? 'Select size'\n : stockStatus === 'out_of_stock'\n ? 'Out of stock'\n : 'Add to cart'}\n </Button>\n </div>\n </div>\n </Transition>\n </div>\n <Transition appear show={state} as={Fragment}>\n <Dialog as=\"div\" className=\"relative z-[100]\" onClose={close}>\n <Transition.Child\n as={Fragment}\n enter=\"ease-out duration-300\"\n enterFrom=\"opacity-0\"\n enterTo=\"opacity-100\"\n leave=\"ease-in duration-200\"\n leaveFrom=\"opacity-100\"\n leaveTo=\"opacity-0\"\n >\n <div className=\"fixed inset-0 bg-gray-700 bg-opacity-75 backdrop-blur-sm\" />\n </Transition.Child>\n\n <div className=\"fixed inset-x-0 bottom-0\">\n <div className=\"flex h-full min-h-full items-center justify-center text-center\">\n <Transition.Child\n as={Fragment}\n enter=\"ease-out duration-300\"\n enterFrom=\"opacity-0\"\n enterTo=\"opacity-100\"\n leave=\"ease-in duration-200\"\n leaveFrom=\"opacity-100\"\n leaveTo=\"opacity-0\"\n >\n <Dialog.Panel\n className=\"flex h-full w-full transform flex-col gap-y-3 overflow-hidden text-left\"\n data-testid=\"mobile-actions-modal\"\n >\n <div className=\"flex w-full justify-end pr-6\">\n <button\n onClick={close}\n className=\"text-ui-fg-base flex h-12 w-12 items-center justify-center rounded-full bg-white\"\n data-testid=\"close-modal-button\"\n >\n <X />\n </button>\n </div>\n <div className=\"bg-white px-6 py-12\">\n {(product.variants?.length ?? 0) > 1 && (\n <div className=\"flex flex-col gap-y-6\">\n {(product.options || []).map((option) => {\n return (\n <div key={option.id}>\n <OptionSelect\n option={option}\n current={options[option.id]}\n updateOption={handleUpdateOption}\n title={option.title ?? ''}\n disabled={optionsDisabled}\n />\n </div>\n );\n })}\n </div>\n )}\n </div>\n </Dialog.Panel>\n </Transition.Child>\n </div>\n </div>\n </Dialog>\n </Transition>\n </>\n );\n};\n\nexport default MobileActions;\n"],"mappings":"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"}
1
+ {"version":3,"file":"mobile-actions.js","names":["MobileActions: React.FC<MobileActionsProps>","Fragment","OptionSelect"],"sources":["../../../src/components/product-actions/mobile-actions.tsx"],"sourcesContent":["import React, { Fragment, useMemo } from 'react';\n\nimport { isEqual } from 'lodash';\n\nimport useToggleState from '@gfed-medusa/sf-lib-common/lib/hooks/use-toggle-state';\nimport { getProductPrice } from '@gfed-medusa/sf-lib-common/lib/utils/get-product-price';\nimport { ChevronDown } from '@gfed-medusa/sf-lib-ui/icons/chevron-down';\nimport { X } from '@gfed-medusa/sf-lib-ui/icons/x';\nimport { Dialog, Transition } from '@headlessui/react';\nimport { Button, clx } from '@medusajs/ui';\n\nimport { isSimpleProduct } from '@/lib/utils/product';\nimport { ProductActionsProduct } from '@/types';\nimport { ProductVariant } from '@/types/graphql';\n\nimport OptionSelect from './option-select';\n\ntype MobileActionsProps = {\n product: ProductActionsProduct;\n variant?: ProductVariant;\n options: Record<string, string | undefined>;\n updateOptions: (title: string, value: string) => void;\n stockStatus?: 'unknown' | 'in_stock' | 'out_of_stock';\n handleAddToCart: () => void;\n isAdding?: boolean;\n show: boolean;\n optionsDisabled: boolean;\n};\n\nconst optionsAsKeymap = (\n variantOptions: ProductVariant['options'] | null | undefined\n) => {\n return variantOptions?.reduce<Record<string, string>>((acc, varopt) => {\n if (!varopt) {\n return acc;\n }\n\n acc[varopt.optionId] = varopt.value;\n\n return acc;\n }, {});\n};\n\nconst MobileActions: React.FC<MobileActionsProps> = ({\n product,\n variant,\n options,\n updateOptions,\n stockStatus,\n handleAddToCart,\n isAdding,\n show,\n optionsDisabled,\n}) => {\n const { state, open, close } = useToggleState();\n\n const price = getProductPrice({\n product,\n variantId: variant?.id,\n });\n\n const selectedPrice = useMemo(() => {\n if (!price) {\n return null;\n }\n const { variantPrice, cheapestPrice } = price;\n\n return (variant ? variantPrice : cheapestPrice) || null;\n }, [price, variant]);\n\n const isSimple = isSimpleProduct(product);\n const handleUpdateOption = (optionId: string, value: string) => {\n updateOptions(optionId, value);\n\n const nextOptions = {\n ...options,\n [optionId]: value,\n };\n\n const hasMatchingVariant = (product.variants ?? []).some((productVariant) =>\n isEqual(optionsAsKeymap(productVariant.options), nextOptions)\n );\n\n if (hasMatchingVariant) {\n close();\n }\n };\n\n return (\n <>\n <div\n className={clx('fixed inset-x-0 bottom-0 z-40 lg:hidden', {\n 'pointer-events-none': !show,\n })}\n >\n <Transition\n as={Fragment}\n show={show}\n enter=\"ease-in-out duration-300\"\n enterFrom=\"opacity-0\"\n enterTo=\"opacity-100\"\n leave=\"ease-in duration-300\"\n leaveFrom=\"opacity-100\"\n leaveTo=\"opacity-0\"\n >\n <div\n className=\"text-large-regular flex h-full w-full flex-col items-center justify-center gap-y-3 border-t border-gray-200 bg-white p-4\"\n data-testid=\"mobile-actions\"\n >\n <div className=\"flex w-full items-start justify-between gap-x-4\">\n <span className=\"flex-1 text-left\" data-testid=\"mobile-title\">\n {product.title}\n </span>\n {selectedPrice ? (\n <div className=\"text-ui-fg-base flex shrink-0 items-start gap-x-2 self-start\">\n {selectedPrice.price_type === 'sale' && (\n <p>\n <span className=\"text-small-regular line-through\">\n {selectedPrice.original_price}\n </span>\n </p>\n )}\n <span\n className={clx({\n 'text-ui-fg-interactive':\n selectedPrice.price_type === 'sale',\n })}\n >\n {!variant && 'From '}\n {selectedPrice.calculated_price}\n </span>\n </div>\n ) : (\n <div className=\"h-5 w-24 shrink-0 self-start animate-pulse bg-gray-100\" />\n )}\n </div>\n <div\n className={clx('grid w-full grid-cols-2 gap-x-4', {\n '!grid-cols-1': isSimple,\n })}\n >\n {!isSimple && (\n <Button\n onClick={open}\n variant=\"secondary\"\n className=\"w-full\"\n data-testid=\"mobile-actions-button\"\n >\n <div className=\"flex w-full items-center justify-between\">\n <span>\n {variant\n ? Object.values(options).join(' / ')\n : 'Select Size'}\n </span>\n <ChevronDown />\n </div>\n </Button>\n )}\n <Button\n onClick={handleAddToCart}\n disabled={!variant || stockStatus === 'out_of_stock'}\n className=\"w-full\"\n isLoading={isAdding}\n data-testid=\"mobile-cart-button\"\n >\n {stockStatus === 'out_of_stock'\n ? 'Out of stock'\n : 'Add to cart'}\n </Button>\n </div>\n </div>\n </Transition>\n </div>\n <Transition appear show={state} as={Fragment}>\n <Dialog as=\"div\" className=\"relative z-[100]\" onClose={close}>\n <Transition.Child\n as={Fragment}\n enter=\"ease-out duration-300\"\n enterFrom=\"opacity-0\"\n enterTo=\"opacity-100\"\n leave=\"ease-in duration-200\"\n leaveFrom=\"opacity-100\"\n leaveTo=\"opacity-0\"\n >\n <div className=\"fixed inset-0 h-screen bg-black/20 backdrop-blur-sm\" />\n </Transition.Child>\n\n <div className=\"fixed inset-x-0 bottom-0\">\n <div className=\"flex h-full min-h-full items-center justify-center text-center\">\n <Transition.Child\n as={Fragment}\n enter=\"ease-out duration-300\"\n enterFrom=\"opacity-0\"\n enterTo=\"opacity-100\"\n leave=\"ease-in duration-200\"\n leaveFrom=\"opacity-100\"\n leaveTo=\"opacity-0\"\n >\n <Dialog.Panel\n className=\"pointer-events-none flex w-full transform flex-col gap-y-3 text-left\"\n data-testid=\"mobile-actions-modal\"\n >\n <div className=\"flex w-full justify-end pr-6\">\n <button\n onClick={close}\n className=\"text-ui-fg-base pointer-events-auto flex h-12 w-12 items-center justify-center rounded-full bg-white\"\n data-testid=\"close-modal-button\"\n >\n <X />\n </button>\n </div>\n <div className=\"pointer-events-auto bg-white px-6 py-12\">\n {(product.variants?.length ?? 0) > 1 && (\n <div className=\"flex flex-col gap-y-6\">\n {(product.options || []).map((option) => {\n return (\n <div key={option.id}>\n <OptionSelect\n option={option}\n current={options[option.id]}\n updateOption={handleUpdateOption}\n title={option.title ?? ''}\n disabled={optionsDisabled}\n />\n </div>\n );\n })}\n </div>\n )}\n </div>\n </Dialog.Panel>\n </Transition.Child>\n </div>\n </div>\n </Dialog>\n </Transition>\n </>\n );\n};\n\nexport default MobileActions;\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import * as react_jsx_runtime3 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime14 from "react/jsx-runtime";
2
2
 
3
3
  //#region src/components/product-onboarding-cta/index.d.ts
4
- declare function ProductOnboardingCta(): Promise<react_jsx_runtime3.JSX.Element | null>;
4
+ declare function ProductOnboardingCta(): Promise<react_jsx_runtime14.JSX.Element | null>;
5
5
  //#endregion
6
6
  export { ProductOnboardingCta as default };
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/product-onboarding-cta/index.tsx"],"sourcesContent":[],"mappings":";;;iBAIe,oBAAA,CAAA,GAAoB,QAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/product-onboarding-cta/index.tsx"],"sourcesContent":[],"mappings":";;;iBAIe,oBAAA,CAAA,GAAoB,QAAA,mBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1,6 +1,6 @@
1
1
  import { ProductVariant } from "../../types/graphql.js";
2
2
  import { ProductActionsProduct } from "../../types/index.js";
3
- import * as react_jsx_runtime4 from "react/jsx-runtime";
3
+ import * as react_jsx_runtime15 from "react/jsx-runtime";
4
4
 
5
5
  //#region src/components/product-price/index.d.ts
6
6
  declare function ProductPrice({
@@ -9,7 +9,7 @@ declare function ProductPrice({
9
9
  }: {
10
10
  product: ProductActionsProduct;
11
11
  variant?: ProductVariant;
12
- }): react_jsx_runtime4.JSX.Element;
12
+ }): react_jsx_runtime15.JSX.Element;
13
13
  //#endregion
14
14
  export { ProductPrice as default };
15
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/product-price/index.tsx"],"sourcesContent":[],"mappings":";;;;;iBAOwB,YAAA;;;AAFyB;WAMtC;YACC;AAPqC,CAAA,CAAA,EAQhD,kBAAA,CAAA,GAAA,CAAA,OANmC"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/product-price/index.tsx"],"sourcesContent":[],"mappings":";;;;;iBAOwB,YAAA;;;AAFyB;WAMtC;YACC;AAPqC,CAAA,CAAA,EAQhD,mBAAA,CAAA,GAAA,CAAA,OANmC"}
@@ -1,5 +1,5 @@
1
1
  import { Product } from "../../types/graphql.js";
2
- import * as react_jsx_runtime2 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/product-tabs/index.d.ts
5
5
  type ProductTabsProps = {
@@ -7,7 +7,7 @@ type ProductTabsProps = {
7
7
  };
8
8
  declare const ProductTabs: ({
9
9
  product
10
- }: ProductTabsProps) => react_jsx_runtime2.JSX.Element;
10
+ }: ProductTabsProps) => react_jsx_runtime0.JSX.Element;
11
11
  //#endregion
12
12
  export { ProductTabs as default };
13
13
  //# sourceMappingURL=index.d.ts.map
@@ -1,16 +1,18 @@
1
1
  import { SortOptions } from "./sort-products/index.js";
2
- import * as react_jsx_runtime5 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/components/refinement-list/index.d.ts
5
5
  type RefinementListProps = {
6
6
  sortBy: SortOptions;
7
7
  search?: boolean;
8
8
  'data-testid'?: string;
9
+ className?: string;
9
10
  };
10
11
  declare const RefinementList: ({
11
12
  sortBy,
12
- "data-testid": dataTestId
13
- }: RefinementListProps) => react_jsx_runtime5.JSX.Element;
13
+ "data-testid": dataTestId,
14
+ className
15
+ }: RefinementListProps) => react_jsx_runtime0.JSX.Element;
14
16
  //#endregion
15
17
  export { RefinementList as default };
16
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/refinement-list/index.tsx"],"sourcesContent":[],"mappings":";;;;KAQK,mBAAA;UACK;;EADL,aAAA,CAAA,EAAA,MAAmB;AACH,CAAA;cAKf,cAAkB,EAAA,CAAA;EAAA,MAAA;EAAA,aAAA,EAAA;AAAA,CAAA,EAGrB,mBAHqB,EAAA,GAGF,kBAAA,CAAA,GAAA,CAAA,OAHE"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/refinement-list/index.tsx"],"sourcesContent":[],"mappings":";;;;KAUK,mBAAA;UACK;;EADL,aAAA,CAAA,EAAA,MAAmB;EAOlB,SAAA,CAAA,EAAA,MA8CL;CA9CuB;cAAlB,cAAkB,EAAA,CAAA;EAAA,MAAA;EAAA,aAAA,EAAA,UAAA;EAAA;AAAA,CAAA,EAIrB,mBAJqB,EAAA,GAIF,kBAAA,CAAA,GAAA,CAAA,OAJE"}
@@ -1,31 +1,44 @@
1
1
  'use client';
2
2
 
3
3
  import sort_products_default from "./sort-products/index.js";
4
- import { jsx } from "react/jsx-runtime";
4
+ import { clx } from "@medusajs/ui";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
5
6
  import { usePathname, useRouter, useSearchParams } from "next/navigation";
6
7
  import { useCallback } from "react";
7
8
 
8
9
  //#region src/components/refinement-list/index.tsx
9
- const RefinementList = ({ sortBy, "data-testid": dataTestId }) => {
10
+ const RefinementList = ({ sortBy, "data-testid": dataTestId, className }) => {
10
11
  const router = useRouter();
11
12
  const pathname = usePathname();
12
13
  const searchParams = useSearchParams();
13
14
  const createQueryString = useCallback((name, value) => {
14
15
  const params = new URLSearchParams(searchParams);
15
16
  params.set(name, value);
17
+ if (name === "sortBy") params.delete("page");
16
18
  return params.toString();
17
19
  }, [searchParams]);
18
20
  const setQueryParams = (name, value) => {
19
21
  const query = createQueryString(name, value);
20
22
  router.push(`${pathname}?${query}`);
21
23
  };
22
- return /* @__PURE__ */ jsx("div", {
23
- className: "small:ml-[1.675rem] small:min-w-[250px] small:flex-col small:px-0 mb-8 flex gap-12 py-4 pl-6",
24
- children: /* @__PURE__ */ jsx(sort_products_default, {
25
- sortBy,
26
- setQueryParams,
27
- "data-testid": dataTestId
28
- })
24
+ return /* @__PURE__ */ jsxs("div", {
25
+ className: clx("w-full", className),
26
+ children: [/* @__PURE__ */ jsx("div", {
27
+ className: "small:hidden",
28
+ children: /* @__PURE__ */ jsx(sort_products_default, {
29
+ sortBy,
30
+ setQueryParams,
31
+ "data-testid": dataTestId,
32
+ variant: "dropdown"
33
+ })
34
+ }), /* @__PURE__ */ jsx("div", {
35
+ className: "small:ml-[1.675rem] small:min-w-[250px] small:flex-col small:px-0 small:py-4 small:pr-6 small:block hidden",
36
+ children: /* @__PURE__ */ jsx(sort_products_default, {
37
+ sortBy,
38
+ setQueryParams,
39
+ "data-testid": dataTestId
40
+ })
41
+ })]
29
42
  });
30
43
  };
31
44
  var refinement_list_default = RefinementList;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["SortProducts"],"sources":["../../../src/components/refinement-list/index.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback } from 'react';\n\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation';\n\nimport SortProducts, { SortOptions } from './sort-products';\n\ntype RefinementListProps = {\n sortBy: SortOptions;\n search?: boolean;\n 'data-testid'?: string;\n};\n\nconst RefinementList = ({\n sortBy,\n 'data-testid': dataTestId,\n}: RefinementListProps) => {\n const router = useRouter();\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const createQueryString = useCallback(\n (name: string, value: string) => {\n const params = new URLSearchParams(searchParams);\n params.set(name, value);\n\n return params.toString();\n },\n [searchParams]\n );\n\n const setQueryParams = (name: string, value: string) => {\n const query = createQueryString(name, value);\n router.push(`${pathname}?${query}`);\n };\n\n return (\n <div className=\"small:ml-[1.675rem] small:min-w-[250px] small:flex-col small:px-0 mb-8 flex gap-12 py-4 pl-6\">\n <SortProducts\n sortBy={sortBy}\n setQueryParams={setQueryParams}\n data-testid={dataTestId}\n />\n </div>\n );\n};\n\nexport default RefinementList;\n"],"mappings":";;;;;;;;AAcA,MAAM,kBAAkB,EACtB,QACA,eAAe,iBACU;CACzB,MAAM,SAAS,WAAW;CAC1B,MAAM,WAAW,aAAa;CAC9B,MAAM,eAAe,iBAAiB;CAEtC,MAAM,oBAAoB,aACvB,MAAc,UAAkB;EAC/B,MAAM,SAAS,IAAI,gBAAgB,aAAa;AAChD,SAAO,IAAI,MAAM,MAAM;AAEvB,SAAO,OAAO,UAAU;IAE1B,CAAC,aAAa,CACf;CAED,MAAM,kBAAkB,MAAc,UAAkB;EACtD,MAAM,QAAQ,kBAAkB,MAAM,MAAM;AAC5C,SAAO,KAAK,GAAG,SAAS,GAAG,QAAQ;;AAGrC,QACE,oBAAC;EAAI,WAAU;YACb,oBAACA;GACS;GACQ;GAChB,eAAa;IACb;GACE;;AAIV,8BAAe"}
1
+ {"version":3,"file":"index.js","names":["SortProducts"],"sources":["../../../src/components/refinement-list/index.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback } from 'react';\n\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation';\n\nimport { clx } from '@medusajs/ui';\n\nimport SortProducts, { SortOptions } from './sort-products';\n\ntype RefinementListProps = {\n sortBy: SortOptions;\n search?: boolean;\n 'data-testid'?: string;\n className?: string;\n};\n\nconst RefinementList = ({\n sortBy,\n 'data-testid': dataTestId,\n className,\n}: RefinementListProps) => {\n const router = useRouter();\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const createQueryString = useCallback(\n (name: string, value: string) => {\n const params = new URLSearchParams(searchParams);\n params.set(name, value);\n if (name === 'sortBy') {\n params.delete('page');\n }\n\n return params.toString();\n },\n [searchParams]\n );\n\n const setQueryParams = (name: string, value: string) => {\n const query = createQueryString(name, value);\n router.push(`${pathname}?${query}`);\n };\n\n return (\n <div className={clx('w-full', className)}>\n <div className=\"small:hidden\">\n <SortProducts\n sortBy={sortBy}\n setQueryParams={setQueryParams}\n data-testid={dataTestId}\n variant=\"dropdown\"\n />\n </div>\n <div className=\"small:ml-[1.675rem] small:min-w-[250px] small:flex-col small:px-0 small:py-4 small:pr-6 small:block hidden\">\n <SortProducts\n sortBy={sortBy}\n setQueryParams={setQueryParams}\n data-testid={dataTestId}\n />\n </div>\n </div>\n );\n};\n\nexport default RefinementList;\n"],"mappings":";;;;;;;;;AAiBA,MAAM,kBAAkB,EACtB,QACA,eAAe,YACf,gBACyB;CACzB,MAAM,SAAS,WAAW;CAC1B,MAAM,WAAW,aAAa;CAC9B,MAAM,eAAe,iBAAiB;CAEtC,MAAM,oBAAoB,aACvB,MAAc,UAAkB;EAC/B,MAAM,SAAS,IAAI,gBAAgB,aAAa;AAChD,SAAO,IAAI,MAAM,MAAM;AACvB,MAAI,SAAS,SACX,QAAO,OAAO,OAAO;AAGvB,SAAO,OAAO,UAAU;IAE1B,CAAC,aAAa,CACf;CAED,MAAM,kBAAkB,MAAc,UAAkB;EACtD,MAAM,QAAQ,kBAAkB,MAAM,MAAM;AAC5C,SAAO,KAAK,GAAG,SAAS,GAAG,QAAQ;;AAGrC,QACE,qBAAC;EAAI,WAAW,IAAI,UAAU,UAAU;aACtC,oBAAC;GAAI,WAAU;aACb,oBAACA;IACS;IACQ;IAChB,eAAa;IACb,SAAQ;KACR;IACE,EACN,oBAAC;GAAI,WAAU;aACb,oBAACA;IACS;IACQ;IAChB,eAAa;KACb;IACE;GACF;;AAIV,8BAAe"}