pb-sxp-ui 1.20.26 → 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.
Files changed (42) hide show
  1. package/dist/index.cjs +292 -395
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +355 -291
  4. package/dist/index.js +292 -395
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.min.cjs +6 -6
  7. package/dist/index.min.cjs.map +1 -1
  8. package/dist/index.min.js +6 -6
  9. package/dist/index.min.js.map +1 -1
  10. package/dist/pb-ui.js +292 -395
  11. package/dist/pb-ui.js.map +1 -1
  12. package/dist/pb-ui.min.js +6 -6
  13. package/dist/pb-ui.min.js.map +1 -1
  14. package/es/core/components/StructurePage/index.d.ts +4 -0
  15. package/es/core/components/StructurePage/index.js +8 -1
  16. package/es/core/components/SxpPageRender/Modal/index.d.ts +1 -0
  17. package/es/core/components/SxpPageRender/Modal/index.js +3 -3
  18. package/es/core/components/SxpPageRender/index.d.ts +1 -0
  19. package/es/core/components/SxpPageRender/typing.d.ts +1 -0
  20. package/es/materials/sxp/popup/AddToCart/index.d.ts +1 -27
  21. package/es/materials/sxp/popup/AddToCart/index.js +117 -173
  22. package/es/materials/sxp/popup/AddToCart/index.new.d.ts +8 -0
  23. package/es/materials/sxp/popup/AddToCart/index.new.js +174 -0
  24. package/es/materials/sxp/popup/AddToCart/index.old.d.ts +33 -0
  25. package/es/materials/sxp/popup/AddToCart/index.old.js +299 -0
  26. package/es/materials/sxp/popup/AddToCart/material.js +1 -54
  27. package/es/materials/sxp/popup/CommodityDetailDiroNew/index.js +48 -53
  28. package/lib/core/components/StructurePage/index.d.ts +4 -0
  29. package/lib/core/components/StructurePage/index.js +8 -1
  30. package/lib/core/components/SxpPageRender/Modal/index.d.ts +1 -0
  31. package/lib/core/components/SxpPageRender/Modal/index.js +3 -3
  32. package/lib/core/components/SxpPageRender/index.d.ts +1 -0
  33. package/lib/core/components/SxpPageRender/typing.d.ts +1 -0
  34. package/lib/materials/sxp/popup/AddToCart/index.d.ts +1 -27
  35. package/lib/materials/sxp/popup/AddToCart/index.js +115 -171
  36. package/lib/materials/sxp/popup/AddToCart/index.new.d.ts +8 -0
  37. package/lib/materials/sxp/popup/AddToCart/index.new.js +176 -0
  38. package/lib/materials/sxp/popup/AddToCart/index.old.d.ts +33 -0
  39. package/lib/materials/sxp/popup/AddToCart/index.old.js +301 -0
  40. package/lib/materials/sxp/popup/AddToCart/material.js +1 -54
  41. package/lib/materials/sxp/popup/CommodityDetailDiroNew/index.js +48 -53
  42. package/package.json +1 -1
@@ -61,6 +61,10 @@ export interface IApiResponse {
61
61
  productUserId?: string;
62
62
  multiCta?: IMultiCtaData;
63
63
  position?: number;
64
+ shopify?: {
65
+ domain: string;
66
+ storefrontAccessToken: string;
67
+ };
64
68
  };
65
69
  }
66
70
  export interface IStructurePageProps {
@@ -523,7 +523,7 @@ const StructurePage = (_a) => {
523
523
  return res.json();
524
524
  })
