@wix/headless-stores 0.0.10 → 0.0.12

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 (133) hide show
  1. package/cjs/dist/enums/index.d.ts +2 -0
  2. package/cjs/dist/enums/index.js +18 -0
  3. package/cjs/dist/enums/social-platform-enums.d.ts +25 -0
  4. package/cjs/dist/enums/social-platform-enums.js +30 -0
  5. package/cjs/dist/enums/sort-enums.d.ts +17 -0
  6. package/cjs/dist/enums/sort-enums.js +21 -0
  7. package/cjs/dist/react/BuyNow.d.ts +2 -4
  8. package/cjs/dist/react/Category.d.ts +9 -11
  9. package/cjs/dist/react/Category.js +8 -23
  10. package/cjs/dist/react/Collection.d.ts +13 -3
  11. package/cjs/dist/react/Collection.js +30 -19
  12. package/cjs/dist/react/FilteredCollection.d.ts +46 -15
  13. package/cjs/dist/react/FilteredCollection.js +45 -12
  14. package/cjs/dist/react/PayNow.d.ts +2 -4
  15. package/cjs/dist/react/Product.d.ts +8 -35
  16. package/cjs/dist/react/Product.js +10 -31
  17. package/cjs/dist/react/ProductActions.d.ts +42 -0
  18. package/cjs/dist/react/ProductActions.js +83 -0
  19. package/cjs/dist/react/ProductModifiers.d.ts +16 -8
  20. package/cjs/dist/react/ProductModifiers.js +19 -10
  21. package/cjs/dist/react/ProductVariantSelector.d.ts +52 -68
  22. package/cjs/dist/react/ProductVariantSelector.js +58 -86
  23. package/cjs/dist/react/RelatedProducts.d.ts +8 -4
  24. package/cjs/dist/react/RelatedProducts.js +12 -7
  25. package/cjs/dist/react/SelectedVariant.d.ts +66 -0
  26. package/cjs/dist/react/SelectedVariant.js +52 -0
  27. package/cjs/dist/react/SocialSharing.d.ts +24 -30
  28. package/cjs/dist/react/SocialSharing.js +8 -2
  29. package/cjs/dist/react/Sort.d.ts +12 -15
  30. package/cjs/dist/react/Sort.js +11 -34
  31. package/cjs/dist/react/index.d.ts +11 -10
  32. package/cjs/dist/react/index.js +3 -2
  33. package/cjs/dist/services/buy-now-service.js +2 -2
  34. package/cjs/dist/services/catalog-options-service.d.ts +2 -2
  35. package/cjs/dist/services/catalog-options-service.js +39 -45
  36. package/cjs/dist/services/catalog-price-range-service.d.ts +2 -2
  37. package/cjs/dist/services/catalog-price-range-service.js +13 -11
  38. package/cjs/dist/services/category-service.d.ts +7 -6
  39. package/cjs/dist/services/category-service.js +15 -11
  40. package/cjs/dist/services/collection-service.d.ts +8 -8
  41. package/cjs/dist/services/collection-service.js +182 -67
  42. package/cjs/dist/services/filter-service.d.ts +1 -1
  43. package/cjs/dist/services/filter-service.js +15 -23
  44. package/cjs/dist/services/product-media-gallery-service.d.ts +3 -3
  45. package/cjs/dist/services/product-modifiers-service.d.ts +6 -8
  46. package/cjs/dist/services/product-modifiers-service.js +14 -7
  47. package/cjs/dist/services/product-service.d.ts +8 -7
  48. package/cjs/dist/services/product-service.js +36 -19
  49. package/cjs/dist/services/related-products-service.d.ts +4 -4
  50. package/cjs/dist/services/related-products-service.js +4 -4
  51. package/cjs/dist/services/selected-variant-service.d.ts +24 -16
  52. package/cjs/dist/services/selected-variant-service.js +271 -126
  53. package/cjs/dist/services/social-sharing-service.d.ts +2 -2
  54. package/cjs/dist/services/social-sharing-service.js +47 -63
  55. package/cjs/dist/services/sort-service.d.ts +3 -2
  56. package/cjs/dist/services/sort-service.js +8 -13
  57. package/dist/enums/index.d.ts +2 -0
  58. package/dist/enums/index.js +2 -0
  59. package/dist/enums/social-platform-enums.d.ts +25 -0
  60. package/dist/enums/social-platform-enums.js +27 -0
  61. package/dist/enums/sort-enums.d.ts +17 -0
  62. package/dist/enums/sort-enums.js +18 -0
  63. package/dist/react/BuyNow.d.ts +2 -4
  64. package/dist/react/Category.d.ts +9 -11
  65. package/dist/react/Category.js +10 -23
  66. package/dist/react/Collection.d.ts +13 -3
  67. package/dist/react/Collection.js +32 -21
  68. package/dist/react/FilteredCollection.d.ts +46 -15
  69. package/dist/react/FilteredCollection.js +49 -16
  70. package/dist/react/PayNow.d.ts +2 -4
  71. package/dist/react/Product.d.ts +8 -35
  72. package/dist/react/Product.js +11 -31
  73. package/dist/react/ProductActions.d.ts +42 -0
  74. package/dist/react/ProductActions.js +79 -0
  75. package/dist/react/ProductModifiers.d.ts +16 -8
  76. package/dist/react/ProductModifiers.js +22 -13
  77. package/dist/react/ProductVariantSelector.d.ts +52 -68
  78. package/dist/react/ProductVariantSelector.js +57 -84
  79. package/dist/react/RelatedProducts.d.ts +8 -4
  80. package/dist/react/RelatedProducts.js +15 -10
  81. package/dist/react/SelectedVariant.d.ts +66 -0
  82. package/dist/react/SelectedVariant.js +46 -0
  83. package/dist/react/SocialSharing.d.ts +24 -30
  84. package/dist/react/SocialSharing.js +11 -5
  85. package/dist/react/Sort.d.ts +12 -15
  86. package/dist/react/Sort.js +13 -34
  87. package/dist/react/index.d.ts +11 -10
  88. package/dist/react/index.js +11 -10
  89. package/dist/services/buy-now-service.js +2 -2
  90. package/dist/services/catalog-options-service.d.ts +2 -2
  91. package/dist/services/catalog-options-service.js +41 -47
  92. package/dist/services/catalog-price-range-service.d.ts +2 -2
  93. package/dist/services/catalog-price-range-service.js +15 -13
  94. package/dist/services/category-service.d.ts +7 -6
  95. package/dist/services/category-service.js +17 -13
  96. package/dist/services/collection-service.d.ts +8 -8
  97. package/dist/services/collection-service.js +188 -73
  98. package/dist/services/filter-service.d.ts +1 -1
  99. package/dist/services/filter-service.js +20 -28
  100. package/dist/services/product-media-gallery-service.d.ts +3 -3
  101. package/dist/services/product-modifiers-service.d.ts +6 -8
  102. package/dist/services/product-modifiers-service.js +16 -9
  103. package/dist/services/product-service.d.ts +8 -7
  104. package/dist/services/product-service.js +38 -21
  105. package/dist/services/related-products-service.d.ts +4 -4
  106. package/dist/services/related-products-service.js +6 -6
  107. package/dist/services/selected-variant-service.d.ts +24 -16
  108. package/dist/services/selected-variant-service.js +273 -127
  109. package/dist/services/social-sharing-service.d.ts +2 -2
  110. package/dist/services/social-sharing-service.js +49 -65
  111. package/dist/services/sort-service.d.ts +3 -2
  112. package/dist/services/sort-service.js +11 -16
  113. package/package.json +7 -1
  114. package/cjs/dist/react/ProductMediaGallery.d.ts +0 -128
  115. package/cjs/dist/react/ProductMediaGallery.js +0 -100
  116. package/dist/astro/BuyNowServiceContext.d.ts +0 -2
  117. package/dist/astro/BuyNowServiceContext.js +0 -6
  118. package/dist/astro/ManagerProviderContext.d.ts +0 -2
  119. package/dist/astro/ManagerProviderContext.js +0 -7
  120. package/dist/astro/withBuyButtonService.d.ts +0 -2
  121. package/dist/astro/withBuyButtonService.js +0 -16
  122. package/dist/react/CurrentCartServiceProvider.d.ts +0 -5
  123. package/dist/react/CurrentCartServiceProvider.js +0 -12
  124. package/dist/react/ProductMediaGallery.d.ts +0 -128
  125. package/dist/react/ProductMediaGallery.js +0 -92
  126. package/dist/react/VariantSelectorServiceProvider.d.ts +0 -7
  127. package/dist/react/VariantSelectorServiceProvider.js +0 -22
  128. package/dist/react/hookim/index.d.ts +0 -5
  129. package/dist/react/hookim/index.js +0 -22
  130. package/dist/services/CurrentCartService.d.ts +0 -18
  131. package/dist/services/CurrentCartService.js +0 -9
  132. package/dist/services/VariantSelectorServices.d.ts +0 -8
  133. package/dist/services/VariantSelectorServices.js +0 -20
