@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.
- package/cjs/dist/enums/index.d.ts +2 -0
- package/cjs/dist/enums/index.js +18 -0
- package/cjs/dist/enums/social-platform-enums.d.ts +25 -0
- package/cjs/dist/enums/social-platform-enums.js +30 -0
- package/cjs/dist/enums/sort-enums.d.ts +17 -0
- package/cjs/dist/enums/sort-enums.js +21 -0
- package/cjs/dist/react/BuyNow.d.ts +2 -4
- package/cjs/dist/react/Category.d.ts +9 -11
- package/cjs/dist/react/Category.js +8 -23
- package/cjs/dist/react/Collection.d.ts +13 -3
- package/cjs/dist/react/Collection.js +30 -19
- package/cjs/dist/react/FilteredCollection.d.ts +46 -15
- package/cjs/dist/react/FilteredCollection.js +45 -12
- package/cjs/dist/react/PayNow.d.ts +2 -4
- package/cjs/dist/react/Product.d.ts +8 -35
- package/cjs/dist/react/Product.js +10 -31
- package/cjs/dist/react/ProductActions.d.ts +42 -0
- package/cjs/dist/react/ProductActions.js +83 -0
- package/cjs/dist/react/ProductModifiers.d.ts +16 -8
- package/cjs/dist/react/ProductModifiers.js +19 -10
- package/cjs/dist/react/ProductVariantSelector.d.ts +52 -68
- package/cjs/dist/react/ProductVariantSelector.js +58 -86
- package/cjs/dist/react/RelatedProducts.d.ts +8 -4
- package/cjs/dist/react/RelatedProducts.js +12 -7
- package/cjs/dist/react/SelectedVariant.d.ts +66 -0
- package/cjs/dist/react/SelectedVariant.js +52 -0
- package/cjs/dist/react/SocialSharing.d.ts +24 -30
- package/cjs/dist/react/SocialSharing.js +8 -2
- package/cjs/dist/react/Sort.d.ts +12 -15
- package/cjs/dist/react/Sort.js +11 -34
- package/cjs/dist/react/index.d.ts +11 -10
- package/cjs/dist/react/index.js +3 -2
- package/cjs/dist/services/buy-now-service.js +2 -2
- package/cjs/dist/services/catalog-options-service.d.ts +2 -2
- package/cjs/dist/services/catalog-options-service.js +39 -45
- package/cjs/dist/services/catalog-price-range-service.d.ts +2 -2
- package/cjs/dist/services/catalog-price-range-service.js +13 -11
- package/cjs/dist/services/category-service.d.ts +7 -6
- package/cjs/dist/services/category-service.js +15 -11
- package/cjs/dist/services/collection-service.d.ts +8 -8
- package/cjs/dist/services/collection-service.js +182 -67
- package/cjs/dist/services/filter-service.d.ts +1 -1
- package/cjs/dist/services/filter-service.js +15 -23
- package/cjs/dist/services/product-media-gallery-service.d.ts +3 -3
- package/cjs/dist/services/product-modifiers-service.d.ts +6 -8
- package/cjs/dist/services/product-modifiers-service.js +14 -7
- package/cjs/dist/services/product-service.d.ts +8 -7
- package/cjs/dist/services/product-service.js +36 -19
- package/cjs/dist/services/related-products-service.d.ts +4 -4
- package/cjs/dist/services/related-products-service.js +4 -4
- package/cjs/dist/services/selected-variant-service.d.ts +24 -16
- package/cjs/dist/services/selected-variant-service.js +271 -126
- package/cjs/dist/services/social-sharing-service.d.ts +2 -2
- package/cjs/dist/services/social-sharing-service.js +47 -63
- package/cjs/dist/services/sort-service.d.ts +3 -2
- package/cjs/dist/services/sort-service.js +8 -13
- package/dist/enums/index.d.ts +2 -0
- package/dist/enums/index.js +2 -0
- package/dist/enums/social-platform-enums.d.ts +25 -0
- package/dist/enums/social-platform-enums.js +27 -0
- package/dist/enums/sort-enums.d.ts +17 -0
- package/dist/enums/sort-enums.js +18 -0
- package/dist/react/BuyNow.d.ts +2 -4
- package/dist/react/Category.d.ts +9 -11
- package/dist/react/Category.js +10 -23
- package/dist/react/Collection.d.ts +13 -3
- package/dist/react/Collection.js +32 -21
- package/dist/react/FilteredCollection.d.ts +46 -15
- package/dist/react/FilteredCollection.js +49 -16
- package/dist/react/PayNow.d.ts +2 -4
- package/dist/react/Product.d.ts +8 -35
- package/dist/react/Product.js +11 -31
- package/dist/react/ProductActions.d.ts +42 -0
- package/dist/react/ProductActions.js +79 -0
- package/dist/react/ProductModifiers.d.ts +16 -8
- package/dist/react/ProductModifiers.js +22 -13
- package/dist/react/ProductVariantSelector.d.ts +52 -68
- package/dist/react/ProductVariantSelector.js +57 -84
- package/dist/react/RelatedProducts.d.ts +8 -4
- package/dist/react/RelatedProducts.js +15 -10
- package/dist/react/SelectedVariant.d.ts +66 -0
- package/dist/react/SelectedVariant.js +46 -0
- package/dist/react/SocialSharing.d.ts +24 -30
- package/dist/react/SocialSharing.js +11 -5
- package/dist/react/Sort.d.ts +12 -15
- package/dist/react/Sort.js +13 -34
- package/dist/react/index.d.ts +11 -10
- package/dist/react/index.js +11 -10
- package/dist/services/buy-now-service.js +2 -2
- package/dist/services/catalog-options-service.d.ts +2 -2
- package/dist/services/catalog-options-service.js +41 -47
- package/dist/services/catalog-price-range-service.d.ts +2 -2
- package/dist/services/catalog-price-range-service.js +15 -13
- package/dist/services/category-service.d.ts +7 -6
- package/dist/services/category-service.js +17 -13
- package/dist/services/collection-service.d.ts +8 -8
- package/dist/services/collection-service.js +188 -73
- package/dist/services/filter-service.d.ts +1 -1
- package/dist/services/filter-service.js +20 -28
- package/dist/services/product-media-gallery-service.d.ts +3 -3
- package/dist/services/product-modifiers-service.d.ts +6 -8
- package/dist/services/product-modifiers-service.js +16 -9
- package/dist/services/product-service.d.ts +8 -7
- package/dist/services/product-service.js +38 -21
- package/dist/services/related-products-service.d.ts +4 -4
- package/dist/services/related-products-service.js +6 -6
- package/dist/services/selected-variant-service.d.ts +24 -16
- package/dist/services/selected-variant-service.js +273 -127
- package/dist/services/social-sharing-service.d.ts +2 -2
- package/dist/services/social-sharing-service.js +49 -65
- package/dist/services/sort-service.d.ts +3 -2
- package/dist/services/sort-service.js +11 -16
- package/package.json +7 -1
- package/cjs/dist/react/ProductMediaGallery.d.ts +0 -128
- package/cjs/dist/react/ProductMediaGallery.js +0 -100
- package/dist/astro/BuyNowServiceContext.d.ts +0 -2
- package/dist/astro/BuyNowServiceContext.js +0 -6
- package/dist/astro/ManagerProviderContext.d.ts +0 -2
- package/dist/astro/ManagerProviderContext.js +0 -7
- package/dist/astro/withBuyButtonService.d.ts +0 -2
- package/dist/astro/withBuyButtonService.js +0 -16
- package/dist/react/CurrentCartServiceProvider.d.ts +0 -5
- package/dist/react/CurrentCartServiceProvider.js +0 -12
- package/dist/react/ProductMediaGallery.d.ts +0 -128
- package/dist/react/ProductMediaGallery.js +0 -92
- package/dist/react/VariantSelectorServiceProvider.d.ts +0 -7
- package/dist/react/VariantSelectorServiceProvider.js +0 -22
- package/dist/react/hookim/index.d.ts +0 -5
- package/dist/react/hookim/index.js +0 -22
- package/dist/services/CurrentCartService.d.ts +0 -18
- package/dist/services/CurrentCartService.js +0 -9
- package/dist/services/VariantSelectorServices.d.ts +0 -8
- package/dist/services/VariantSelectorServices.js +0 -20
|
@@ -1,11 +1,46 @@
|
|
|
1
|
-
import { defineService, implementService
|
|
2
|
-
import { SignalsServiceDefinition } from
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
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
|
|
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(
|
|
64
|
+
return (variants.find(variant => {
|
|
30
65
|
const variantChoices = processVariantChoices(variant);
|
|
31
66
|
const choiceKeys = Object.keys(selectedChoices);
|
|
32
|
-
return choiceKeys.every(
|
|
67
|
+
return choiceKeys.every(key => variantChoices[key] === selectedChoices[key]);
|
|
33
68
|
}) || null);
|
|
34
69
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
//
|
|
44
|
-
|
|
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(
|
|
59
|
-
const
|
|
60
|
-
const
|
|
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(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
192
|
+
const variantsList = variants.get();
|
|
193
|
+
if (!variantsList || variantsList.length === 0)
|
|
110
194
|
return null;
|
|
111
|
-
return (
|
|
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 ||
|
|
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(
|
|
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
|
-
|
|
197
|
-
|
|
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
|
-
|
|
310
|
+
updateDataFromVariant(matchingVariant);
|
|
204
311
|
};
|
|
205
|
-
const addToCart = async (
|
|
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(
|
|
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:
|
|
218
|
-
options: variant?._id
|
|
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(
|
|
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 ===
|
|
233
|
-
renderType ===
|
|
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 ===
|
|
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
|
-
//
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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 :
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
321
|
-
|
|
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
|
|
2
|
-
import type { Signal } from
|
|
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;
|