@gem-sdk/components 2.1.19 → 2.1.21

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 (44) hide show
  1. package/dist/cjs/article/components/ArticleList.js +1 -1
  2. package/dist/cjs/banner/components/hero-banner/index.liquid.js +9 -7
  3. package/dist/cjs/banner/components/hero-banner/utils/index.js +5 -3
  4. package/dist/cjs/form/components/textarea/TextArea.liquid.js +2 -2
  5. package/dist/cjs/image/components/Image.js +0 -1
  6. package/dist/cjs/image/components/Image.liquid.js +0 -1
  7. package/dist/cjs/marquee/components/MarqueeBase.liquid.js +7 -26
  8. package/dist/cjs/post-purchase/product/components/ProductDiscountTag.js +5 -2
  9. package/dist/cjs/post-purchase/product/components/ProductOffer.js +16 -3
  10. package/dist/cjs/post-purchase/product/components/ProductPrice.js +3 -1
  11. package/dist/cjs/post-purchase/product/components/ProductPriceBreakdown.js +9 -21
  12. package/dist/cjs/post-purchase/product/constants/ProductOfferPlaceholder.js +127 -0
  13. package/dist/cjs/post-purchase/product/hooks/useDynamicProduct.js +28 -0
  14. package/dist/cjs/post-purchase/product/settings/ProductOffer.js +26 -0
  15. package/dist/cjs/product/components/ProductImagesV2/jsx/components/ProductFeaturedImageCarousel.js +12 -4
  16. package/dist/cjs/product/setting/ProductButton.js +1 -1
  17. package/dist/cjs/sticky/setting/preset-config.js +2 -2
  18. package/dist/cjs/third-party/components/NotifyBackInStockPreOrder.js +1 -1
  19. package/dist/cjs/third-party/components/ShopifySubscriptions.liquid.js +3 -2
  20. package/dist/cjs/third-party/setting/NotifyBackInStockPreOrder.js +2 -2
  21. package/dist/cjs/third-party/setting/ShopifySubscriptions.js +22 -0
  22. package/dist/esm/article/components/ArticleList.js +1 -1
  23. package/dist/esm/banner/components/hero-banner/index.liquid.js +9 -7
  24. package/dist/esm/banner/components/hero-banner/utils/index.js +5 -3
  25. package/dist/esm/form/components/textarea/TextArea.liquid.js +2 -2
  26. package/dist/esm/image/components/Image.js +0 -1
  27. package/dist/esm/image/components/Image.liquid.js +0 -1
  28. package/dist/esm/marquee/components/MarqueeBase.liquid.js +7 -26
  29. package/dist/esm/post-purchase/product/components/ProductDiscountTag.js +5 -2
  30. package/dist/esm/post-purchase/product/components/ProductOffer.js +16 -3
  31. package/dist/esm/post-purchase/product/components/ProductPrice.js +3 -1
  32. package/dist/esm/post-purchase/product/components/ProductPriceBreakdown.js +9 -21
  33. package/dist/esm/post-purchase/product/constants/ProductOfferPlaceholder.js +125 -0
  34. package/dist/esm/post-purchase/product/hooks/useDynamicProduct.js +26 -0
  35. package/dist/esm/post-purchase/product/settings/ProductOffer.js +26 -0
  36. package/dist/esm/product/components/ProductImagesV2/jsx/components/ProductFeaturedImageCarousel.js +13 -5
  37. package/dist/esm/product/setting/ProductButton.js +1 -1
  38. package/dist/esm/sticky/setting/preset-config.js +2 -2
  39. package/dist/esm/third-party/components/NotifyBackInStockPreOrder.js +1 -1
  40. package/dist/esm/third-party/components/ShopifySubscriptions.liquid.js +3 -2
  41. package/dist/esm/third-party/setting/NotifyBackInStockPreOrder.js +2 -2
  42. package/dist/esm/third-party/setting/ShopifySubscriptions.js +22 -0
  43. package/dist/types/index.d.ts +4 -0
  44. package/package.json +2 -2