525
525
  .then((result) => {
526
- var _a, _b, _c, _d;
526
+ var _a, _b, _c, _d, _e;
527
527
  if (result.code === '0' || result.code === '00000') {
528
528
  let multiCtaData = null;
529
529
  if (isCmsMode) {
@@ -539,6 +539,13 @@ const StructurePage = (_a) => {
539
539
  console.error('[StructurePage] No multiCta data found in response:', result);
540
540
  setError(result.message || 'No multiCta data found');
541
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
+ }
542
549
  }
543
550
  else {
544
551
  setError(result.message || 'Failed to load data');
@@ -10,6 +10,7 @@ interface IModalProps {
10
10
  fullHeight?: number;
11
11
  isFullScreen?: boolean;
12
12
  openState?: IPopupType;
13
+ showCloseButton?: boolean;
13
14
  }
14
15
  declare const _default: React.NamedExoticComponent<React.PropsWithChildren<IModalProps>>;
15
16
  export default _default;
@@ -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);
@@ -81,6 +81,7 @@ export interface ISxpPageRenderProps {
81
81
  };
82
82
  shopifyDomain?: string;
83
83
  storefrontAccessToken?: string;
84
+ popupList?: any[];
84
85
  };
85
86
  descStyle?: CSSProperties;
86
87
  tipText?: {
@@ -46,6 +46,7 @@ export type ProductInfoType = {
46
46
  taxInfo?: string;
47
47
  cover?: string;
48
48
  remark?: string;
49
+ shopifyId?: string;
49
50
  };
50
51
  export interface IScene {
51
52
  blueprintStep: number;
@@ -1,33 +1,7 @@
1
- import { FC, CSSProperties } from 'react';
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, __rest } from "tslib";
2
- import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
1
+ import { __awaiter } from "tslib";
2
+ import React, { useState, useEffect, useCallback } from 'react';
3
3
  import { useSxpDataSource } from '../../../../core/hooks';
4
- import { useEventReport } from '../../../../core/hooks/useEventReport';
5
- import { setFontForText } from '../../../../core/utils/tool';
4
+ import Modal from '../../../../core/components/SxpPageRender/Modal';
6
5
  import './index.less';
7
- const AddToCartPopup = (_a) => {
8
- var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
9
- var { style, isActive = true, index, shopifyDomain = '', storefrontAccessToken = '', variantStyles = {}, buttonStyle = {}, quantityStyle = {}, texts = {}, popupBg = {} } = _a, props = __rest(_a, ["style", "isActive", "index", "shopifyDomain", "storefrontAccessToken", "variantStyles", "buttonStyle", "quantityStyle", "texts", "popupBg"]);
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 = (_c = (_b = data === null || data === void 0 ? void 0 : data.video) === null || _b === void 0 ? void 0 : _b.bindProduct) !== null && _c !== void 0 ? _c : (_e = (_d = data === null || data === void 0 ? void 0 : data.video) === null || _d === void 0 ? void 0 : _d.bindProducts) === null || _e === void 0 ? void 0 : _e[0];
21
- const cta = product === null || product === void 0 ? void 0 : product.bindCta;
22
- const position = (_g = (_f = popupDetailData === null || popupDetailData === void 0 ? void 0 : popupDetailData.index) !== null && _f !== void 0 ? _f : index) !== null && _g !== void 0 ? _g : 0;
23
- const finalShopifyDomain = shopifyDomain || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.shopifyDomain) || 'dev-store-749237498237498636.myshopify.com';
24
- const finalStorefrontToken = storefrontAccessToken || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.storefrontAccessToken) || '77d894c490f79430ce7bd0a7efdff6b7';
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 _m;
38
- if (!productId || !finalShopifyDomain || !finalStorefrontToken) {
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 formattedProductId = productId.startsWith('gid://')
95
- ? productId
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': finalStorefrontToken
77
+ 'X-Shopify-Storefront-Access-Token': storefrontToken
103
78
  },
104
79
  body: JSON.stringify({
105
80
  query,
106
- variables: { id: formattedProductId }
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
- if (!((_m = result.data) === null || _m === void 0 ? void 0 : _m.product)) {
118
- console.error('[AddToCartPopup] 未找到商品');
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
- const errorMessage = err instanceof Error ? err.message : finalTexts.error;
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, finalShopifyDomain, finalStorefrontToken, finalTexts.error]);
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 => selectedOptions[option.name] === option.value);
116
+ return variant.selectedOptions.every(option => {
117
+ return selectedOptions[option.name] === option.value;
118
+ });
150
119
  });
151
120
  setSelectedVariant(matchedVariant || null);
