pb-sxp-ui 1.20.25 → 1.20.27
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/index.cjs +2164 -2248
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +355 -291
- package/dist/index.js +2164 -2248
- package/dist/index.js.map +1 -1
- package/dist/index.min.cjs +6 -6
- package/dist/index.min.cjs.map +1 -1
- package/dist/index.min.js +6 -6
- package/dist/index.min.js.map +1 -1
- package/dist/pb-ui.js +2164 -2248
- package/dist/pb-ui.js.map +1 -1
- package/dist/pb-ui.min.js +6 -6
- package/dist/pb-ui.min.js.map +1 -1
- package/es/core/components/StructurePage/index.d.ts +4 -0
- package/es/core/components/StructurePage/index.js +14 -23
- package/es/core/components/SxpPageRender/Modal/index.d.ts +1 -0
- package/es/core/components/SxpPageRender/Modal/index.js +3 -3
- package/es/core/components/SxpPageRender/index.d.ts +1 -0
- package/es/core/components/SxpPageRender/typing.d.ts +1 -0
- package/es/materials/sxp/popup/AddToCart/index.d.ts +1 -27
- package/es/materials/sxp/popup/AddToCart/index.js +117 -173
- package/es/materials/sxp/popup/AddToCart/index.new.d.ts +8 -0
- package/es/materials/sxp/popup/AddToCart/index.new.js +174 -0
- package/es/materials/sxp/popup/AddToCart/index.old.d.ts +33 -0
- package/es/materials/sxp/popup/AddToCart/index.old.js +299 -0
- package/es/materials/sxp/popup/AddToCart/material.js +1 -54
- package/es/materials/sxp/popup/CommodityDetailDiroNew/index.js +48 -53
- package/lib/core/components/StructurePage/index.d.ts +4 -0
- package/lib/core/components/StructurePage/index.js +14 -23
- package/lib/core/components/SxpPageRender/Modal/index.d.ts +1 -0
- package/lib/core/components/SxpPageRender/Modal/index.js +3 -3
- package/lib/core/components/SxpPageRender/index.d.ts +1 -0
- package/lib/core/components/SxpPageRender/typing.d.ts +1 -0
- package/lib/materials/sxp/popup/AddToCart/index.d.ts +1 -27
- package/lib/materials/sxp/popup/AddToCart/index.js +115 -171
- package/lib/materials/sxp/popup/AddToCart/index.new.d.ts +8 -0
- package/lib/materials/sxp/popup/AddToCart/index.new.js +176 -0
- package/lib/materials/sxp/popup/AddToCart/index.old.d.ts +33 -0
- package/lib/materials/sxp/popup/AddToCart/index.old.js +301 -0
- package/lib/materials/sxp/popup/AddToCart/material.js +1 -54
- package/lib/materials/sxp/popup/CommodityDetailDiroNew/index.js +48 -53
- package/package.json +1 -1
|
@@ -2,30 +2,14 @@ import { __rest } from "tslib";
|
|
|
2
2
|
import React, { useEffect, useState, useRef, useMemo, useCallback } from 'react';
|
|
3
3
|
import { useEditor } from '../../hooks';
|
|
4
4
|
import FormatImage from '../SxpPageRender/FormatImage';
|
|
5
|
+
import * as _materials_ from '../../../materials/sxp';
|
|
5
6
|
const RESOLVER = {};
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (
|
|
9
|
-
|
|
10
|
-
var _a;
|
|
11
|
-
if ((_a = v === null || v === void 0 ? void 0 : v.extend) === null || _a === void 0 ? void 0 : _a.type) {
|
|
12
|
-
RESOLVER[v.extend.type] = v;
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
if (Object.keys(RESOLVER).length > 0) {
|
|
16
|
-
console.log('[StructurePage] Successfully loaded materials:', Object.keys(RESOLVER));
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
console.warn('[StructurePage] Materials module loaded but no valid components found');
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
console.warn('[StructurePage] Materials module is not a valid object:', materialsModule);
|
|
7
|
+
Object.values(_materials_).forEach((v) => {
|
|
8
|
+
var _a;
|
|
9
|
+
if ((_a = v === null || v === void 0 ? void 0 : v.extend) === null || _a === void 0 ? void 0 : _a.type) {
|
|
10
|
+
RESOLVER[v.extend.type] = v;
|
|
24
11
|
}
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
console.error('[StructurePage] Failed to load materials for StructurePage:', error);
|
|
28
|
-
}
|
|
12
|
+
});
|
|
29
13
|
const baseStyles = {
|
|
30
14
|
container: {
|
|
31
15
|
backgroundColor: '#000',
|
|
@@ -539,7 +523,7 @@ const StructurePage = (_a) => {
|
|
|
539
523
|
return res.json();
|
|
540
524
|
})
|
|
541
525
|
.then((result) => {
|
|
542
|
-
var _a, _b, _c, _d;
|
|
526
|
+
var _a, _b, _c, _d, _e;
|
|
543
527
|
if (result.code === '0' || result.code === '00000') {
|
|
544
528
|
let multiCtaData = null;
|
|
545
529
|
if (isCmsMode) {
|
|
@@ -555,6 +539,13 @@ const StructurePage = (_a) => {
|
|
|
555
539
|
console.error('[StructurePage] No multiCta data found in response:', result);
|
|
556
540
|
setError(result.message || 'No multiCta data found');
|
|
557
541
|
}
|
|
542
|
+
if ((_e = result.data) === null || _e === void 0 ? void 0 : _e.shopify) {
|
|
543
|
+
window.__SHOPIFY_CONFIG__ = {
|
|
544
|
+
domain: result.data.shopify.domain,
|
|
545
|
+
storefrontAccessToken: result.data.shopify.storefrontAccessToken
|
|
546
|
+
};
|
|
547
|
+
console.log('[StructurePage] Shopify config stored:', window.__SHOPIFY_CONFIG__);
|
|
548
|
+
}
|
|
558
549
|
}
|
|
559
550
|
else {
|
|
560
551
|
setError(result.message || 'Failed to load data');
|
|
@@ -4,7 +4,7 @@ import * as ReactDOM from 'react-dom';
|
|
|
4
4
|
import { useEditor, useSxpDataSource } from '../../../../core/hooks';
|
|
5
5
|
import { useVisibleHeight } from '../../../../core/hooks/useVisibleHeight';
|
|
6
6
|
const closeIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAjhJREFUWEfFlztOw0AQhmeWiJ4CCmpQ5DiRQsIJyAWg5A0lR0AIChDiCJS8ER0cADgBeRSxt4CCDgkaKiq8i+zYeWx2413HEWmiJJv9v535Z2aN8M8vFPT9z3zETD0aAUChUJjwvPFHAJhBhB3Hqd6OAsK2yyucwykAvP38eJX398Z3AJDLlVYR8ToU9Rhj25TWr9KEsKy5dULIGQCMtfZly45TvwsAstm56UwG6wA4FUFwzrdctxZBDcWSy5XWEPG8I84/GcMipdWPtgcsaz5PCHtKG0IuTiqUvjT9U/WYMG2IOPE+AP+LtCB0xKUAAyA2Xbd2o2OG0NQXvTnvhL17D7EPtH9TRCIWwkRcGYGIQgYBABuqPuHXOQBc6pw80lBGwBQiiXhsBHQhkoprA6iM6acjhDQKu5YJZW6XeOI3XJdpvfsdTu52VfXEekD8owQiXGIubpSCbhDbLu8DwKEAd+A41SOdPpE4BS0viFOtvV2iKWqUgn5x/tmS70xR01GuDSCKc86/OCcLgTyyZ0ScDGNhFAktAJV4NFJ9YyaFiAWIE+9uVkkgBgLoig8DMWAa9ro9ynkUdlW5maZDCmB6clmz0k1HH4Cs1Ezbq2p2yEpUuBOKTSZZex00RUWIrltxuuK6EOGDSbGIOPZicpMx6fny650377qNRgBgWeVFQuA+6UjVgREhGIMlSqsPUQqIbZdOOIdZQmCv2axRnU1N1+TzJYsxOEaEV8ep7frPZ7Gd0FTEdP0ft0/kMNdg0eoAAAAASUVORK5CYII=';
|
|
7
|
-
const Modal = ({ visible, onClose, children, modalStyle, padding, popup, schema, fullHeight, isFullScreen = false, openState }) => {
|
|
7
|
+
const Modal = ({ visible, onClose, children, modalStyle, padding, popup, schema, fullHeight, isFullScreen = false, openState, showCloseButton = true }) => {
|
|
8
8
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
|
|
9
9
|
const { visibleHeight, bottomHeight } = useVisibleHeight();
|
|
10
10
|
const touchRef = useRef(null);
|
|
@@ -178,7 +178,7 @@ const Modal = ({ visible, onClose, children, modalStyle, padding, popup, schema,
|
|
|
178
178
|
setScrollTop(15 - ((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.scrollTop));
|
|
179
179
|
}
|
|
180
180
|
})), child()),
|
|
181
|
-
React.createElement("button", { className: 'modal-icon-wrapper', role: 'button', "aria-label": 'close button', onClick: onClose, style: { top: scrollTop } },
|
|
182
|
-
React.createElement("img", { src: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.popupCloseIcon) || closeIcon, alt: 'close button', className: 'modal-icon' }))))))), modalEleRef.current);
|
|
181
|
+
showCloseButton && (React.createElement("button", { className: 'modal-icon-wrapper', role: 'button', "aria-label": 'close button', onClick: onClose, style: { top: scrollTop } },
|
|
182
|
+
React.createElement("img", { src: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.popupCloseIcon) || closeIcon, alt: 'close button', className: 'modal-icon' })))))))), modalEleRef.current);
|
|
183
183
|
};
|
|
184
184
|
export default memo(Modal);
|
|
@@ -1,33 +1,7 @@
|
|
|
1
|
-
import { FC
|
|
1
|
+
import { FC } from 'react';
|
|
2
2
|
import './index.less';
|
|
3
3
|
export interface IAddToCartPopupProps {
|
|
4
|
-
style?: CSSProperties;
|
|
5
4
|
isActive?: boolean;
|
|
6
|
-
index?: number;
|
|
7
|
-
shopifyDomain?: string;
|
|
8
|
-
storefrontAccessToken?: string;
|
|
9
|
-
variantStyles?: {
|
|
10
|
-
title?: CSSProperties;
|
|
11
|
-
price?: CSSProperties;
|
|
12
|
-
option?: CSSProperties;
|
|
13
|
-
selectedOption?: CSSProperties;
|
|
14
|
-
};
|
|
15
|
-
buttonStyle?: CSSProperties;
|
|
16
|
-
quantityStyle?: CSSProperties;
|
|
17
|
-
texts?: {
|
|
18
|
-
addToCart?: string;
|
|
19
|
-
selectOptions?: string;
|
|
20
|
-
loading?: string;
|
|
21
|
-
error?: string;
|
|
22
|
-
color?: string;
|
|
23
|
-
size?: string;
|
|
24
|
-
material?: string;
|
|
25
|
-
style?: string;
|
|
26
|
-
};
|
|
27
|
-
popupBg?: {
|
|
28
|
-
horizontalMargin?: number;
|
|
29
|
-
bottomMargin?: number;
|
|
30
|
-
};
|
|
31
5
|
}
|
|
32
6
|
declare const AddToCartPopup: FC<IAddToCartPopupProps>;
|
|
33
7
|
export default AddToCartPopup;
|
|
@@ -1,53 +1,31 @@
|
|
|
1
|
-
import { __awaiter
|
|
2
|
-
import React, { useState, useEffect, useCallback
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
|
3
3
|
import { useSxpDataSource } from '../../../../core/hooks';
|
|
4
|
-
import
|
|
5
|
-
import { setFontForText } from '../../../../core/utils/tool';
|
|
4
|
+
import Modal from '../../../../core/components/SxpPageRender/Modal';
|
|
6
5
|
import './index.less';
|
|
7
|
-
const AddToCartPopup = (
|
|
8
|
-
var _b, _c, _d, _e, _f, _g, _h, _j
|
|
9
|
-
|
|
10
|
-
const { sxpParameter, popupDetailData, isPreview, bffFbReport, globalConfig } = useSxpDataSource();
|
|
11
|
-
const { jumpToWeb } = useEventReport();
|
|
12
|
-
const curTimeRef = useRef(null);
|
|
6
|
+
const AddToCartPopup = ({ isActive = true }) => {
|
|
7
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
8
|
+
const { popupDetailData, globalConfig } = useSxpDataSource();
|
|
13
9
|
const [productData, setProductData] = useState(null);
|
|
14
10
|
const [selectedOptions, setSelectedOptions] = useState({});
|
|
15
11
|
const [selectedVariant, setSelectedVariant] = useState(null);
|
|
16
12
|
const [quantity, setQuantity] = useState(1);
|
|
17
13
|
const [loading, setLoading] = useState(true);
|
|
18
14
|
const [error, setError] = useState(null);
|
|
15
|
+
const [showImagePreview, setShowImagePreview] = useState(false);
|
|
16
|
+
const [previewImageUrl, setPreviewImageUrl] = useState('');
|
|
19
17
|
const data = popupDetailData;
|
|
20
|
-
const product = (
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const productId = (product === null || product === void 0 ? void 0 : product.itemId) || '';
|
|
26
|
-
const finalTexts = {
|
|
27
|
-
addToCart: texts.addToCart || 'Add to Cart',
|
|
28
|
-
selectOptions: texts.selectOptions || 'Please select options',
|
|
29
|
-
loading: texts.loading || 'Loading...',
|
|
30
|
-
error: texts.error || 'Failed to load product',
|
|
31
|
-
color: texts.color || 'Color',
|
|
32
|
-
size: texts.size || 'Size',
|
|
33
|
-
material: texts.material || 'Material',
|
|
34
|
-
style: texts.style || 'Style'
|
|
35
|
-
};
|
|
18
|
+
const product = (_e = (_b = (_a = data === null || data === void 0 ? void 0 : data.video) === null || _a === void 0 ? void 0 : _a.bindProduct) !== null && _b !== void 0 ? _b : (_d = (_c = data === null || data === void 0 ? void 0 : data.video) === null || _c === void 0 ? void 0 : _c.bindProducts) === null || _d === void 0 ? void 0 : _d[0]) !== null && _e !== void 0 ? _e : data === null || data === void 0 ? void 0 : data.product;
|
|
19
|
+
const shopifyConfig = window.__SHOPIFY_CONFIG__;
|
|
20
|
+
const shopifyDomain = ((_f = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.shopify) === null || _f === void 0 ? void 0 : _f.domain) || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.shopifyDomain) || (shopifyConfig === null || shopifyConfig === void 0 ? void 0 : shopifyConfig.domain) || 'dev-store-749237498237498636.myshopify.com';
|
|
21
|
+
const storefrontToken = ((_g = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.shopify) === null || _g === void 0 ? void 0 : _g.storefrontAccessToken) || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.storefrontAccessToken) || (shopifyConfig === null || shopifyConfig === void 0 ? void 0 : shopifyConfig.storefrontAccessToken) || '77d894c490f79430ce7bd0a7efdff6b7';
|
|
22
|
+
const productId = (product === null || product === void 0 ? void 0 : product.shopifyId) || (product === null || product === void 0 ? void 0 : product.itemId) || '';
|
|
36
23
|
const fetchProductData = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
-
var
|
|
38
|
-
if (!productId || !
|
|
39
|
-
console.log('[AddToCartPopup] 缺少必要配置:', {
|
|
40
|
-
productId,
|
|
41
|
-
shopifyDomain: finalShopifyDomain,
|
|
42
|
-
hasToken: !!finalStorefrontToken
|
|
43
|
-
});
|
|
24
|
+
var _k;
|
|
25
|
+
if (!productId || !shopifyDomain || !storefrontToken) {
|
|
44
26
|
setLoading(false);
|
|
45
27
|
return;
|
|
46
28
|
}
|
|
47
|
-
console.log('[AddToCartPopup] 开始加载商品数据:', {
|
|
48
|
-
productId,
|
|
49
|
-
shopifyDomain: finalShopifyDomain
|
|
50
|
-
});
|
|
51
29
|
setLoading(true);
|
|
52
30
|
setError(null);
|
|
53
31
|
try {
|
|
@@ -91,45 +69,34 @@ const AddToCartPopup = (_a) => {
|
|
|
91
69
|
}
|
|
92
70
|
}
|
|
93
71
|
`;
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
: `gid://shopify/Product/${productId}`;
|
|
97
|
-
console.log('[AddToCartPopup] 使用的 Product ID:', formattedProductId);
|
|
98
|
-
const response = yield fetch(`https://${finalShopifyDomain}/api/2024-01/graphql.json`, {
|
|
72
|
+
const fullProductId = productId.startsWith('gid://') ? productId : `gid://shopify/Product/${productId}`;
|
|
73
|
+
const response = yield fetch(`https://${shopifyDomain}/api/2024-01/graphql.json`, {
|
|
99
74
|
method: 'POST',
|
|
100
75
|
headers: {
|
|
101
76
|
'Content-Type': 'application/json',
|
|
102
|
-
'X-Shopify-Storefront-Access-Token':
|
|
77
|
+
'X-Shopify-Storefront-Access-Token': storefrontToken
|
|
103
78
|
},
|
|
104
79
|
body: JSON.stringify({
|
|
105
80
|
query,
|
|
106
|
-
variables: { id:
|
|
81
|
+
variables: { id: fullProductId }
|
|
107
82
|
})
|
|
108
83
|
});
|
|
109
|
-
if (!response.ok) {
|
|
110
|
-
throw new Error(`HTTP ${response.status}`);
|
|
111
|
-
}
|
|
112
84
|
const result = yield response.json();
|
|
113
85
|
if (result.errors) {
|
|
114
|
-
console.error('[AddToCartPopup] GraphQL 错误:', result.errors);
|
|
115
86
|
throw new Error(result.errors[0].message);
|
|
116
87
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
throw new Error('Product not found');
|
|
120
|
-
}
|
|
121
|
-
console.log('[AddToCartPopup] 商品数据加载成功:', result.data.product.title);
|
|
88
|
+
console.log('[AddToCart] Shopify Product Data:', result.data.product);
|
|
89
|
+
console.log('[AddToCart] Options:', (_k = result.data.product) === null || _k === void 0 ? void 0 : _k.options);
|
|
122
90
|
setProductData(result.data.product);
|
|
123
91
|
}
|
|
124
92
|
catch (err) {
|
|
125
|
-
|
|
126
|
-
setError(errorMessage);
|
|
93
|
+
setError(err instanceof Error ? err.message : 'Failed to load product');
|
|
127
94
|
console.error('[AddToCartPopup] 加载失败:', err);
|
|
128
95
|
}
|
|
129
96
|
finally {
|
|
130
97
|
setLoading(false);
|
|
131
98
|
}
|
|
132
|
-
}), [productId,
|
|
99
|
+
}), [productId, shopifyDomain, storefrontToken]);
|
|
133
100
|
useEffect(() => {
|
|
134
101
|
if (isActive) {
|
|
135
102
|
fetchProductData();
|
|
@@ -146,134 +113,111 @@ const AddToCartPopup = (_a) => {
|
|
|
146
113
|
return;
|
|
147
114
|
}
|
|
148
115
|
const matchedVariant = variants.find(variant => {
|
|
149
|
-
return variant.selectedOptions.every(option =>
|
|
116
|
+
return variant.selectedOptions.every(option => {
|
|
117
|
+
return selectedOptions[option.name] === option.value;
|
|
118
|
+
});
|
|
150
119
|
});
|
|
151
120
|
setSelectedVariant(matchedVariant || null);
|
|
152
|
-
|
|
121
|
+
if ((matchedVariant === null || matchedVariant === void 0 ? void 0 : matchedVariant.quantityAvailable) !== undefined && matchedVariant.quantityAvailable > 0) {
|
|
122
|
+
setQuantity(prev => Math.min(prev, matchedVariant.quantityAvailable));
|
|
123
|
+
}
|
|
153
124
|
}, [selectedOptions, productData]);
|
|
154
|
-
const handleOptionSelect =
|
|
155
|
-
setSelectedOptions(prev => {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
else {
|
|
161
|
-
newOptions[optionName] = value;
|
|
162
|
-
}
|
|
163
|
-
return newOptions;
|
|
164
|
-
});
|
|
165
|
-
}, []);
|
|
166
|
-
const handleQuantityChange = useCallback((delta) => {
|
|
167
|
-
setQuantity(prev => {
|
|
168
|
-
var _a;
|
|
169
|
-
const newQuantity = prev + delta;
|
|
170
|
-
const maxQuantity = (_a = selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.quantityAvailable) !== null && _a !== void 0 ? _a : 999;
|
|
171
|
-
return Math.max(1, Math.min(newQuantity, maxQuantity));
|
|
172
|
-
});
|
|
173
|
-
}, [selectedVariant]);
|
|
174
|
-
const isOptionValueAvailable = useCallback((optionName, value) => {
|
|
175
|
-
if (!productData)
|
|
176
|
-
return false;
|
|
177
|
-
const variants = productData.variants.edges.map(edge => edge.node);
|
|
178
|
-
const tempOptions = Object.assign(Object.assign({}, selectedOptions), { [optionName]: value });
|
|
179
|
-
return variants.some(variant => {
|
|
180
|
-
const matches = variant.selectedOptions.every(option => !tempOptions[option.name] || tempOptions[option.name] === option.value);
|
|
181
|
-
const hasStock = variant.quantityAvailable === null || variant.quantityAvailable > 0;
|
|
182
|
-
return matches && variant.availableForSale && hasStock;
|
|
183
|
-
});
|
|
184
|
-
}, [productData, selectedOptions]);
|
|
185
|
-
const handleAddToCart = useCallback(() => {
|
|
186
|
-
var _a;
|
|
187
|
-
if (!selectedVariant || quantity === 0)
|
|
125
|
+
const handleOptionSelect = (optionName, value) => {
|
|
126
|
+
setSelectedOptions(prev => (Object.assign(Object.assign({}, prev), { [optionName]: value })));
|
|
127
|
+
};
|
|
128
|
+
const handleAddToCart = () => {
|
|
129
|
+
if (!selectedVariant) {
|
|
130
|
+
alert('Please select all options');
|
|
188
131
|
return;
|
|
189
|
-
|
|
190
|
-
const
|
|
191
|
-
console.log('[
|
|
132
|
+
}
|
|
133
|
+
const variantId = selectedVariant.id.replace('gid://shopify/ProductVariant/', '');
|
|
134
|
+
console.log('[AddToCart] 添加到购物车:', {
|
|
192
135
|
variantId,
|
|
193
136
|
quantity,
|
|
194
|
-
|
|
137
|
+
shopifyDomain,
|
|
138
|
+
selectedVariant
|
|
195
139
|
});
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
contentType: 'product',
|
|
200
|
-
data,
|
|
201
|
-
position,
|
|
202
|
-
content_id: (_a = product === null || product === void 0 ? void 0 : product.itemId) !== null && _a !== void 0 ? _a : '',
|
|
203
|
-
value: parseFloat(selectedVariant.price.amount) * quantity,
|
|
204
|
-
currency: selectedVariant.price.currencyCode,
|
|
205
|
-
contents: [{
|
|
206
|
-
id: variantId,
|
|
207
|
-
quantity
|
|
208
|
-
}]
|
|
140
|
+
const params = new URLSearchParams({
|
|
141
|
+
id: variantId,
|
|
142
|
+
quantity: quantity.toString()
|
|
209
143
|
});
|
|
144
|
+
const cartUrl = `https://${shopifyDomain}/cart/add?${params.toString()}`;
|
|
145
|
+
console.log('[AddToCart] 跳转到购物车 URL:', cartUrl);
|
|
210
146
|
window.location.href = cartUrl;
|
|
211
|
-
}
|
|
212
|
-
const totalPrice =
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const price = parseFloat(selectedVariant.price.amount);
|
|
216
|
-
const total = price * quantity;
|
|
217
|
-
return total.toFixed(2);
|
|
218
|
-
}, [selectedVariant, quantity]);
|
|
219
|
-
useEffect(() => {
|
|
220
|
-
const initTime = () => {
|
|
221
|
-
curTimeRef.current = new Date();
|
|
222
|
-
};
|
|
223
|
-
initTime();
|
|
224
|
-
window.addEventListener('pageshow', initTime);
|
|
225
|
-
return () => {
|
|
226
|
-
window.removeEventListener('pageshow', initTime);
|
|
227
|
-
};
|
|
228
|
-
}, []);
|
|
147
|
+
};
|
|
148
|
+
const totalPrice = selectedVariant
|
|
149
|
+
? (parseFloat(selectedVariant.price.amount) * quantity).toFixed(2)
|
|
150
|
+
: '0.00';
|
|
229
151
|
if (loading) {
|
|
230
|
-
return (React.createElement("div", { className:
|
|
231
|
-
React.createElement("div",
|
|
152
|
+
return (React.createElement("div", { className: 'add-to-cart-popup' },
|
|
153
|
+
React.createElement("div", { className: 'loading' }, "Loading...")));
|
|
154
|
+
}
|
|
155
|
+
if (error) {
|
|
156
|
+
return (React.createElement("div", { className: 'add-to-cart-popup' },
|
|
157
|
+
React.createElement("div", { className: 'error' }, error)));
|
|
232
158
|
}
|
|
233
|
-
if (
|
|
234
|
-
return
|
|
235
|
-
React.createElement("div", null,
|
|
236
|
-
finalTexts.error,
|
|
237
|
-
": ",
|
|
238
|
-
error || 'Product not found')));
|
|
159
|
+
if (!productData) {
|
|
160
|
+
return null;
|
|
239
161
|
}
|
|
240
|
-
const mainImage = ((_h =
|
|
241
|
-
const
|
|
242
|
-
const
|
|
243
|
-
return (React.createElement("div",
|
|
244
|
-
React.createElement("div", { className:
|
|
245
|
-
React.createElement("div", { className:
|
|
246
|
-
React.createElement("
|
|
247
|
-
React.createElement("div", { className:
|
|
248
|
-
React.createElement("
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
React.createElement("div", { className:
|
|
257
|
-
React.createElement("
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
React.createElement("
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
React.createElement("div", { className:
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
162
|
+
const mainImage = ((_h = productData.images.edges[0]) === null || _h === void 0 ? void 0 : _h.node.url) || '';
|
|
163
|
+
const variantImage = ((_j = selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.image) === null || _j === void 0 ? void 0 : _j.url) || mainImage;
|
|
164
|
+
const maxQuantity = (selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.quantityAvailable) || 999;
|
|
165
|
+
return (React.createElement("div", { className: 'add-to-cart-popup' },
|
|
166
|
+
React.createElement("div", { className: 'popup-content' },
|
|
167
|
+
React.createElement("div", { className: 'product-header' },
|
|
168
|
+
React.createElement("div", { className: 'product-title' }, productData.title)),
|
|
169
|
+
React.createElement("div", { className: 'variant-detail' },
|
|
170
|
+
React.createElement("div", { className: 'variant-image-container', onClick: () => {
|
|
171
|
+
if (variantImage) {
|
|
172
|
+
setPreviewImageUrl(variantImage);
|
|
173
|
+
setShowImagePreview(true);
|
|
174
|
+
}
|
|
175
|
+
}, style: { cursor: 'pointer' } },
|
|
176
|
+
React.createElement("img", { src: variantImage, alt: 'Selected variant', className: 'variant-image' })),
|
|
177
|
+
React.createElement("div", { className: 'variant-info' },
|
|
178
|
+
React.createElement("div", { className: 'variant-specs-row' },
|
|
179
|
+
React.createElement("div", { className: 'variant-specs' }, Object.keys(selectedOptions).length > 0 ? (Object.entries(selectedOptions).map(([key, value]) => (React.createElement("span", { key: key, className: 'spec-item' }, value)))) : (React.createElement("span", { className: 'spec-placeholder' }, "Please select options"))),
|
|
180
|
+
selectedVariant && selectedVariant.quantityAvailable !== undefined && (React.createElement("div", { className: 'stock-info' },
|
|
181
|
+
"Available: ",
|
|
182
|
+
selectedVariant.quantityAvailable))),
|
|
183
|
+
React.createElement("div", { className: 'variant-price-row' },
|
|
184
|
+
React.createElement("div", { className: 'price' },
|
|
185
|
+
"$",
|
|
186
|
+
totalPrice),
|
|
187
|
+
React.createElement("div", { className: 'quantity-selector' },
|
|
188
|
+
React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1 }, "\u2212"),
|
|
189
|
+
React.createElement("span", { className: 'qty-value' }, quantity),
|
|
190
|
+
React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(quantity + 1), disabled: !selectedVariant || quantity >= maxQuantity }, "+"))))),
|
|
191
|
+
React.createElement("div", { className: 'variant-options' }, productData.options.map(option => (React.createElement("div", { key: option.name, className: 'option-group' },
|
|
192
|
+
React.createElement("div", { className: 'option-label' }, option.name),
|
|
193
|
+
React.createElement("div", { className: 'option-values' }, option.values.map(value => {
|
|
194
|
+
const isAvailable = productData.variants.edges.some(({ node: variant }) => {
|
|
195
|
+
const hasThisOption = variant.selectedOptions.some(opt => opt.name === option.name && opt.value === value);
|
|
196
|
+
if (!hasThisOption || !variant.availableForSale)
|
|
197
|
+
return false;
|
|
198
|
+
if (variant.quantityAvailable !== undefined) {
|
|
199
|
+
return variant.quantityAvailable > 0;
|
|
200
|
+
}
|
|
201
|
+
return true;
|
|
202
|
+
});
|
|
203
|
+
const isSelected = selectedOptions[option.name] === value;
|
|
204
|
+
return (React.createElement("button", { key: value, className: `option-btn ${isSelected ? 'selected' : ''} ${!isAvailable ? 'disabled' : ''}`, onClick: () => isAvailable && handleOptionSelect(option.name, value), disabled: !isAvailable }, value));
|
|
205
|
+
}))))))),
|
|
206
|
+
React.createElement("div", { className: 'popup-footer' },
|
|
207
|
+
React.createElement("button", { className: 'add-to-cart-btn', onClick: handleAddToCart, disabled: !selectedVariant }, "Add To Cart")),
|
|
208
|
+
showImagePreview && previewImageUrl && (React.createElement(Modal, { visible: showImagePreview, padding: 0, isFullScreen: true, onClose: () => setShowImagePreview(false) },
|
|
209
|
+
React.createElement("div", { style: {
|
|
210
|
+
width: '100%',
|
|
211
|
+
height: '100%',
|
|
212
|
+
display: 'flex',
|
|
213
|
+
alignItems: 'center',
|
|
214
|
+
justifyContent: 'center',
|
|
215
|
+
backgroundColor: 'rgba(0, 0, 0, 0.9)'
|
|
216
|
+
}, onClick: () => setShowImagePreview(false) },
|
|
217
|
+
React.createElement("img", { src: previewImageUrl, alt: 'Preview', style: {
|
|
218
|
+
maxWidth: '100%',
|
|
219
|
+
maxHeight: '100%',
|
|
220
|
+
objectFit: 'contain'
|
|
221
|
+
} }))))));
|
|
278
222
|
};
|
|
279
223
|
export default AddToCartPopup;
|