@@ -42,6 +42,11 @@ const config = {
42
42
  {
43
43
  id: 'setting',
44
44
  controls: [
45
+ {
46
+ id: 'appBlockId',
47
+ type: 'input',
48
+ default: ''
49
+ },
45
50
  {
46
51
  id: 'install',
47
52
  type: 'open-link',
@@ -58,6 +63,23 @@ const config = {
58
63
  href: 'https://admin.shopify.com/?redirect=/apps/subscriptions-remix',
59
64
  appName: ShopifySubscriptions.AppConfig.label
60
65
  },
66
+ {
67
+ id: 'widgetType',
68
+ label: 'Choose widget',
69
+ type: 'select',
70
+ default: 'app-block',
71
+ options: [
72
+ {
73
+ label: 'app block',
74
+ value: 'app-block'
75
+ }
76
+ ]
77
+ },
78
+ {
79
+ id: 'productHandle',
80
+ type: 'product-handle',
81
+ hide: true
82
+ },
61
83
  {
62
84
  id: 'align',
63
85
  label: 'Alignment',
@@ -10,7 +10,7 @@ const ArticleList = ({ styles, setting, className, children, builderProps })=>{
10
10
  const { articleSetting, numberOfArticle } = setting ?? {};
11
11
  const { articleIds, articlePickType } = articleSetting ?? {};
12
12
  const articlesQuery = {
13
- first: 10,
13
+ first: articleIds?.length ?? 50,
14
14
  where: {
15
15
  baseIDIn: [
16
16
  ...articleSetting?.articleIds ?? []
@@ -130,6 +130,7 @@ const HeroBanner = ({ builderAttrs, builderProps, setting, styles, style, childr
130
130
  tablet: createBlurDataURL(srcSet?.tablet?.width ?? srcSet?.desktop?.width ?? 0, srcSet?.tablet?.height ?? srcSet?.desktop?.width ?? 0),
131
131
  mobile: createBlurDataURL(srcSet?.mobile?.width ?? srcSet?.tablet?.width ?? srcSet?.desktop?.width ?? 0, srcSet?.mobile?.height ?? srcSet?.tablet?.height ?? srcSet?.desktop?.width ?? 0)
132
132
  };
133
+ const enableLazyLoad = !setting?.preload && enableLazyloadImage;
133
134
  const renderInnerHeroBanner = ()=>{
134
135
  return template /* liquid */ `
135
136
  <div
@@ -193,9 +194,10 @@ const HeroBanner = ({ builderAttrs, builderProps, setting, styles, style, childr
193
194
  'clip-path': getClipPath(borderBg?.width, cornerBg)
194
195
  }}"
195
196
  >
196
- <div class="${cls('hero-banner-bg-parallax gp-hero-banner-image-background gp_lazybg', {
197
+ <div class="${cls('hero-banner-bg-parallax gp-hero-banner-image-background', {
197
198
  'gp-duration-[var(--duration)] group-hover/hero:gp-scale-[var(--scale)]': hoverEffect,
198
- 'gp-transition-transform': hoverEffect
199
+ 'gp-transition-transform': hoverEffect,
200
+ gp_lazybg: enableLazyLoad
199
201
  })}"
200
202
  style="${{
201
203
  ...getStyleBackgroundByDevice(background, {
@@ -204,9 +206,9 @@ const HeroBanner = ({ builderAttrs, builderProps, setting, styles, style, childr
204
206
  liquid: true
205
207
  }),
206
208
  ...makeStyleResponsive('bgi', {
207
- desktop: `url('${bgiEnableByDevice['desktop'] ? setting?.preload || !enableLazyloadImage ? getImageSrc(getResponsiveValueByScreen(srcSet, 'desktop'), 'desktop') : imagePlaceholder['desktop'] : ''}')`,
208
- tablet: `url('${bgiEnableByDevice['tablet'] ? setting?.preload || !enableLazyloadImage ? getImageSrc(getResponsiveValueByScreen(srcSet, 'tablet'), 'tablet') : imagePlaceholder['tablet'] : ''}')`,
209
- mobile: `url('${bgiEnableByDevice['mobile'] ? setting?.preload || !enableLazyloadImage ? getImageSrc(getResponsiveValueByScreen(srcSet, 'mobile'), 'mobile') : imagePlaceholder['mobile'] : ''}')`
209
+ desktop: `url('${bgiEnableByDevice['desktop'] ? !enableLazyLoad ? getImageSrc(getResponsiveValueByScreen(srcSet, 'desktop'), 'desktop') : imagePlaceholder['desktop'] : ''}')`,
210
+ tablet: `url('${bgiEnableByDevice['tablet'] ? !enableLazyLoad ? getImageSrc(getResponsiveValueByScreen(srcSet, 'tablet'), 'tablet') : imagePlaceholder['tablet'] : ''}')`,
211
+ mobile: `url('${bgiEnableByDevice['mobile'] ? !enableLazyLoad ? getImageSrc(getResponsiveValueByScreen(srcSet, 'mobile'), 'mobile') : imagePlaceholder['mobile'] : ''}')`
210
212
  }),
211
213
  '--duration': `${hoverEffectDuration ?? 0}s`,
212
214
  '--scale': hoverEffectScale ?? 1,
@@ -214,6 +216,7 @@ const HeroBanner = ({ builderAttrs, builderProps, setting, styles, style, childr
214
216
  ...getStyleHeroBannerBg(backgroundResponsive || {}, enableParallax)
215
217
  }}"
216
218
  >
219
+ ${embed()}
217
220
  ${!setting?.preload ? DEVICES.map((device)=>{
218
221
  return RenderIf(getEnableBgImageByDevice(device), NextImage({
219
222
  src: getImageSrc(getResponsiveValueByScreen(srcSet, device), device),
@@ -223,8 +226,7 @@ const HeroBanner = ({ builderAttrs, builderProps, setting, styles, style, childr
223
226
  enableLazyloadImage
224
227
  }));
225
228
  }).join('') : ''}
226
- </div>
227
- ${embed()} </div>
229
+ </div></div>
228
230
  </div>
229
231
  ${RenderIf(overlayEnable, template`<div
230
232
  aria-label="Overlay"
@@ -25,13 +25,14 @@ const getHeightHeroBanner = (background, enableParallax)=>{
25
25
  'tablet'
26
26
  ];
27
27
  DEVICES.forEach((device)=>{
28
+ const enableParallaxDevice = background?.[device]?.type === 'image' ? enableParallax : false;
28
29
  const isScale = isScaleImage({
29
- enableParallax,
30
+ enableParallax: enableParallaxDevice,
30
31
  attachment: background[device]?.attachment
31
32
  });
32
33
  result = {
33
34
  ...result,
34
- [device]: enableParallax ? '150%' : isScale ? '100vh' : '100%'
35
+ [device]: enableParallaxDevice ? '150%' : isScale ? '100vh' : '100%'
35
36
  };
36
37
  });
37
38
  return makeStyleResponsive('h', result);
@@ -44,8 +45,9 @@ const getWidthHeroBanner = (background, enableParallax)=>{
44
45
  'tablet'
45
46
  ];
46
47
  DEVICES.forEach((device)=>{
48
+ const enableParallaxDevice = background?.[device]?.type === 'image' ? enableParallax : false;
47
49
  const isScale = isScaleImage({
48
- enableParallax,
50
+ enableParallax: enableParallaxDevice,
49
51
  attachment: background[device]?.attachment
50
52
  });
51
53
  result = {
@@ -2,10 +2,10 @@ import { makeStyleResponsive, makeWidth, composeAdvanceStyle, composeTypographyC
2
2
  import { getDynamicSourceLocales } from '../../../helpers.js';
3
3
 
4
4
  const FormTextarea = ({ setting, builderProps, className, builderAttrs, advanced, pageContext })=>{
5
- const { text, name, placeholder, required, width, fullWidth, typography } = setting ?? {};
5
+ const { text, name, placeholder, required, width, fullWidth, typography, translate } = setting ?? {};
6
6
  const textAreaWidth = makeStyleResponsive('w', makeWidth(width, fullWidth));
7
7
  const defaultName = name === '' || name === undefined ? 'contact[note]' : name;
8
- const { border, rounded, hasBoxShadow, boxShadow, pos, d, op, right, top, left, bottom, z, margin, padding, translate } = advanced ?? {};
8
+ const { border, rounded, hasBoxShadow, boxShadow, pos, d, op, right, top, left, bottom, z, margin, padding } = advanced ?? {};
9
9
  const spacingSetting = advanced?.['spacing-setting'];
10
10
  const inputStyle = composeAdvanceStyle({
11
11
  border,
@@ -76,7 +76,6 @@ const Image = ({ styles, className, setting, builderAttrs, builderProps, style,
76
76
  style: {
77
77
  ...getStyleShadowState(styles?.boxShadowImg, 'box-shadow', styles?.hasBoxShadowImg),
78
78
  borderRadius: 'inherit',
79
- overflow: 'hidden',
80
79
  ...makeStyleResponsive('jc', styles?.align)
81
80
  },
82
81
  children: [
@@ -46,7 +46,6 @@ const Image = ({ styles, className, setting, builderAttrs, builderProps, style,
46
46
  style="${{
47
47
  ...getStyleShadowState(styles?.boxShadowImg, 'box-shadow', styles?.hasBoxShadowImg),
48
48
  'border-radius': 'inherit',
49
- overflow: 'hidden',
50
49
  ...makeStyleResponsive('jc', styles?.align)
51
50
  }}"
52
51
  >
@@ -42,7 +42,6 @@ const MarqueeBase = ({ style = {}, autoFill = false, play = true, pauseOnHover =
42
42
  };
43
43
  return template`
44
44
  <div
45
-
46
45
  style="${containerStyle()}"
47
46
  class="rfm-marquee-container"
48
47
  >
@@ -51,35 +50,17 @@ const MarqueeBase = ({ style = {}, autoFill = false, play = true, pauseOnHover =
51
50
  style="${marqueeStyle()}"
52
51
  >
53
52
  <div class="rfm-initial-child-container">
54
-
55
- ${template`
56
- <div style="${childStyle()}" class="${`rfm-child`}">
57
- ${children}
58
- </div>
59
- `}
60
- </div>
61
- <div class="rfm-child-placeholder">
62
- ${template`
63
- <div style="${childStyle()}" class="${`rfm-child`}">
64
- ${children}
65
- </div>
66
- `}
67
- </div>
68
- <div class="rfm-child-placeholder">
69
-
70
- ${template`
71
- <div style="${childStyle()}" class="${`rfm-child`}">
72
- ${children}
73
- </div>
74
- `}
53
+ ${template`
54
+ <div style="${childStyle()}" class="${`rfm-child`}">
55
+ ${children}
56
+ </div>
57
+ `}
75
58
  </div>
76
59
  </div>
77
- <div
60
+ <div
78
61
  class="rfm-marquee placeholder-marquee"
79
62
  style="${marqueeStyle()}"
80
- >
81
-
82
- </div>
63
+ ></div>
83
64
  </div>
84
65
  `;
85
66
  };
@@ -1,26 +1,29 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { useProduct, useProductOfferDiscount, cls } from '@gem-sdk/core';
3
3
  import Text from '../../text/Text.js';
4
+ import { useDynamicProduct } from '../hooks/useDynamicProduct.js';
4
5
 
5
6
  const PostPurchaseProductDiscountTag = ({ setting = {}, styles = {}, style, builderAttrs, builderProps, children })=>{
6
7
  const currentProduct = useProduct();
7
8
  const currentProductId = currentProduct?.baseID?.replace('gid://shopify/Product/', '');
8
9
  const currentOfferDiscount = useProductOfferDiscount();
10
+ const { isDynamicProduct, isEnableDynamicDiscount } = useDynamicProduct();
9
11
  const { typo } = styles;
10
12
  const { message } = setting;
13
+ const hasDiscount = !!currentOfferDiscount || isDynamicProduct && isEnableDynamicDiscount;
11
14
  return /*#__PURE__*/ jsxs("div", {
12
15
  ...builderAttrs,
13
16
  className: cls(builderProps?.uid, 'gp-flex gp-w-full'),
14
17
  style: {
15
18
  ...style,
16
- opacity: currentOfferDiscount ? 1 : 0.2
19
+ opacity: hasDiscount ? 1 : 0.2
17
20
  },
18
21
  id: `shopify-text-element-${builderProps?.uid}`,
19
22
  "data-product-id": currentProductId,
20
23
  children: [
21
24
  /*#__PURE__*/ jsx(Text, {
22
25
  setting: {
23
- text: currentOfferDiscount ? message : message?.replace(new RegExp(/\{\{Discount\}\}/, 'gi'), '0%')
26
+ text: hasDiscount ? message : message?.replace(new RegExp(/\{\{Discount\}\}/, 'gi'), '0%')
24
27
  },
25
28
  styles: {
26
29
  typo
@@ -7,14 +7,20 @@ import Loading from '../../../common/components/Loading.js';
7
7
  import { DEVICES } from './ProductVariant.js';
8
8
  import { postPurchaseViewSpacing } from '../../utils/helper.js';
9
9
  import { hasPublicStoreFrontData, createStoreFrontFetcher } from '../helpers/index.js';
10
+ import { productOfferPlaceholder } from '../constants/ProductOfferPlaceholder.js';
11
+ import { useDynamicProduct } from '../hooks/useDynamicProduct.js';
10
12
 
11
13
  const PostPurchaseProductOffer = ({ styles, builderAttrs, builderProps, children, setting })=>{
12
14
  const mode = useEditorMode();
13
- const { productSetting, productOfferLayout, inlineAlignment, ...rowSetting } = setting || {};
15
+ const { productSetting, productOfferLayout, inlineAlignment, discountAndShippingFee, ...rowSetting } = setting || {};
14
16
  const { productOfferColumnGap, productOfferVerticalGutter, productOfferWidth, ...rowStyles } = styles || {};
15
17
  const productOffers = usePageStore((s)=>s.productOffers);
16
18
  const publicStoreFrontData = usePageStore((s)=>s.publicStoreFrontData);
17
- const totalProduct = useMemo(()=>productOffers?.length, [
19
+ const { isDynamicProduct } = useDynamicProduct();
20
+ const dynamicDiscountOffer = usePageStore((s)=>s.dynamicDiscountOffer);
21
+ const totalProduct = useMemo(()=>isDynamicProduct ? dynamicDiscountOffer?.appliedProductCount : productOffers?.length, [
22
+ dynamicDiscountOffer?.appliedProductCount,
23
+ isDynamicProduct,
18
24
  productOffers?.length
19
25
  ]);
20
26
  const sortedProductBaseIDs = useMemo(()=>{
@@ -40,7 +46,14 @@ const PostPurchaseProductOffer = ({ styles, builderAttrs, builderProps, children
40
46
  const products = useMemo(()=>flattenConnection(productData.data?.products), [
41
47
  productData.data?.products
42
48
  ]);
43
- const productSortedById = sortedProductBaseIDs?.map((id)=>products?.find((el)=>el?.baseID === id)).filter(Boolean);
49
+ const productSortedById = useMemo(()=>{
50
+ return isDynamicProduct && dynamicDiscountOffer?.appliedProductCount ? Array(dynamicDiscountOffer.appliedProductCount).fill(productOfferPlaceholder) : sortedProductBaseIDs?.map((id)=>products?.find((el)=>el?.baseID === id)).filter(Boolean);
51
+ }, [
52
+ isDynamicProduct,
53
+ dynamicDiscountOffer?.appliedProductCount,
54
+ sortedProductBaseIDs,
55
+ products
56
+ ]);
44
57
  const getStyles = ()=>{
45
58
  return {
46
59
  ...makeStyleResponsive('cg', productOfferColumnGap),
@@ -2,6 +2,7 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { useCurrentVariant, useProduct, shopifyPriceRounding, useProductOfferDiscount, useFormatMoney, cls } from '@gem-sdk/core';
3
3
  import { useMemo } from 'react';
4
4
  import Text from '../../text/Text.js';
5
+ import { useDynamicProduct } from '../hooks/useDynamicProduct.js';
5
6
 
6
7
  const PostPurchaseProductPrice = ({ styles, style, builderAttrs, builderProps, children })=>{
7
8
  const currentVariant = useCurrentVariant();
@@ -9,6 +10,7 @@ const PostPurchaseProductPrice = ({ styles, style, builderAttrs, builderProps, c
9
10
  const price = currentVariant?.price ?? 0;
10
11
  const salePrice = currentVariant?.salePrice ?? 0;
11
12
  const discount = parseFloat(shopifyPriceRounding(useProductOfferDiscount(), 2));
13
+ const { isDynamicProduct } = useDynamicProduct();
12
14
  const priceShow = useMemo(()=>{
13
15
  if (!discount) {
14
16
  if (styles?.priceType === 'compare') {
@@ -49,7 +51,7 @@ const PostPurchaseProductPrice = ({ styles, style, builderAttrs, builderProps, c
49
51
  /*#__PURE__*/ jsx(Text, {
50
52
  styles: styles,
51
53
  setting: {
52
- text: moneyFormatted
54
+ text: isDynamicProduct ? '$???' : moneyFormatted
53
55
  },
54
56
  className: cls({
55
57
  'gp-money': styles?.priceType === 'regular',
@@ -3,6 +3,7 @@ import { useCurrentVariant, useProduct, useQuantity, useProductOfferDiscount, us
3
3
  import { useMemo, useState, useEffect, Fragment as Fragment$1 } from 'react';
4
4
  import { postPurchaseSpacing } from '../../utils/helper.js';
5
5
  import MoneyLine from './priceBreakdown/MoneyLine.js';
6
+ import { useDynamicProduct } from '../hooks/useDynamicProduct.js';
6
7
 
7
8
  const PostPurchaseProductPriceBreakdown = ({ setting = {}, styles = {}, style, builderAttrs, builderProps, children })=>{
8
9
  const currentVariant = useCurrentVariant();
@@ -17,6 +18,7 @@ const PostPurchaseProductPriceBreakdown = ({ setting = {}, styles = {}, style, b
17
18
  const discountShopifyFormat = shopifyPriceRounding(discountWithQuantity, 2);
18
19
  const totalMoneyFormatted = useFormatMoney(subTotal - parseFloat(discountShopifyFormat), false);
19
20
  const currentProductId = currentProduct?.baseID?.replace('gid://shopify/Product/', '');
21
+ const { isDynamicProduct, dynamicPrice, dynamicDiscount, isEnableDynamicDiscount } = useDynamicProduct();
20
22
  const { labelStyle, moneyStyle, spacing, width, align, isShowPrice } = styles;
21
23
  const itemGap = useMemo(()=>{
22
24
  return postPurchaseSpacing[spacing || 'none'];
@@ -29,19 +31,19 @@ const PostPurchaseProductPriceBreakdown = ({ setting = {}, styles = {}, style, b
29
31
  }, [
30
32
  isShowPrice
31
33
  ]);
32
- const moneyLines = useMemo(()=>{
34
+ const getMoneyLines = ()=>{
33
35
  const data = [];
34
36
  if (styles.isShowSubTotalLabel !== false) {
35
37
  data.push({
36
38
  title: setting.subTotalLabel,
37
- money: subTotalMoneyFormatted,
39
+ money: isDynamicProduct ? dynamicPrice : subTotalMoneyFormatted,
38
40
  uniqueId: 'subTotalLabel'
39
41
  });
40
42
  }
41
43
  if (styles.isShowDiscountLabel !== false) {
42
44
  data.push({
43
45
  title: setting.discountLabel,
44
- money: discount > 0 ? discountMoneyFormatted : 'No discount',
46
+ money: isDynamicProduct && dynamicDiscount && isEnableDynamicDiscount ? dynamicPrice : discount > 0 ? discountMoneyFormatted : 'No discount',
45
47
  uniqueId: 'discountLabel'
46
48
  });
47
49
  }
@@ -67,25 +69,11 @@ const PostPurchaseProductPriceBreakdown = ({ setting = {}, styles = {}, style, b
67
69
  }
68
70
  data.push({
69
71
  title: setting.totalLabel,
70
- money: totalMoneyFormatted,
72
+ money: isDynamicProduct ? dynamicPrice : totalMoneyFormatted,
71
73
  uniqueId: 'totalLabel'
72
74
  });
73
75
  return data;
74
- }, [
75
- discount,
76
- discountMoneyFormatted,
77
- setting.discountLabel,
78
- setting.shippingLabel,
79
- setting.subTotalLabel,
80
- setting.taxesLabel,
81
- setting.totalLabel,
82
- styles.isShowSubTotalLabel,
83
- styles.isShowDiscountLabel,
84
- styles.isShowShippingLabel,
85
- styles.isShowTaxesLabel,
86
- subTotalMoneyFormatted,
87
- totalMoneyFormatted
88
- ]);
76
+ };
89
77
  return /*#__PURE__*/ jsxs(Fragment, {
90
78
  children: [
91
79
  /*#__PURE__*/ jsxs("div", {
@@ -136,9 +124,9 @@ const PostPurchaseProductPriceBreakdown = ({ setting = {}, styles = {}, style, b
136
124
  ...makeStyleResponsive('w', width),
137
125
  gap: itemGap
138
126
  },
139
- children: moneyLines.map((item)=>/*#__PURE__*/ jsxs(Fragment$1, {
127
+ children: getMoneyLines().map((item)=>/*#__PURE__*/ jsxs(Fragment$1, {
140
128
  children: [
141
- item.uniqueId === 'totalLabel' && moneyLines.length > 1 && /*#__PURE__*/ jsx("hr", {}),
129
+ item.uniqueId === 'totalLabel' && getMoneyLines().length > 1 && /*#__PURE__*/ jsx("hr", {}),
142
130
  /*#__PURE__*/ jsx("div", {
143
131
  children: /*#__PURE__*/ jsx(MoneyLine, {
144
132
  uniqueId: item.uniqueId,
@@ -0,0 +1,125 @@
1
+ const productOfferPlaceholder = {
2
+ id: '',
3
+ title: 'Dynamic product',
4
+ description: 'This is a dynamic product. The actual product will appear here based on your setup',
5
+ descriptionHtml: '<p class="QN2lPu">This is a dynamic product. The actual product will</p>\n<p class="QN2lPu">appear here based on your setup</p>',
6
+ createdAt: '2024-07-01T04:19:51.286753Z',
7
+ handle: 'dynamic-product',
8
+ averageRating: 0,
9
+ isStorefront: true,
10
+ isSample: false,
11
+ baseID: '',
12
+ sku: '',
13
+ options: [
14
+ {
15
+ id: '1',
16
+ name: 'Variant',
17
+ optionType: '',
18
+ values: [
19
+ {
20
+ id: '1',
21
+ label: 'Variant option',
22
+ isDefault: true,
23
+ baseID: '1'
24
+ }
25
+ ]
26
+ }
27
+ ],
28
+ vendor: '',
29
+ featuredImage: {
30
+ id: '542178560626918105',
31
+ contentType: 'IMAGE',
32
+ previewImage: '',
33
+ src: 'https://cdn.shopify.com/s/files/1/0858/3168/0279/files/gempages_502328832959710176-312cf60c-d923-4913-9873-66545effe9cc.png',
34
+ width: 449,
35
+ height: 449,
36
+ alt: ''
37
+ },
38
+ collections: {
39
+ edges: [
40
+ {
41
+ node: {
42
+ id: '502321959132988135',
43
+ title: 'Home page'
44
+ }
45
+ },
46
+ {
47
+ node: {
48
+ id: '539286505089204764',
49
+ title: 'b'
50
+ }
51
+ },
52
+ {
53
+ node: {
54
+ id: '539286505089401372',
55
+ title: 'e'
56
+ }
57
+ }
58
+ ]
59
+ },
60
+ tags: [],
61
+ medias: {
62
+ edges: [
63
+ {
64
+ cursor: 'gqFpzweGNIc/AALZoXYB',
65
+ node: {
66
+ id: '542178560626918105',
67
+ contentType: 'IMAGE',
68
+ previewImage: '',
69
+ src: 'https://cdn.shopify.com/s/files/1/0858/3168/0279/files/gempages_502328832959710176-312cf60c-d923-4913-9873-66545effe9cc.png',
70
+ width: 449,
71
+ height: 449,
72
+ alt: ''
73
+ }
74
+ }
75
+ ],
76
+ pageInfo: {
77
+ endCursor: 'gqFpzweGNIc/AALZoXYB',
78
+ hasNextPage: true
79
+ }
80
+ },
81
+ variants: {
82
+ edges: [
83
+ {
84
+ cursor: 'gqFpzwc5ZqRtDAMIoXYC',
85
+ node: {
86
+ id: '520560088328176392',
87
+ title: 'Default Title',
88
+ barcode: '',
89
+ baseID: 'gid://shopify/ProductVariant/49298248925463',
90
+ costPrice: 88,
91
+ height: 0,
92
+ inventoryPolicy: 'DENY',
93
+ inventoryQuantity: 211,
94
+ inventoryStatus: '',
95
+ isDigital: true,
96
+ length: 0,
97
+ lowInventoryAmount: 0,
98
+ manageInventory: false,
99
+ mediaId: '0',
100
+ platform: 'SHOPIFY',
101
+ price: 88,
102
+ salePrice: 88,
103
+ sku: '',
104
+ soldIndividually: false,
105
+ weight: 0,
106
+ width: 0,
107
+ selectedOptions: [
108
+ {
109
+ name: 'Variant',
110
+ value: 'Variant option',
111
+ optionType: ''
112
+ }
113
+ ],
114
+ media: undefined
115
+ }
116
+ }
117
+ ],
118
+ pageInfo: {
119
+ hasNextPage: false,
120
+ endCursor: 'gaFpzwc5ZqRtDAMI'
121
+ }
122
+ }
123
+ };
124
+
125
+ export { productOfferPlaceholder };
@@ -0,0 +1,26 @@
1
+ import { usePageStore } from '@gem-sdk/core';
2
+ import { useMemo } from 'react';
3
+
4
+ const useDynamicProduct = ()=>{
5
+ const dynamicDiscountOffer = usePageStore((s)=>s.dynamicDiscountOffer);
6
+ const isDynamicProduct = useMemo(()=>{
7
+ return !!dynamicDiscountOffer;
8
+ }, [
9
+ dynamicDiscountOffer
10
+ ]);
11
+ // false = No discount
12
+ const isEnableDynamicDiscount = useMemo(()=>{
13
+ return dynamicDiscountOffer?.isEnabled;
14
+ }, [
15
+ dynamicDiscountOffer
16
+ ]);
17
+ const dynamicPrice = '$???';
18
+ return {
19
+ isDynamicProduct,
20
+ dynamicPrice,
21
+ dynamicDiscount: dynamicDiscountOffer,
22
+ isEnableDynamicDiscount
23
+ };
24
+ };
25
+
26
+ export { useDynamicProduct };
@@ -180,6 +180,14 @@ const config = {
180
180
  }
181
181
  }
182
182
  },
183
+ {
184
+ id: 'dynamicOfferQuantity',
185
+ type: 'dynamic-offer-quantity',
186
+ min: 1,
187
+ max: 4,
188
+ default: 2,
189
+ isOnlyAcceptInteger: true
190
+ },
183
191
  {
184
192
  id: 'discountAndShippingFee',
185
193
  type: 'discount-and-shipping-fee-product-offer',
@@ -373,6 +381,24 @@ const config = {
373
381
  },
374
382
  layout: 'vertical'
375
383
  },
384
+ {
385
+ type: 'group',
386
+ label: {
387
+ en: 'Product offers'
388
+ },
389
+ controls: [
390
+ {
391
+ type: 'control',
392
+ label: {
393
+ en: 'Quantity'
394
+ },
395
+ setting: {
396
+ id: 'dynamicOfferQuantity'
397
+ }
398
+ }
399
+ ],
400
+ condition: 'false'
401
+ },
376
402
  {
377
403
  type: 'control',
378
404
  label: {
@@ -6,7 +6,7 @@ import { getAspectRatio } from '../../common/common.js';
6
6
  import { checkRenderFeaturedCarousel, getDotSettingByLayout } from '../../common/productFeaturedImage.js';
7
7
  import { handleMouseMove, handleMouseOut } from '../../common/hoverAction.js';
8
8
  import ProductFeaturedImageOnly from './ProductFeaturedImageOnly.js';
9
- import { memo, useMemo, useCallback, useEffect, createRef } from 'react';
9
+ import { memo, useCallback, useState, useEffect, useMemo, createRef } from 'react';
10
10
  import { handleSetSrcForFeatureProductImage } from '../../../../../image/helpers/getSrcSet.js';
11
11
 
12
12
  const ProductFeaturedImageCarousel = ({ productImages, imgRef, onHandleClick, onClickArrow, onHandleLoaded, onHandleUpdateActiveIndex, builderPropUID, builderPropsClass, children, parentUid, ...setting })=>{
@@ -16,12 +16,20 @@ const ProductFeaturedImageCarousel = ({ productImages, imgRef, onHandleClick, on
16
16
  const { onListener, ref } = useInteraction();
17
17
  let delayTimeout;
18
18
  const mode = useEditorMode();
19
- const imageActiveIndex = useMemo(()=>{
19
+ const getImageActiveIndex = useCallback(()=>{
20
20
  const index = productImages?.findIndex((item)=>item.id === featuredImageGlobal?.id);
21
- return index;
21
+ return index ?? 0;
22
22
  }, [
23
- productImages,
24
- featuredImageGlobal
23
+ featuredImageGlobal?.id,
24
+ productImages
25
+ ]);
26
+ const [imageActiveIndex, setImageActiveIndex] = useState(getImageActiveIndex());
27
+ useEffect(()=>{
28
+ setImageActiveIndex(getImageActiveIndex());
29
+ }, [
30
+ featuredImageGlobal,
31
+ getImageActiveIndex,
32
+ productImages
25
33
  ]);
26
34
  const imageActive = useMemo(()=>{
27
35
  if (productImages?.length) return featuredImageGlobal || productImages?.[0];
@@ -228,7 +228,7 @@ const config = {
228
228
  value: 'go-to-url'
229
229
  }
230
230
  ],
231
- default: 'continue-shopping'
231
+ default: 'open-cart-drawer'
232
232
  },
233
233
  {
234
234
  id: 'customURL',
@@ -759,7 +759,7 @@ const StickyPreset = {
759
759
  settings: {
760
760
  label: 'Add to cart',
761
761
  outOfStockLabel: 'Out of stock',
762
- actionEffect: 'continue-shopping',
762
+ actionEffect: 'open-cart-drawer',
763
763
  customURL: {
764
764
  link: '/cart',
765
765
  target: '_self'
@@ -1854,7 +1854,7 @@ const StickyPresetProduct = {
1854
1854
  settings: {
1855
1855
  label: 'Add to cart',
1856
1856
  outOfStockLabel: 'Out of stock',
1857
- actionEffect: 'continue-shopping',
1857
+ actionEffect: 'open-cart-drawer',
1858
1858
  customURL: {
1859
1859
  link: '/cart',
1860
1860
  target: '_self'
@@ -5,7 +5,7 @@ import ThirdPartyPreview from './ThirdPartyPreview.js';
5
5
  const AppConfig = {
6
6
  id: 'notify-back-in-stockpreorder',
7
7
  label: 'Notify! Back in Stock|PreOrder',
8
- logoUrl: 'https://cdn.shopify.com/app-store/listing_images/9216cd5dd17ab1a38de2641bae109159/icon/CNWHjbfSt4MDEAE=.png',
8
+ logoUrl: 'https://cdn.shopify.com/s/files/1/0643/0497/1949/files/Notify_Me_Logo.png?v=1736234550',
9
9
  tag: 'NotifyBackInStockPreOrder'
10
10
  };
11
11
  const NotifyBackInStockPreOrderContent = ()=>{