@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.
- package/dist/cjs/article/components/ArticleList.js +1 -1
- package/dist/cjs/banner/components/hero-banner/index.liquid.js +9 -7
- package/dist/cjs/banner/components/hero-banner/utils/index.js +5 -3
- package/dist/cjs/form/components/textarea/TextArea.liquid.js +2 -2
- package/dist/cjs/image/components/Image.js +0 -1
- package/dist/cjs/image/components/Image.liquid.js +0 -1
- package/dist/cjs/marquee/components/MarqueeBase.liquid.js +7 -26
- package/dist/cjs/post-purchase/product/components/ProductDiscountTag.js +5 -2
- package/dist/cjs/post-purchase/product/components/ProductOffer.js +16 -3
- package/dist/cjs/post-purchase/product/components/ProductPrice.js +3 -1
- package/dist/cjs/post-purchase/product/components/ProductPriceBreakdown.js +9 -21
- package/dist/cjs/post-purchase/product/constants/ProductOfferPlaceholder.js +127 -0
- package/dist/cjs/post-purchase/product/hooks/useDynamicProduct.js +28 -0
- package/dist/cjs/post-purchase/product/settings/ProductOffer.js +26 -0
- package/dist/cjs/product/components/ProductImagesV2/jsx/components/ProductFeaturedImageCarousel.js +12 -4
- package/dist/cjs/product/setting/ProductButton.js +1 -1
- package/dist/cjs/sticky/setting/preset-config.js +2 -2
- package/dist/cjs/third-party/components/NotifyBackInStockPreOrder.js +1 -1
- package/dist/cjs/third-party/components/ShopifySubscriptions.liquid.js +3 -2
- package/dist/cjs/third-party/setting/NotifyBackInStockPreOrder.js +2 -2
- package/dist/cjs/third-party/setting/ShopifySubscriptions.js +22 -0
- package/dist/esm/article/components/ArticleList.js +1 -1
- package/dist/esm/banner/components/hero-banner/index.liquid.js +9 -7
- package/dist/esm/banner/components/hero-banner/utils/index.js +5 -3
- package/dist/esm/form/components/textarea/TextArea.liquid.js +2 -2
- package/dist/esm/image/components/Image.js +0 -1
- package/dist/esm/image/components/Image.liquid.js +0 -1
- package/dist/esm/marquee/components/MarqueeBase.liquid.js +7 -26
- package/dist/esm/post-purchase/product/components/ProductDiscountTag.js +5 -2
- package/dist/esm/post-purchase/product/components/ProductOffer.js +16 -3
- package/dist/esm/post-purchase/product/components/ProductPrice.js +3 -1
- package/dist/esm/post-purchase/product/components/ProductPriceBreakdown.js +9 -21
- package/dist/esm/post-purchase/product/constants/ProductOfferPlaceholder.js +125 -0
- package/dist/esm/post-purchase/product/hooks/useDynamicProduct.js +26 -0
- package/dist/esm/post-purchase/product/settings/ProductOffer.js +26 -0
- package/dist/esm/product/components/ProductImagesV2/jsx/components/ProductFeaturedImageCarousel.js +13 -5
- package/dist/esm/product/setting/ProductButton.js +1 -1
- package/dist/esm/sticky/setting/preset-config.js +2 -2
- package/dist/esm/third-party/components/NotifyBackInStockPreOrder.js +1 -1
- package/dist/esm/third-party/components/ShopifySubscriptions.liquid.js +3 -2
- package/dist/esm/third-party/setting/NotifyBackInStockPreOrder.js +2 -2
- package/dist/esm/third-party/setting/ShopifySubscriptions.js +22 -0
- package/dist/types/index.d.ts +4 -0
- 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:
|
|
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
|
|
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'] ?
|
|
208
|
-
tablet: `url('${bgiEnableByDevice['tablet'] ?
|
|
209
|
-
mobile: `url('${bgiEnableByDevice['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]:
|
|
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
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
|
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 =
|
|
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
|
|
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:
|
|
127
|
+
children: getMoneyLines().map((item)=>/*#__PURE__*/ jsxs(Fragment$1, {
|
|
140
128
|
children: [
|
|
141
|
-
item.uniqueId === 'totalLabel' &&
|
|
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: {
|
package/dist/esm/product/components/ProductImagesV2/jsx/components/ProductFeaturedImageCarousel.js
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
-
|
|
24
|
-
|
|
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];
|
|
@@ -759,7 +759,7 @@ const StickyPreset = {
|
|
|
759
759
|
settings: {
|
|
760
760
|
label: 'Add to cart',
|
|
761
761
|
outOfStockLabel: 'Out of stock',
|
|
762
|
-
actionEffect: '
|
|
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: '
|
|
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/
|
|
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 = ()=>{
|