@@ -1,11 +1,46 @@
1
- import { defineService, implementService, } from "@wix/services-definitions";
2
- import { SignalsServiceDefinition } from "@wix/services-definitions/core-services/signals";
3
- import { productsV3 } from "@wix/stores";
4
- export const SelectedVariantServiceDefinition = defineService("selectedVariant");
5
- export const SelectedVariantService = implementService.withConfig()(SelectedVariantServiceDefinition, ({ getService, config }) => {
1
+ import { defineService, implementService } from '@wix/services-definitions';
2
+ import { SignalsServiceDefinition } from '@wix/services-definitions/core-services/signals';
3
+ import { ModifierRenderType, InventoryAvailabilityStatus, } from '@wix/auto_sdk_stores_products-v-3';
4
+ import { queryInventoryItems } from '@wix/auto_sdk_stores_inventory-items-v-3';
5
+ // import { CurrentCartServiceDefinition } from '../../ecom/services/current-cart-service';
6
+ import { ProductServiceDefinition } from './product-service';
7
+ export const SelectedVariantServiceDefinition = defineService('selectedVariant');
8
+ export const SelectedVariantService = implementService.withConfig()(SelectedVariantServiceDefinition, ({ getService }) => {
6
9
  const signalsService = getService(SignalsServiceDefinition);
7
10
  // const cartService = getService(CurrentCartServiceDefinition);
8
- const configProduct = config.product;
11
+ const productService = getService(ProductServiceDefinition);
12
+ // const mediaService = getService(MediaGalleryServiceDefinition);
13
+ const selectedChoices = signalsService.signal({});
14
+ const preOrderMessage = signalsService.signal(null);
15
+ const initialProduct = productService.product.get();
16
+ signalsService.effect(() => {
17
+ const product = productService.product.get();
18
+ const selectedChoicesValue = selectedChoices.get() || {};
19
+ let mediaToDisplay = [];
20
+ const productItemsImages = product?.media?.itemsInfo?.items?.map(item => item).filter(Boolean) ??
21
+ [];
22
+ if (productItemsImages.length) {
23
+ mediaToDisplay = productItemsImages;
24
+ }
25
+ else if (product?.media?.main) {
26
+ mediaToDisplay = [product.media.main];
27
+ }
28
+ // Get images based on selected choices if available
29
+ let selectedChoicesImages = [];
30
+ Object.keys(selectedChoicesValue).forEach(choiceKey => {
31
+ const productOption = product?.options
32
+ ?.find((option) => option.name === choiceKey)
33
+ ?.choicesSettings?.choices?.find((choice) => choice.name === selectedChoicesValue[choiceKey]);
34
+ if (productOption) {
35
+ selectedChoicesImages.push(...(productOption.linkedMedia ?? []));
36
+ }
37
+ });
38
+ if (selectedChoicesImages?.length) {
39
+ mediaToDisplay = selectedChoicesImages;
40
+ }
41
+ console.log({ mediaToDisplay });
42
+ // mediaService.setMediaToDisplay(mediaToDisplay ?? []);
43
+ });
9
44
  const parsePrice = (amount) => {
10
45
  if (!amount)
11
46
  return 0;
@@ -26,28 +61,67 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
26
61
  return choices;
27
62
  };
28
63
  const findVariantByChoices = (variants, selectedChoices) => {
29
- return (variants.find((variant) => {
64
+ return (variants.find(variant => {
30
65
  const variantChoices = processVariantChoices(variant);
31
66
  const choiceKeys = Object.keys(selectedChoices);
32
- return choiceKeys.every((key) => variantChoices[key] === selectedChoices[key]);
67
+ return choiceKeys.every(key => variantChoices[key] === selectedChoices[key]);
33
68
  }) || null);
34
69
  };
35
- // const getDefaultVariant = (): productsV3.Variant | null => {
36
- // const variantsList = variants.get();
37
- // return variantsList[0] || null;
38
- // };
39
- const updateQuantityFromVariant = (variant) => {
70
+ const findVariantWithMinPrice = () => {
71
+ const variantsList = variants.get();
72
+ const variantPrices = variantsList.map(x => Number(x.price?.actualPrice?.formattedAmount) ||
73
+ Number(x.price?.actualPrice?.amount));
74
+ const minPrice = String(Math.min(...variantPrices));
75
+ return variantsList.find(x => x.price?.actualPrice?.formattedAmount === minPrice ||
76
+ x.price?.actualPrice?.amount === minPrice);
77
+ };
78
+ const updateInventoryItemData = async (variantId, inStock, preOrderEnabled) => {
79
+ if (!variantId) {
80
+ preOrderMessage.set(null);
81
+ return;
82
+ }
83
+ try {
84
+ // Use the correct Wix inventoryItemsV3.queryInventoryItems() API
85
+ const queryResult = await queryInventoryItems()
86
+ .eq('variantId', variantId)
87
+ .find();
88
+ const inventoryItem = queryResult.items?.[0];
89
+ const isTrackingQuantity = inventoryItem?.trackQuantity ?? false;
90
+ trackQuantity.set(isTrackingQuantity);
91
+ preOrderMessage.set(inventoryItem?.preorderInfo?.message || null);
92
+ if (!inventoryItem || !isTrackingQuantity) {
93
+ quantityAvailable.set(null);
94
+ return;
95
+ }
96
+ if (inStock && inventoryItem?.quantity) {
97
+ quantityAvailable.set(inventoryItem.quantity);
98
+ }
99
+ else if (preOrderEnabled && inventoryItem.preorderInfo?.limit) {
100
+ quantityAvailable.set(inventoryItem.preorderInfo.limit);
101
+ }
102
+ else {
103
+ quantityAvailable.set(null);
104
+ }
105
+ }
106
+ catch (error) {
107
+ console.error('Failed to fetch inventory quantity:', error);
108
+ // Fallback on error
109
+ quantityAvailable.set(null);
110
+ trackQuantity.set(false);
111
+ }
112
+ };
113
+ const updateDataFromVariant = (variant) => {
40
114
  if (variant) {
41
115
  const inStock = variant.inventoryStatus?.inStock ?? true;
42
116
  const preOrderEnabled = variant.inventoryStatus?.preorderEnabled ?? false;
43
- // If in stock, allow 999. If out of stock but pre-order enabled, allow 999. Otherwise 0.
44
- quantityAvailable.set(inStock || preOrderEnabled ? 999 : 0);
117
+ // update the quantity available, tracking indication and pre-order message from the inventory API
118
+ updateInventoryItemData(variant._id, inStock, preOrderEnabled);
45
119
  }
46
120
  else {
47
121
  quantityAvailable.set(0);
122
+ trackQuantity.set(false);
48
123
  }
49
124
  };
50
- const selectedChoices = signalsService.signal({});
51
125
  const isLoading = signalsService.signal(false);
52
126
  const error = signalsService.signal(null);
53
127
  const variants = signalsService.signal([]);
@@ -55,60 +129,70 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
55
129
  const basePrice = signalsService.signal(0);
56
130
  const discountPrice = signalsService.signal(null);
57
131
  const isOnSale = signalsService.signal(null);
58
- const quantityAvailable = signalsService.signal(0);
59
- const productId = signalsService.signal("");
60
- const sku = signalsService.signal("");
132
+ const quantityAvailable = signalsService.signal(null);
133
+ const trackQuantity = signalsService.signal(false);
134
+ const selectedQuantity = signalsService.signal(1);
135
+ const productId = signalsService.signal('');
61
136
  const ribbonLabel = signalsService.signal(null);
62
- const v3Product = signalsService.signal(configProduct);
63
- if (configProduct) {
64
- productId.set(configProduct._id || "");
65
- ribbonLabel.set(configProduct.ribbon?.name || null);
66
- const actualPrice = configProduct.actualPriceRange?.minValue?.amount;
67
- const compareAtPrice = configProduct.compareAtPriceRange?.minValue?.amount;
68
- basePrice.set(parsePrice(actualPrice));
69
- discountPrice.set(compareAtPrice ? parsePrice(compareAtPrice) : null);
70
- isOnSale.set(!!compareAtPrice && parsePrice(compareAtPrice) > parsePrice(actualPrice));
71
- if (configProduct.options) {
72
- const optionsMap = {};
73
- configProduct.options.forEach((option) => {
74
- if (option.name && option.choicesSettings?.choices) {
75
- optionsMap[option.name] = option.choicesSettings.choices.map((choice) => choice.name || "");
137
+ const v3Product = signalsService.signal(initialProduct);
138
+ const init = (currentProduct) => {
139
+ if (currentProduct) {
140
+ v3Product.set(currentProduct);
141
+ productId.set(currentProduct._id || '');
142
+ ribbonLabel.set(currentProduct.ribbon?.name || null);
143
+ const actualPrice = currentProduct.actualPriceRange?.minValue?.amount;
144
+ const compareAtPrice = currentProduct.compareAtPriceRange?.minValue?.amount;
145
+ basePrice.set(parsePrice(actualPrice));
146
+ discountPrice.set(compareAtPrice ? parsePrice(compareAtPrice) : null);
147
+ isOnSale.set(!!compareAtPrice &&
148
+ parsePrice(compareAtPrice) > parsePrice(actualPrice));
149
+ if (currentProduct.options) {
150
+ const optionsMap = {};
151
+ currentProduct.options.forEach((option) => {
152
+ if (option.name && option.choicesSettings?.choices) {
153
+ optionsMap[option.name] = option.choicesSettings.choices.map((choice) => choice.name || '');
154
+ }
155
+ });
156
+ options.set(optionsMap);
157
+ }
158
+ if (currentProduct.variantSummary.variantCount > 1) {
159
+ variants.set(currentProduct.variantsInfo?.variants || []);
160
+ if (currentProduct.variantsInfo?.variants?.length) {
161
+ // updateDataFromVariant(currentProduct.variantsInfo?.variants[0]);
76
162
  }
77
- });
78
- options.set(optionsMap);
79
- }
80
- if (configProduct.variantsInfo?.variants) {
81
- variants.set(configProduct.variantsInfo.variants);
82
- if (configProduct.variantsInfo.variants.length > 0) {
83
- updateQuantityFromVariant(configProduct.variantsInfo.variants[0] || null);
163
+ }
164
+ else {
165
+ const singleVariant = {
166
+ _id: 'default',
167
+ visible: true,
168
+ choices: [],
169
+ price: {
170
+ actualPrice: currentProduct.actualPriceRange?.minValue,
171
+ compareAtPrice: currentProduct.compareAtPriceRange?.minValue,
172
+ },
173
+ inventoryStatus: {
174
+ inStock: currentProduct.inventory?.availabilityStatus ===
175
+ InventoryAvailabilityStatus.IN_STOCK ||
176
+ currentProduct.inventory?.availabilityStatus ===
177
+ InventoryAvailabilityStatus.PARTIALLY_OUT_OF_STOCK,
178
+ preorderEnabled: currentProduct.inventory?.preorderStatus === 'ENABLED',
179
+ },
180
+ };
181
+ variants.set([singleVariant]);
182
+ updateDataFromVariant(singleVariant);
84
183
  }
85
184
  }
86
- else {
87
- const singleVariant = {
88
- _id: "default",
89
- visible: true,
90
- choices: [],
91
- price: {
92
- actualPrice: configProduct.actualPriceRange?.minValue,
93
- compareAtPrice: configProduct.compareAtPriceRange?.minValue,
94
- },
95
- inventoryStatus: {
96
- inStock: configProduct.inventory?.availabilityStatus === "IN_STOCK" ||
97
- configProduct.inventory?.availabilityStatus ===
98
- "PARTIALLY_OUT_OF_STOCK",
99
- preorderEnabled: configProduct.inventory?.preorderStatus === "ENABLED",
100
- },
101
- };
102
- variants.set([singleVariant]);
103
- updateQuantityFromVariant(singleVariant);
104
- }
105
- }
185
+ };
186
+ signalsService.effect(() => {
187
+ const currentProduct = productService.product.get();
188
+ init(currentProduct);
189
+ });
106
190
  const currentVariant = signalsService.computed((() => {
107
- const prod = v3Product.get();
108
191
  const choices = selectedChoices.get();
109
- if (!prod?.variantsInfo?.variants)
192
+ const variantsList = variants.get();
193
+ if (!variantsList || variantsList.length === 0)
110
194
  return null;
111
- return (prod.variantsInfo.variants.find((variant) => {
195
+ return (variantsList.find((variant) => {
112
196
  const variantChoices = processVariantChoices(variant);
113
197
  if (Object.keys(choices).length !== Object.keys(variantChoices).length)
114
198
  return false;
@@ -121,8 +205,19 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
121
205
  const variant = currentVariant.get();
122
206
  return variant?._id || null;
123
207
  });
208
+ const variantWithMinPrice = findVariantWithMinPrice();
124
209
  const currentPrice = signalsService.computed(() => {
125
210
  const variant = currentVariant.get();
211
+ if (!variant && variantWithMinPrice) {
212
+ const formattedAmount = variantWithMinPrice?.price?.actualPrice?.formattedAmount;
213
+ if (formattedAmount) {
214
+ return formattedAmount;
215
+ }
216
+ const amount = variantWithMinPrice?.price?.actualPrice?.amount;
217
+ if (amount) {
218
+ return `$${amount}`;
219
+ }
220
+ }
126
221
  const prod = v3Product.get();
127
222
  // Try to get formatted amount first (if fields worked)
128
223
  if (variant?.price?.actualPrice?.formattedAmount) {
@@ -139,11 +234,21 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
139
234
  else if (prod?.actualPriceRange?.minValue?.amount) {
140
235
  rawAmount = prod.actualPriceRange.minValue.amount;
141
236
  }
142
- return rawAmount ? `$${rawAmount}` : "";
237
+ return rawAmount ? `$${rawAmount}` : '';
143
238
  });
144
239
  const currentCompareAtPrice = signalsService.computed(() => {
145
240
  const variant = currentVariant.get();
146
241
  const prod = v3Product.get();
242
+ if (!variant && variantWithMinPrice) {
243
+ const formattedAmount = variantWithMinPrice?.price?.compareAtPrice?.formattedAmount;
244
+ if (formattedAmount) {
245
+ return formattedAmount;
246
+ }
247
+ const amount = variantWithMinPrice?.price?.compareAtPrice?.amount;
248
+ if (amount) {
249
+ return `$${amount}`;
250
+ }
251
+ }
147
252
  // Try to get formatted compare-at price first
148
253
  if (variant?.price?.compareAtPrice?.formattedAmount) {
149
254
  return variant.price.compareAtPrice.formattedAmount;
@@ -181,41 +286,48 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
181
286
  });
182
287
  const currency = signalsService.computed(() => {
183
288
  const prod = v3Product.get();
184
- return prod?.currency || "USD";
289
+ return prod?.currency || 'USD';
185
290
  });
186
291
  const selectedVariant = () => {
187
292
  const variantId = selectedVariantId.get();
188
293
  const variantsList = variants.get();
189
- return variantsList.find((v) => v._id === variantId) || null;
294
+ return variantsList.find(v => v._id === variantId) || null;
190
295
  };
191
296
  const finalPrice = () => {
192
297
  const discount = discountPrice.get();
193
298
  const base = basePrice.get();
194
299
  return discount !== null ? discount : base;
195
300
  };
196
- // @ts-ignore
197
- const isLowStock = (threshold = 5) => {
301
+ const isLowStock = () => {
302
+ // Note: Currently always returns false as inventory quantity tracking
303
+ // is handled separately by the inventory service
198
304
  return false;
199
305
  };
200
306
  const setSelectedChoices = (choices) => {
201
307
  selectedChoices.set(choices);
308
+ selectedQuantity.set(1); // Reset quantity when choices change
202
309
  const matchingVariant = findVariantByChoices(variants.get(), choices);
203
- updateQuantityFromVariant(matchingVariant);
310
+ updateDataFromVariant(matchingVariant);
204
311
  };
205
- const addToCart = async (quantity = 1, modifiers) => {
312
+ const addToCart = async (_quantity = 1, modifiers) => {
206
313
  try {
207
314
  isLoading.set(true);
208
315
  error.set(null);
209
316
  const prod = v3Product.get();
210
317
  const variant = currentVariant.get();
211
318
  if (!prod?._id) {
212
- throw new Error("Product not found");
319
+ throw new Error('Product not found');
213
320
  }
214
321
  // Build catalog reference with modifiers if provided
215
322
  const catalogReference = {
216
323
  catalogItemId: prod._id,
217
- appId: "215238eb-22a5-4c36-9e7b-e7c08025e04e",
218
- options: variant?._id ? { variantId: variant._id, preOrderRequested: !!variant?.inventoryStatus?.preorderEnabled } : undefined,
324
+ appId: '215238eb-22a5-4c36-9e7b-e7c08025e04e',
325
+ options: variant?._id && variant._id !== 'default'
326
+ ? {
327
+ variantId: variant._id,
328
+ preOrderRequested: !!variant?.inventoryStatus?.preorderEnabled,
329
+ }
330
+ : undefined,
219
331
  };
220
332
  // Transform and add modifiers to catalog reference if they exist
221
333
  if (modifiers && Object.keys(modifiers).length > 0) {
@@ -225,19 +337,19 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
225
337
  const productModifiers = prod.modifiers || [];
226
338
  Object.values(modifiers).forEach((modifierValue) => {
227
339
  const modifierName = modifierValue.modifierName;
228
- const productModifier = productModifiers.find((m) => m.name === modifierName);
340
+ const productModifier = productModifiers.find(m => m.name === modifierName);
229
341
  if (!productModifier)
230
342
  return;
231
343
  const renderType = productModifier.modifierRenderType;
232
- if (renderType === "TEXT_CHOICES" ||
233
- renderType === "SWATCH_CHOICES") {
344
+ if (renderType === ModifierRenderType.TEXT_CHOICES ||
345
+ renderType === ModifierRenderType.SWATCH_CHOICES) {
234
346
  // For choice modifiers, use the modifier key and choice value
235
347
  const modifierKey = productModifier.key || modifierName;
236
348
  if (modifierValue.choiceValue) {
237
349
  options[modifierKey] = modifierValue.choiceValue;
238
350
  }
239
351
  }
240
- else if (renderType === "FREE_TEXT") {
352
+ else if (renderType === ModifierRenderType.FREE_TEXT) {
241
353
  // For free text modifiers, use the freeTextSettings key
242
354
  const freeTextKey = productModifier.freeTextSettings?.key || modifierName;
243
355
  if (modifierValue.freeTextValue) {
@@ -259,17 +371,16 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
259
371
  };
260
372
  }
261
373
  }
262
- // @ts-ignore
263
- const lineItems = [
264
- {
265
- catalogReference,
266
- quantity,
267
- },
268
- ];
374
+ // const lineItems = [
375
+ // {
376
+ // catalogReference,
377
+ // quantity,
378
+ // },
379
+ // ];
269
380
  // await cartService.addToCart(lineItems);
270
381
  }
271
382
  catch (err) {
272
- error.set(err instanceof Error ? err.message : "Failed to add to cart");
383
+ error.set(err instanceof Error ? err.message : 'Failed to add to cart');
273
384
  }
274
385
  finally {
275
386
  isLoading.set(false);
@@ -282,21 +393,33 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
282
393
  };
283
394
  const selectVariantById = (id) => {
284
395
  const variantsList = variants.get();
285
- const variant = variantsList.find((v) => v._id === id);
396
+ const variant = variantsList.find(v => v._id === id);
286
397
  if (variant) {
287
398
  const variantChoices = processVariantChoices(variant);
288
399
  selectedChoices.set(variantChoices);
289
- updateQuantityFromVariant(variant);
290
- }
291
- };
292
- const loadProductVariants = (data) => {
293
- variants.set(data);
294
- if (data.length > 0) {
295
- updateQuantityFromVariant(data[0] || null);
400
+ updateDataFromVariant(variant);
296
401
  }
297
402
  };
298
403
  const resetSelections = () => {
299
404
  selectedChoices.set({});
405
+ selectedQuantity.set(1); // Reset quantity when resetting selections
406
+ };
407
+ // Quantity management methods
408
+ const setSelectedQuantity = (quantity) => {
409
+ const maxQuantity = quantityAvailable.get();
410
+ const validQuantity = Math.max(1, Math.min(quantity, maxQuantity || 999));
411
+ selectedQuantity.set(validQuantity);
412
+ };
413
+ const incrementQuantity = () => {
414
+ const current = selectedQuantity.get();
415
+ const maxQuantity = quantityAvailable.get();
416
+ const newQuantity = Math.min(current + 1, maxQuantity || 999);
417
+ selectedQuantity.set(newQuantity);
418
+ };
419
+ const decrementQuantity = () => {
420
+ const current = selectedQuantity.get();
421
+ const newQuantity = Math.max(1, current - 1);
422
+ selectedQuantity.set(newQuantity);
300
423
  };
301
424
  // New methods for smart variant selection
302
425
  const getAvailableChoicesForOption = (optionName) => {
@@ -304,7 +427,7 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
304
427
  const variantsList = variants.get();
305
428
  // Get all possible choices for this option that result in valid variants
306
429
  const availableChoices = new Set();
307
- variantsList.forEach((variant) => {
430
+ variantsList.forEach(variant => {
308
431
  const variantChoices = processVariantChoices(variant);
309
432
  // Check if this variant matches all currently selected choices (except for the option we're checking)
310
433
  const matchesOtherChoices = Object.entries(currentChoices)
@@ -316,14 +439,57 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
316
439
  });
317
440
  return Array.from(availableChoices);
318
441
  };
442
+ // Core method that provides both availability and stock info efficiently
443
+ const getChoiceInfo = (optionName, choiceValue) => {
444
+ // Create hypothetical choices with this choice selected
445
+ const currentChoices = selectedChoices.get();
446
+ const hypotheticalChoices = {
447
+ ...currentChoices,
448
+ [optionName]: choiceValue,
449
+ };
450
+ // Get all variants and find one that matches these choices
451
+ const variantsList = variants.get();
452
+ const matchingVariants = variantsList.filter(variant => {
453
+ if (!variant.choices)
454
+ return false;
455
+ const variantChoices = {};
456
+ for (const choice of variant.choices) {
457
+ if (choice.optionChoiceNames?.optionName &&
458
+ choice.optionChoiceNames?.choiceName) {
459
+ variantChoices[choice.optionChoiceNames.optionName] =
460
+ choice.optionChoiceNames.choiceName;
461
+ }
462
+ }
463
+ // Check if this variant matches our hypothetical choices
464
+ return Object.entries(hypotheticalChoices).every(([key, value]) => variantChoices[key] === value);
465
+ });
466
+ const isAvailable = matchingVariants.length > 0;
467
+ // Check if ANY of the matching variants are in stock
468
+ const isInStock = matchingVariants.some(variant => variant.inventoryStatus?.inStock === true);
469
+ // Check if ANY of the matching variants have pre-order enabled
470
+ const isPreOrderEnabled = matchingVariants.some(variant => variant.inventoryStatus?.preorderEnabled === true);
471
+ return { isAvailable, isInStock, isPreOrderEnabled };
472
+ };
473
+ // Simplified methods using the core getChoiceInfo
319
474
  const isChoiceAvailable = (optionName, choiceValue) => {
320
- const availableChoices = getAvailableChoicesForOption(optionName);
321
- return availableChoices.includes(choiceValue);
475
+ return getChoiceInfo(optionName, choiceValue).isAvailable;
476
+ };
477
+ const isChoiceInStock = (optionName, choiceValue) => {
478
+ return getChoiceInfo(optionName, choiceValue).isInStock;
479
+ };
480
+ const isChoicePreOrderEnabled = (optionName, choiceValue) => {
481
+ return getChoiceInfo(optionName, choiceValue).isPreOrderEnabled;
322
482
  };
323
483
  const hasAnySelections = () => {
324
484
  const currentChoices = selectedChoices.get();
325
485
  return Object.keys(currentChoices).length > 0;
326
486
  };
487
+ const IsAllVariantsAreOutOfStock = () => {
488
+ const variantsList = variants.get();
489
+ // All variants must be out of stock AND none should have preorder enabled
490
+ return (variantsList?.every(variant => !variant.inventoryStatus?.inStock &&
491
+ !variant.inventoryStatus?.preorderEnabled) ?? true);
492
+ };
327
493
  return {
328
494
  selectedChoices,
329
495
  selectedVariantId,
@@ -332,6 +498,7 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
332
498
  currentCompareAtPrice,
333
499
  isInStock,
334
500
  isPreOrderEnabled,
501
+ preOrderMessage,
335
502
  isLoading,
336
503
  error,
337
504
  variants,
@@ -340,53 +507,32 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
340
507
  discountPrice,
341
508
  isOnSale,
342
509
  quantityAvailable,
510
+ trackQuantity,
511
+ selectedQuantity,
343
512
  productId,
344
- sku,
345
513
  ribbonLabel,
346
514
  setSelectedChoices,
347
515
  addToCart,
348
516
  setOption,
349
517
  selectVariantById,
350
- loadProductVariants,
351
518
  resetSelections,
352
519
  // New methods for smart variant selection
353
520
  getAvailableChoicesForOption,
521
+ getChoiceInfo,
354
522
  isChoiceAvailable,
523
+ isChoiceInStock,
524
+ isChoicePreOrderEnabled,
355
525
  hasAnySelections,
526
+ // Quantity management methods
527
+ setSelectedQuantity,
528
+ incrementQuantity,
529
+ decrementQuantity,
356
530
  selectedVariant,
357
531
  finalPrice,
358
532
  isLowStock,
359
533
  product,
360
534
  productOptions,
361
535
  currency,
536
+ IsAllVariantsAreOutOfStock,
362
537
  };
363
538
  });
364
- export async function loadSelectedVariantServiceConfig(productSlug) {
365
- try {
366
- // Use getProductBySlug directly - single API call with comprehensive fields
367
- const productResponse = await productsV3.getProductBySlug(productSlug, {
368
- fields: [
369
- "DESCRIPTION",
370
- "DIRECT_CATEGORIES_INFO",
371
- "BREADCRUMBS_INFO",
372
- "INFO_SECTION",
373
- "MEDIA_ITEMS_INFO",
374
- "PLAIN_DESCRIPTION",
375
- "THUMBNAIL",
376
- "URL",
377
- "VARIANT_OPTION_CHOICE_NAMES",
378
- "WEIGHT_MEASUREMENT_UNIT_INFO",
379
- ],
380
- });
381
- if (!productResponse.product) {
382
- throw new Error("Product not found");
383
- }
384
- return {
385
- product: productResponse.product,
386
- };
387
- }
388
- catch (error) {
389
- console.error(`Failed to load product for slug "${productSlug}":`, error);
390
- throw error;
391
- }
392
- }
@@ -1,5 +1,5 @@
1
- import { type ServiceFactoryConfig } from "@wix/services-definitions";
2
- import type { Signal } from "./Signal";
1
+ import { type ServiceFactoryConfig } from '@wix/services-definitions';
2
+ import type { Signal } from '../../Signal';
3
3
  export interface SharingPlatform {
4
4
  name: string;
5
5
  icon: string;