152
- setQuantity(1);
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 = useCallback((optionName, value) => {
155
- setSelectedOptions(prev => {
156
- const newOptions = Object.assign({}, prev);
157
- if (newOptions[optionName] === value) {
158
- delete newOptions[optionName];
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
- const variantId = selectedVariant.id.split('/').pop();
190
- const cartUrl = `https://${finalShopifyDomain}/cart/add?id=${variantId}&quantity=${quantity}`;
191
- console.log('[AddToCartPopup] 加购:', {
132
+ }
133
+ const variantId = selectedVariant.id.replace('gid://shopify/ProductVariant/', '');
134
+ console.log('[AddToCart] 添加到购物车:', {
192
135
  variantId,
193
136
  quantity,
194
- cartUrl
137
+ shopifyDomain,
138
+ selectedVariant
195
139
  });
196
- bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
197
- eventName: 'AddToCart',
198
- product: product ? [product] : undefined,
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
- }, [selectedVariant, quantity, finalShopifyDomain, bffFbReport, product, data, position]);
212
- const totalPrice = useMemo(() => {
213
- if (!selectedVariant)
214
- return null;
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: "add-to-cart-popup-loading", style: style },
231
- React.createElement("div", null, finalTexts.loading)));
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 (error || !productData) {
234
- return (React.createElement("div", { className: "add-to-cart-popup-error", style: style },
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 = selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.image) === null || _h === void 0 ? void 0 : _h.url) || ((_j = productData.images.edges[0]) === null || _j === void 0 ? void 0 : _j.node.url) || ((_k = product === null || product === void 0 ? void 0 : product.homePage) === null || _k === void 0 ? void 0 : _k[0]) || '';
241
- const hasAllOptionsSelected = productData.options.length === Object.keys(selectedOptions).length;
242
- const isAddToCartDisabled = !selectedVariant || quantity === 0;
243
- return (React.createElement("div", Object.assign({ className: "add-to-cart-popup-container", style: style }, props),
244
- React.createElement("div", { className: "variant-detail-section" },
245
- React.createElement("div", { className: "variant-image-wrapper" },
246
- React.createElement("img", { src: mainImage, alt: productData.title, className: "variant-image" })),
247
- React.createElement("div", { className: "variant-info-wrapper" },
248
- React.createElement("h2", { className: "product-title-text", style: variantStyles.title, dangerouslySetInnerHTML: {
249
- __html: setFontForText(productData.title, variantStyles.title)
250
- } }),
251
- selectedVariant && (React.createElement(React.Fragment, null,
252
- React.createElement("div", { className: "selected-options-tags" }, selectedVariant.selectedOptions.map(option => (React.createElement("span", { key: option.name, className: "option-tag", style: variantStyles.selectedOption },
253
- option.name,
254
- ": ",
255
- option.value)))),
256
- React.createElement("div", { className: "price-display" },
257
- React.createElement("span", { className: "price-value", style: variantStyles.price, dangerouslySetInnerHTML: {
258
- __html: setFontForText(`${selectedVariant.price.currencyCode} $${totalPrice}`, variantStyles.price)
259
- } })),
260
- React.createElement("div", { className: "quantity-selector-wrapper", style: quantityStyle },
261
- React.createElement("button", { className: "quantity-btn quantity-decrease", onClick: () => handleQuantityChange(-1), disabled: quantity <= 1, "aria-label": "Decrease quantity" }, "-"),
262
- React.createElement("input", { type: "number", value: quantity, readOnly: true, className: "quantity-input-field", "aria-label": "Quantity" }),
263
- React.createElement("button", { className: "quantity-btn quantity-increase", onClick: () => handleQuantityChange(1), disabled: quantity >= ((_l = selectedVariant.quantityAvailable) !== null && _l !== void 0 ? _l : 999), "aria-label": "Increase quantity" }, "+")))),
264
- !hasAllOptionsSelected && (React.createElement("div", { className: "no-selection-hint", style: variantStyles.option }, finalTexts.selectOptions)))),
265
- React.createElement("div", { className: "variant-options-section" }, productData.options.map(option => (React.createElement("div", { key: option.name, className: "option-group-wrapper" },
266
- React.createElement("h3", { className: "option-group-name", style: variantStyles.option, dangerouslySetInnerHTML: {
267
- __html: setFontForText(option.name, variantStyles.option)
268
- } }),
269
- React.createElement("div", { className: "option-values-grid" }, option.values.map(value => {
270
- const isSelected = selectedOptions[option.name] === value;
271
- const isAvailable = isOptionValueAvailable(option.name, value);
272
- return (React.createElement("button", { key: value, className: `option-value-button ${isSelected ? 'selected' : ''} ${!isAvailable ? 'disabled' : ''}`, onClick: () => isAvailable && handleOptionSelect(option.name, value), disabled: !isAvailable, "aria-label": `${option.name}: ${value}`, "aria-pressed": isSelected }, value));
273
- })))))),
274
- React.createElement("button", { className: `add-to-cart-button ${isAddToCartDisabled ? 'disabled' : ''}`, style: buttonStyle, onClick: handleAddToCart, disabled: isAddToCartDisabled, "aria-label": finalTexts.addToCart },
275
- React.createElement("span", { dangerouslySetInnerHTML: {
276
- __html: setFontForText(finalTexts.addToCart, buttonStyle)
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;
@@ -0,0 +1,8 @@
1
+ import { FC } from 'react';
2
+ import './index.less';
3
+ export interface IAddToCartPopupProps {
4
+ isActive?: boolean;
5
+ onClose?: () => void;
6
+ }
7
+ declare const AddToCartPopup: FC<IAddToCartPopupProps>;
8
+ export default AddToCartPopup;