@jay-framework/wix-stores-v1 0.15.0
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/README.md +150 -0
- package/dist/actions/get-collections.jay-action +12 -0
- package/dist/actions/get-product-by-slug.jay-action +10 -0
- package/dist/actions/search-products.jay-action +32 -0
- package/dist/contracts/category-list.jay-contract +55 -0
- package/dist/contracts/category-list.jay-contract.d.ts +41 -0
- package/dist/contracts/category-page.jay-contract +199 -0
- package/dist/contracts/category-page.jay-contract.d.ts +125 -0
- package/dist/contracts/media-gallery.jay-contract +22 -0
- package/dist/contracts/media-gallery.jay-contract.d.ts +53 -0
- package/dist/contracts/media.jay-contract +5 -0
- package/dist/contracts/media.jay-contract.d.ts +25 -0
- package/dist/contracts/product-card.jay-contract +177 -0
- package/dist/contracts/product-card.jay-contract.d.ts +119 -0
- package/dist/contracts/product-options.jay-contract +66 -0
- package/dist/contracts/product-options.jay-contract.d.ts +57 -0
- package/dist/contracts/product-page.jay-contract +151 -0
- package/dist/contracts/product-page.jay-contract.d.ts +218 -0
- package/dist/contracts/product-search.jay-contract +240 -0
- package/dist/contracts/product-search.jay-contract.d.ts +165 -0
- package/dist/index.client.js +799 -0
- package/dist/index.d.ts +1037 -0
- package/dist/index.js +853 -0
- package/package.json +65 -0
- package/plugin.yaml +31 -0
|
@@ -0,0 +1,799 @@
|
|
|
1
|
+
import { WIX_CART_CONTEXT, cartIndicator, cartPage } from "@jay-framework/wix-cart/client";
|
|
2
|
+
import { makeJayStackComponent, makeJayInit } from "@jay-framework/fullstack-component";
|
|
3
|
+
import { registerReactiveGlobalContext, createSignal, createMemo, createEffect } from "@jay-framework/component";
|
|
4
|
+
import { patch, REPLACE } from "@jay-framework/json-patch";
|
|
5
|
+
import { createJayContext, useGlobalContext } from "@jay-framework/runtime";
|
|
6
|
+
import { WIX_CLIENT_CONTEXT } from "@jay-framework/wix-server-client/client";
|
|
7
|
+
import { WIX_CART_CONTEXT as WIX_CART_CONTEXT2 } from "@jay-framework/wix-cart";
|
|
8
|
+
import { products, collections } from "@wix/stores";
|
|
9
|
+
import { createActionCaller } from "@jay-framework/stack-client-runtime";
|
|
10
|
+
var StockStatus = /* @__PURE__ */ ((StockStatus2) => {
|
|
11
|
+
StockStatus2[StockStatus2["OUT_OF_STOCK"] = 0] = "OUT_OF_STOCK";
|
|
12
|
+
StockStatus2[StockStatus2["IN_STOCK"] = 1] = "IN_STOCK";
|
|
13
|
+
return StockStatus2;
|
|
14
|
+
})(StockStatus || {});
|
|
15
|
+
var Selected = /* @__PURE__ */ ((Selected2) => {
|
|
16
|
+
Selected2[Selected2["selected"] = 0] = "selected";
|
|
17
|
+
Selected2[Selected2["notSelected"] = 1] = "notSelected";
|
|
18
|
+
return Selected2;
|
|
19
|
+
})(Selected || {});
|
|
20
|
+
const instances = {
|
|
21
|
+
productsClientInstance: void 0,
|
|
22
|
+
collectionsClientInstance: void 0
|
|
23
|
+
};
|
|
24
|
+
function getProductsClient(wixClient) {
|
|
25
|
+
if (!instances.productsClientInstance) {
|
|
26
|
+
instances.productsClientInstance = wixClient.use(products);
|
|
27
|
+
}
|
|
28
|
+
return instances.productsClientInstance;
|
|
29
|
+
}
|
|
30
|
+
function getCollectionsClient(wixClient) {
|
|
31
|
+
if (!instances.collectionsClientInstance) {
|
|
32
|
+
instances.collectionsClientInstance = wixClient.use(collections);
|
|
33
|
+
}
|
|
34
|
+
return instances.collectionsClientInstance;
|
|
35
|
+
}
|
|
36
|
+
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
37
|
+
MediaType2[MediaType2["IMAGE"] = 0] = "IMAGE";
|
|
38
|
+
MediaType2[MediaType2["VIDEO"] = 1] = "VIDEO";
|
|
39
|
+
return MediaType2;
|
|
40
|
+
})(MediaType || {});
|
|
41
|
+
var AvailabilityStatus = /* @__PURE__ */ ((AvailabilityStatus2) => {
|
|
42
|
+
AvailabilityStatus2[AvailabilityStatus2["IN_STOCK"] = 0] = "IN_STOCK";
|
|
43
|
+
AvailabilityStatus2[AvailabilityStatus2["OUT_OF_STOCK"] = 1] = "OUT_OF_STOCK";
|
|
44
|
+
AvailabilityStatus2[AvailabilityStatus2["PARTIALLY_OUT_OF_STOCK"] = 2] = "PARTIALLY_OUT_OF_STOCK";
|
|
45
|
+
return AvailabilityStatus2;
|
|
46
|
+
})(AvailabilityStatus || {});
|
|
47
|
+
var PreorderStatus = /* @__PURE__ */ ((PreorderStatus2) => {
|
|
48
|
+
PreorderStatus2[PreorderStatus2["ENABLED"] = 0] = "ENABLED";
|
|
49
|
+
PreorderStatus2[PreorderStatus2["DISABLED"] = 1] = "DISABLED";
|
|
50
|
+
PreorderStatus2[PreorderStatus2["PARTIALLY_ENABLED"] = 2] = "PARTIALLY_ENABLED";
|
|
51
|
+
return PreorderStatus2;
|
|
52
|
+
})(PreorderStatus || {});
|
|
53
|
+
var ProductType = /* @__PURE__ */ ((ProductType2) => {
|
|
54
|
+
ProductType2[ProductType2["PHYSICAL"] = 0] = "PHYSICAL";
|
|
55
|
+
ProductType2[ProductType2["DIGITAL"] = 1] = "DIGITAL";
|
|
56
|
+
return ProductType2;
|
|
57
|
+
})(ProductType || {});
|
|
58
|
+
var QuickAddType = /* @__PURE__ */ ((QuickAddType2) => {
|
|
59
|
+
QuickAddType2[QuickAddType2["SIMPLE"] = 0] = "SIMPLE";
|
|
60
|
+
QuickAddType2[QuickAddType2["SINGLE_OPTION"] = 1] = "SINGLE_OPTION";
|
|
61
|
+
QuickAddType2[QuickAddType2["NEEDS_CONFIGURATION"] = 2] = "NEEDS_CONFIGURATION";
|
|
62
|
+
return QuickAddType2;
|
|
63
|
+
})(QuickAddType || {});
|
|
64
|
+
var OptionRenderType = /* @__PURE__ */ ((OptionRenderType2) => {
|
|
65
|
+
OptionRenderType2[OptionRenderType2["TEXT_CHOICES"] = 0] = "TEXT_CHOICES";
|
|
66
|
+
OptionRenderType2[OptionRenderType2["COLOR_SWATCH_CHOICES"] = 1] = "COLOR_SWATCH_CHOICES";
|
|
67
|
+
return OptionRenderType2;
|
|
68
|
+
})(OptionRenderType || {});
|
|
69
|
+
var ChoiceType = /* @__PURE__ */ ((ChoiceType2) => {
|
|
70
|
+
ChoiceType2[ChoiceType2["CHOICE_TEXT"] = 0] = "CHOICE_TEXT";
|
|
71
|
+
ChoiceType2[ChoiceType2["ONE_COLOR"] = 1] = "ONE_COLOR";
|
|
72
|
+
return ChoiceType2;
|
|
73
|
+
})(ChoiceType || {});
|
|
74
|
+
function mapAvailabilityStatus(status) {
|
|
75
|
+
switch (status) {
|
|
76
|
+
case "OUT_OF_STOCK":
|
|
77
|
+
return AvailabilityStatus.OUT_OF_STOCK;
|
|
78
|
+
case "PARTIALLY_OUT_OF_STOCK":
|
|
79
|
+
return AvailabilityStatus.PARTIALLY_OUT_OF_STOCK;
|
|
80
|
+
default:
|
|
81
|
+
return AvailabilityStatus.IN_STOCK;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function mapPreorderStatus() {
|
|
85
|
+
return PreorderStatus.DISABLED;
|
|
86
|
+
}
|
|
87
|
+
function mapMediaType(mediaType) {
|
|
88
|
+
return mediaType === "video" ? MediaType.VIDEO : MediaType.IMAGE;
|
|
89
|
+
}
|
|
90
|
+
function mapProductType(productType) {
|
|
91
|
+
return productType === "digital" ? ProductType.DIGITAL : ProductType.PHYSICAL;
|
|
92
|
+
}
|
|
93
|
+
function hasProductDiscount(product) {
|
|
94
|
+
const price = product.price?.price || 0;
|
|
95
|
+
const discountedPrice = product.price?.discountedPrice || price;
|
|
96
|
+
return discountedPrice < price;
|
|
97
|
+
}
|
|
98
|
+
function getQuickAddType(product) {
|
|
99
|
+
const optionCount = product.productOptions?.length ?? 0;
|
|
100
|
+
if (optionCount > 1) {
|
|
101
|
+
return QuickAddType.NEEDS_CONFIGURATION;
|
|
102
|
+
}
|
|
103
|
+
if (optionCount === 1) {
|
|
104
|
+
return QuickAddType.SINGLE_OPTION;
|
|
105
|
+
}
|
|
106
|
+
return QuickAddType.SIMPLE;
|
|
107
|
+
}
|
|
108
|
+
function mapOptionRenderType(optionType) {
|
|
109
|
+
return optionType === "color" ? OptionRenderType.COLOR_SWATCH_CHOICES : OptionRenderType.TEXT_CHOICES;
|
|
110
|
+
}
|
|
111
|
+
function mapQuickOption(option, variants) {
|
|
112
|
+
if (!option) return null;
|
|
113
|
+
const choices = option.choices || [];
|
|
114
|
+
return {
|
|
115
|
+
_id: option.name,
|
|
116
|
+
name: option.name || "",
|
|
117
|
+
optionRenderType: mapOptionRenderType(option.optionType),
|
|
118
|
+
choices: choices.map((choice) => {
|
|
119
|
+
const variant = variants?.find((v) => Object.values(v.choices).includes(choice.value));
|
|
120
|
+
return {
|
|
121
|
+
choiceId: choice.description,
|
|
122
|
+
name: choice.value || "",
|
|
123
|
+
choiceType: option.optionType === "color" ? ChoiceType.ONE_COLOR : ChoiceType.CHOICE_TEXT,
|
|
124
|
+
colorCode: "",
|
|
125
|
+
// V1 doesn't store color code in choices
|
|
126
|
+
inStock: variant?.stock?.inStock ?? choice.inStock ?? true,
|
|
127
|
+
variantId: variant?._id || "",
|
|
128
|
+
isSelected: false
|
|
129
|
+
};
|
|
130
|
+
})
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const DEFAULT_PRODUCT_PAGE_PATH = "/products";
|
|
134
|
+
function mapProductToCard(product, productPagePath = DEFAULT_PRODUCT_PAGE_PATH) {
|
|
135
|
+
const mainMedia = product.media?.mainMedia;
|
|
136
|
+
const slug = product.slug || "";
|
|
137
|
+
product.price?.discountedPrice ?? product.price?.price ?? 0;
|
|
138
|
+
product.price?.price ?? 0;
|
|
139
|
+
const formattedActualPrice = product.price?.formatted?.discountedPrice || "";
|
|
140
|
+
const formattedCompareAtPrice = product.price?.formatted?.price || "";
|
|
141
|
+
const hasDiscount = hasProductDiscount(product);
|
|
142
|
+
console.log("product", product.name, product.slug);
|
|
143
|
+
return {
|
|
144
|
+
_id: product._id || "",
|
|
145
|
+
name: product.name || "",
|
|
146
|
+
slug,
|
|
147
|
+
productUrl: slug ? `${productPagePath}/${slug}` : "",
|
|
148
|
+
mainMedia: {
|
|
149
|
+
// V1 provides complete URLs
|
|
150
|
+
url: mainMedia?.image?.url || "",
|
|
151
|
+
altText: mainMedia?.title || product.name || "",
|
|
152
|
+
mediaType: mapMediaType(mainMedia?.mediaType)
|
|
153
|
+
},
|
|
154
|
+
thumbnail: {
|
|
155
|
+
// V1 provides complete thumbnail URLs
|
|
156
|
+
url: mainMedia?.thumbnail?.url || "",
|
|
157
|
+
altText: mainMedia?.title || product.name || "",
|
|
158
|
+
width: mainMedia?.thumbnail?.width || 300,
|
|
159
|
+
height: mainMedia?.thumbnail?.height || 300
|
|
160
|
+
},
|
|
161
|
+
// Simplified price fields
|
|
162
|
+
price: formattedActualPrice,
|
|
163
|
+
strikethroughPrice: hasDiscount ? formattedCompareAtPrice : "",
|
|
164
|
+
hasDiscount,
|
|
165
|
+
inventory: {
|
|
166
|
+
// V1 uses stock.inventoryStatus
|
|
167
|
+
availabilityStatus: mapAvailabilityStatus(product.stock?.inventoryStatus),
|
|
168
|
+
preorderStatus: mapPreorderStatus()
|
|
169
|
+
},
|
|
170
|
+
ribbon: {
|
|
171
|
+
_id: product.ribbon || "",
|
|
172
|
+
name: product.ribbon || ""
|
|
173
|
+
},
|
|
174
|
+
hasRibbon: !!product.ribbon,
|
|
175
|
+
brand: {
|
|
176
|
+
_id: product.brand || "",
|
|
177
|
+
name: product.brand || ""
|
|
178
|
+
},
|
|
179
|
+
productType: mapProductType(product.productType),
|
|
180
|
+
isAddingToCart: false,
|
|
181
|
+
// Quick add behavior
|
|
182
|
+
quickAddType: getQuickAddType(product),
|
|
183
|
+
quickOption: getQuickAddType(product) === QuickAddType.SINGLE_OPTION ? mapQuickOption(product.productOptions?.[0], product.variants) : null
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function mapCollectionToViewState(collection) {
|
|
187
|
+
return {
|
|
188
|
+
_id: collection._id,
|
|
189
|
+
name: collection.name || "",
|
|
190
|
+
slug: collection.slug || "",
|
|
191
|
+
description: collection.description || "",
|
|
192
|
+
imageUrl: collection.media?.mainMedia?.image?.url || "",
|
|
193
|
+
productCount: collection.numberOfProducts || 0
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const WIX_STORES_V1_CONTEXT = createJayContext();
|
|
197
|
+
function provideWixStoresV1Context() {
|
|
198
|
+
const wixClientContext = useGlobalContext(WIX_CLIENT_CONTEXT);
|
|
199
|
+
const wixClient = wixClientContext.client;
|
|
200
|
+
const cartContext = useGlobalContext(WIX_CART_CONTEXT2);
|
|
201
|
+
const productsClient = getProductsClient(wixClient);
|
|
202
|
+
const collectionsClient = getCollectionsClient(wixClient);
|
|
203
|
+
const storesContext = registerReactiveGlobalContext(WIX_STORES_V1_CONTEXT, () => {
|
|
204
|
+
async function addToCart(productId, quantity = 1, variantId) {
|
|
205
|
+
console.log(`[WixStoresV1] Adding to cart: ${productId} x ${quantity}`);
|
|
206
|
+
let finalVariantId = variantId;
|
|
207
|
+
let productSlug;
|
|
208
|
+
try {
|
|
209
|
+
const productResult = await productsClient.getProduct(productId);
|
|
210
|
+
const product = productResult.product;
|
|
211
|
+
productSlug = product?.slug;
|
|
212
|
+
if (!finalVariantId && product?.variants?.[0]) {
|
|
213
|
+
finalVariantId = product.variants[0]._id;
|
|
214
|
+
}
|
|
215
|
+
} catch (err) {
|
|
216
|
+
console.warn("[WixStoresV1] Could not fetch product:", err);
|
|
217
|
+
}
|
|
218
|
+
return cartContext.addToCart(productId, quantity, {
|
|
219
|
+
variantId: finalVariantId,
|
|
220
|
+
productSlug
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
async function loadMoreCollectionProducts(collectionId, page, pageSize) {
|
|
224
|
+
try {
|
|
225
|
+
const result = await productsClient.queryProducts().hasSome("collectionIds", [collectionId]).skip((page - 1) * pageSize).limit(pageSize).find();
|
|
226
|
+
const products2 = (result.items || []).map((p) => mapProductToCard(p));
|
|
227
|
+
const totalProducts = result.totalCount ?? products2.length;
|
|
228
|
+
const hasMore = page * pageSize < totalProducts;
|
|
229
|
+
return { products: products2, hasMore, totalProducts };
|
|
230
|
+
} catch (error) {
|
|
231
|
+
console.error("[WixStoresV1] Failed to load collection products:", error);
|
|
232
|
+
return { products: [], hasMore: false, totalProducts: 0 };
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
async function getCollections() {
|
|
236
|
+
try {
|
|
237
|
+
const result = await collectionsClient.queryCollections().find();
|
|
238
|
+
return (result.items || []).map((col) => mapCollectionToViewState(col));
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error("[WixStoresV1] Failed to load collections:", error);
|
|
241
|
+
return [];
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
// Delegate cart indicator and operations to WIX_CART_CONTEXT
|
|
246
|
+
cartIndicator: cartContext.cartIndicator,
|
|
247
|
+
refreshCartIndicator: () => cartContext.refreshCartIndicator(),
|
|
248
|
+
getEstimatedCart: () => cartContext.getEstimatedCart(),
|
|
249
|
+
addToCart,
|
|
250
|
+
// Custom implementation that resolves V1 variants first
|
|
251
|
+
removeLineItems: (ids) => cartContext.removeLineItems(ids),
|
|
252
|
+
updateLineItemQuantity: (id, qty) => cartContext.updateLineItemQuantity(id, qty),
|
|
253
|
+
clearCart: () => cartContext.clearCart(),
|
|
254
|
+
applyCoupon: (code) => cartContext.applyCoupon(code),
|
|
255
|
+
removeCoupon: () => cartContext.removeCoupon(),
|
|
256
|
+
// V1-specific operations
|
|
257
|
+
loadMoreCollectionProducts,
|
|
258
|
+
getCollections
|
|
259
|
+
};
|
|
260
|
+
});
|
|
261
|
+
console.log("[wix-stores-v1] Client stores context initialized (delegating cart to wix-cart)");
|
|
262
|
+
return storesContext;
|
|
263
|
+
}
|
|
264
|
+
function ProductPageInteractive(props, refs, viewStateSignals, fastCarryForward, storesContext) {
|
|
265
|
+
const [quantity, setQuantity] = createSignal(viewStateSignals.quantity[0]().quantity);
|
|
266
|
+
const { productId, variants } = fastCarryForward;
|
|
267
|
+
const { actionsEnabled: [actionsEnabled, setActionsEnabled], options: [options, setOptions], mediaGallery: [mediaGallery, setMediaGallery], pricePerUnit: [pricePerUnit, setPricePerUnit] } = viewStateSignals;
|
|
268
|
+
const [isAddingToCart, setIsAddingToCart] = createSignal(false);
|
|
269
|
+
const [selectedMediaId, setSelectedMediaId] = createSignal(null);
|
|
270
|
+
const selectedOptionsRecord = createMemo(() => {
|
|
271
|
+
const result = {};
|
|
272
|
+
for (const option of options()) {
|
|
273
|
+
if (option.textChoiceSelection) {
|
|
274
|
+
result[option._id] = option.textChoiceSelection;
|
|
275
|
+
} else {
|
|
276
|
+
const selectedChoice = option.choices.find((c) => c.isSelected);
|
|
277
|
+
if (selectedChoice) {
|
|
278
|
+
result[option._id] = selectedChoice.choiceId;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return result;
|
|
283
|
+
});
|
|
284
|
+
function findVariant(variants2, selectedOptions) {
|
|
285
|
+
const found = variants2.find((variant) => Object.entries(selectedOptions).every(([optionName, choiceValue]) => variant.choices[optionName] === choiceValue));
|
|
286
|
+
return found || variants2[0];
|
|
287
|
+
}
|
|
288
|
+
const selectedVariant = createMemo(() => findVariant(variants, selectedOptionsRecord()));
|
|
289
|
+
const sku = createMemo(() => selectedVariant()?.sku || "");
|
|
290
|
+
const price = createMemo(() => selectedVariant()?.price || "");
|
|
291
|
+
const strikethroughPrice = createMemo(() => selectedVariant()?.strikethroughPrice || "");
|
|
292
|
+
const stockStatus = createMemo(() => selectedVariant()?.inventoryStatus || StockStatus.OUT_OF_STOCK);
|
|
293
|
+
const computedActionsEnabled = createMemo(() => stockStatus() === StockStatus.IN_STOCK);
|
|
294
|
+
const interactiveMedia = createMemo((prev) => {
|
|
295
|
+
prev = prev || mediaGallery();
|
|
296
|
+
const oldSelectedIndex = prev.availableMedia.findIndex((_) => _.selected === Selected.selected);
|
|
297
|
+
const newSelectedIndex = Math.max(0, prev.availableMedia.findIndex((_) => _.mediaId === selectedMediaId()));
|
|
298
|
+
if (oldSelectedIndex === newSelectedIndex)
|
|
299
|
+
return prev;
|
|
300
|
+
const newSelectedMedia = prev.availableMedia[newSelectedIndex];
|
|
301
|
+
return patch(prev, [
|
|
302
|
+
{ op: REPLACE, path: ["selectedMedia"], value: newSelectedMedia.media },
|
|
303
|
+
{
|
|
304
|
+
op: REPLACE,
|
|
305
|
+
path: ["availableMedia", oldSelectedIndex, "selected"],
|
|
306
|
+
value: Selected.notSelected
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
op: REPLACE,
|
|
310
|
+
path: ["availableMedia", newSelectedIndex, "selected"],
|
|
311
|
+
value: Selected.selected
|
|
312
|
+
}
|
|
313
|
+
]);
|
|
314
|
+
});
|
|
315
|
+
refs.quantity.decrementButton.onclick(() => {
|
|
316
|
+
setQuantity((prev) => Math.max(1, prev - 1));
|
|
317
|
+
});
|
|
318
|
+
refs.quantity.incrementButton.onclick(() => {
|
|
319
|
+
setQuantity((prev) => prev + 1);
|
|
320
|
+
});
|
|
321
|
+
refs.quantity.quantity.oninput(({ event }) => {
|
|
322
|
+
const value = parseInt(event.target.value, 10);
|
|
323
|
+
if (!isNaN(value) && value > 0) {
|
|
324
|
+
setQuantity(value);
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
refs.mediaGallery?.availableMedia?.selected?.onclick(({ coordinate }) => {
|
|
328
|
+
const mediaId = coordinate[0];
|
|
329
|
+
setSelectedMediaId(mediaId);
|
|
330
|
+
});
|
|
331
|
+
refs.options?.choices?.choiceButton?.onclick(({ coordinate }) => {
|
|
332
|
+
const [optionId, choiceId] = coordinate;
|
|
333
|
+
const optionIndex = options().findIndex((_) => _._id === optionId);
|
|
334
|
+
const option = options()[optionIndex];
|
|
335
|
+
const newChoiceIndex = option.choices.findIndex((_) => _.choiceId === choiceId);
|
|
336
|
+
const oldChoiceIndex = option.choices.findIndex((_) => _.isSelected);
|
|
337
|
+
const removeSelectedPatch = oldChoiceIndex > -1 && oldChoiceIndex !== newChoiceIndex ? [
|
|
338
|
+
{
|
|
339
|
+
op: REPLACE,
|
|
340
|
+
path: [optionIndex, "choices", oldChoiceIndex, "isSelected"],
|
|
341
|
+
value: false
|
|
342
|
+
}
|
|
343
|
+
] : [];
|
|
344
|
+
setOptions(patch(options(), [
|
|
345
|
+
{
|
|
346
|
+
op: REPLACE,
|
|
347
|
+
path: [optionIndex, "choices", newChoiceIndex, "isSelected"],
|
|
348
|
+
value: true
|
|
349
|
+
},
|
|
350
|
+
...removeSelectedPatch
|
|
351
|
+
]));
|
|
352
|
+
});
|
|
353
|
+
refs.options?.textChoice?.oninput(({ event, coordinate }) => {
|
|
354
|
+
const [optionId] = coordinate;
|
|
355
|
+
const optionIndex = options().findIndex((_) => _._id === optionId);
|
|
356
|
+
const selectedChoiceId = event.target.value;
|
|
357
|
+
setOptions(patch(options(), [
|
|
358
|
+
{
|
|
359
|
+
op: REPLACE,
|
|
360
|
+
path: [optionIndex, "textChoiceSelection"],
|
|
361
|
+
value: selectedChoiceId
|
|
362
|
+
}
|
|
363
|
+
]));
|
|
364
|
+
});
|
|
365
|
+
refs.addToCartButton.onclick(async () => {
|
|
366
|
+
if (stockStatus() === StockStatus.OUT_OF_STOCK) {
|
|
367
|
+
console.warn("[ProductPage V1] Product is out of stock");
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
setIsAddingToCart(true);
|
|
371
|
+
try {
|
|
372
|
+
const variantId = selectedVariant()?._id;
|
|
373
|
+
await storesContext.addToCart(productId, quantity(), variantId);
|
|
374
|
+
console.log("[ProductPage V1] Added to cart:", quantity(), "items");
|
|
375
|
+
} catch (error) {
|
|
376
|
+
console.error("[ProductPage V1] Failed to add to cart:", error);
|
|
377
|
+
} finally {
|
|
378
|
+
setIsAddingToCart(false);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
return {
|
|
382
|
+
render: () => ({
|
|
383
|
+
quantity: { quantity: quantity() },
|
|
384
|
+
actionsEnabled: computedActionsEnabled,
|
|
385
|
+
options,
|
|
386
|
+
modifiers: () => [],
|
|
387
|
+
mediaGallery: interactiveMedia,
|
|
388
|
+
sku,
|
|
389
|
+
price,
|
|
390
|
+
pricePerUnit,
|
|
391
|
+
stockStatus,
|
|
392
|
+
strikethroughPrice
|
|
393
|
+
})
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
const productPage = makeJayStackComponent().withProps().withContexts(WIX_STORES_V1_CONTEXT).withInteractive(ProductPageInteractive);
|
|
397
|
+
var CurrentSort = /* @__PURE__ */ ((CurrentSort2) => {
|
|
398
|
+
CurrentSort2[CurrentSort2["relevance"] = 0] = "relevance";
|
|
399
|
+
CurrentSort2[CurrentSort2["priceAsc"] = 1] = "priceAsc";
|
|
400
|
+
CurrentSort2[CurrentSort2["priceDesc"] = 2] = "priceDesc";
|
|
401
|
+
CurrentSort2[CurrentSort2["newest"] = 3] = "newest";
|
|
402
|
+
CurrentSort2[CurrentSort2["nameAsc"] = 4] = "nameAsc";
|
|
403
|
+
CurrentSort2[CurrentSort2["nameDesc"] = 5] = "nameDesc";
|
|
404
|
+
return CurrentSort2;
|
|
405
|
+
})(CurrentSort || {});
|
|
406
|
+
const searchProducts = createActionCaller("wixStoresV1.searchProducts", "GET");
|
|
407
|
+
createActionCaller("wixStoresV1.getProductBySlug", "GET");
|
|
408
|
+
createActionCaller("wixStoresV1.getCollections", "GET");
|
|
409
|
+
const PAGE_SIZE$1 = 12;
|
|
410
|
+
function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForward, storesContext) {
|
|
411
|
+
const { searchExpression: [searchExpression, setSearchExpression], isSearching: [isSearching, setIsSearching], hasSearched: [hasSearched, setHasSearched], searchResults: [searchResults, setSearchResults], resultCount: [resultCount, setResultCount], hasResults: [hasResults, setHasResults], hasSuggestions: [hasSuggestions, setHasSuggestions], suggestions: [suggestions, setSuggestions], filters: [filters, setFilters], sortBy: [sortBy, setSortBy], hasMore: [hasMore, setHasMore], loadedCount: [loadedCount, setLoadedCount], totalCount: [totalCount, setTotalCount] } = viewStateSignals;
|
|
412
|
+
const [submittedSearchTerm, setSubmittedSearchTerm] = createSignal(null);
|
|
413
|
+
const [currentPage, setCurrentPage] = createSignal(1);
|
|
414
|
+
let isFirst = true;
|
|
415
|
+
let debounceTimeout = null;
|
|
416
|
+
let searchVersion = 0;
|
|
417
|
+
const DEBOUNCE_MS = 300;
|
|
418
|
+
const mapSortToAction = (sort) => {
|
|
419
|
+
switch (sort) {
|
|
420
|
+
case CurrentSort.priceAsc:
|
|
421
|
+
return "price_asc";
|
|
422
|
+
case CurrentSort.priceDesc:
|
|
423
|
+
return "price_desc";
|
|
424
|
+
case CurrentSort.newest:
|
|
425
|
+
return "newest";
|
|
426
|
+
case CurrentSort.nameAsc:
|
|
427
|
+
return "name_asc";
|
|
428
|
+
case CurrentSort.nameDesc:
|
|
429
|
+
return "name_desc";
|
|
430
|
+
default:
|
|
431
|
+
return "relevance";
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
const performSearch = async (version, searchTerm, currentFilters, currentSort) => {
|
|
435
|
+
setIsSearching(true);
|
|
436
|
+
setHasSearched(true);
|
|
437
|
+
try {
|
|
438
|
+
const result = await searchProducts({
|
|
439
|
+
query: searchTerm || "",
|
|
440
|
+
filters: {
|
|
441
|
+
minPrice: currentFilters.priceRange.minPrice || void 0,
|
|
442
|
+
maxPrice: currentFilters.priceRange.maxPrice || void 0,
|
|
443
|
+
collectionIds: currentFilters.categoryFilter.categories.filter((c) => c.isSelected).map((c) => c.categoryId)
|
|
444
|
+
},
|
|
445
|
+
sortBy: mapSortToAction(currentSort),
|
|
446
|
+
pageSize: PAGE_SIZE$1,
|
|
447
|
+
page: 1
|
|
448
|
+
});
|
|
449
|
+
if (version !== searchVersion)
|
|
450
|
+
return;
|
|
451
|
+
setSearchResults(result.products);
|
|
452
|
+
setResultCount(result.products.length);
|
|
453
|
+
setTotalCount(result.totalCount);
|
|
454
|
+
setLoadedCount(result.products.length);
|
|
455
|
+
setHasMore(result.hasMore);
|
|
456
|
+
setHasResults(result.products.length > 0);
|
|
457
|
+
setCurrentPage(1);
|
|
458
|
+
} catch (error) {
|
|
459
|
+
if (version === searchVersion) {
|
|
460
|
+
console.error("[ProductSearch V1] Search failed:", error);
|
|
461
|
+
}
|
|
462
|
+
} finally {
|
|
463
|
+
if (version === searchVersion) {
|
|
464
|
+
setIsSearching(false);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
const performLoadMore = async () => {
|
|
469
|
+
if (isSearching() || !hasMore())
|
|
470
|
+
return;
|
|
471
|
+
setIsSearching(true);
|
|
472
|
+
try {
|
|
473
|
+
const currentFilters = filters();
|
|
474
|
+
const currentSort = sortBy().currentSort;
|
|
475
|
+
const searchTerm = submittedSearchTerm();
|
|
476
|
+
const nextPage = currentPage() + 1;
|
|
477
|
+
const result = await searchProducts({
|
|
478
|
+
query: searchTerm || "",
|
|
479
|
+
filters: {
|
|
480
|
+
minPrice: currentFilters.priceRange.minPrice || void 0,
|
|
481
|
+
maxPrice: currentFilters.priceRange.maxPrice || void 0,
|
|
482
|
+
collectionIds: currentFilters.categoryFilter.categories.filter((c) => c.isSelected).map((c) => c.categoryId)
|
|
483
|
+
},
|
|
484
|
+
sortBy: mapSortToAction(currentSort),
|
|
485
|
+
page: nextPage,
|
|
486
|
+
pageSize: PAGE_SIZE$1
|
|
487
|
+
});
|
|
488
|
+
const currentResults = searchResults();
|
|
489
|
+
const newResults = [...currentResults, ...result.products];
|
|
490
|
+
setSearchResults(newResults);
|
|
491
|
+
setResultCount(newResults.length);
|
|
492
|
+
setLoadedCount(newResults.length);
|
|
493
|
+
setHasMore(result.hasMore);
|
|
494
|
+
setCurrentPage(nextPage);
|
|
495
|
+
} catch (error) {
|
|
496
|
+
console.error("[ProductSearch V1] Load more failed:", error);
|
|
497
|
+
} finally {
|
|
498
|
+
setIsSearching(false);
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
createEffect(() => {
|
|
502
|
+
const searchTerm = submittedSearchTerm();
|
|
503
|
+
const currentFilters = filters();
|
|
504
|
+
const currentSort = sortBy().currentSort;
|
|
505
|
+
if (isFirst) {
|
|
506
|
+
isFirst = false;
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (debounceTimeout) {
|
|
510
|
+
clearTimeout(debounceTimeout);
|
|
511
|
+
}
|
|
512
|
+
debounceTimeout = setTimeout(() => {
|
|
513
|
+
searchVersion++;
|
|
514
|
+
const version = searchVersion;
|
|
515
|
+
performSearch(version, searchTerm, currentFilters, currentSort);
|
|
516
|
+
}, DEBOUNCE_MS);
|
|
517
|
+
});
|
|
518
|
+
refs.searchExpression.oninput(({ event }) => {
|
|
519
|
+
const value = event.target.value;
|
|
520
|
+
setSearchExpression(value);
|
|
521
|
+
});
|
|
522
|
+
refs.searchExpression.onkeydown(({ event }) => {
|
|
523
|
+
if (event.key === "Enter") {
|
|
524
|
+
event.preventDefault();
|
|
525
|
+
setSubmittedSearchTerm(searchExpression().trim());
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
refs.searchButton.onclick(() => {
|
|
529
|
+
setSubmittedSearchTerm(searchExpression().trim());
|
|
530
|
+
});
|
|
531
|
+
refs.clearSearchButton.onclick(() => {
|
|
532
|
+
setSearchExpression("");
|
|
533
|
+
setSubmittedSearchTerm(null);
|
|
534
|
+
setHasSearched(false);
|
|
535
|
+
});
|
|
536
|
+
refs.sortBy.sortDropdown.oninput(({ event }) => {
|
|
537
|
+
const value = event.target.value;
|
|
538
|
+
const sortMap = {
|
|
539
|
+
relevance: CurrentSort.relevance,
|
|
540
|
+
priceAsc: CurrentSort.priceAsc,
|
|
541
|
+
priceDesc: CurrentSort.priceDesc,
|
|
542
|
+
newest: CurrentSort.newest,
|
|
543
|
+
nameAsc: CurrentSort.nameAsc,
|
|
544
|
+
nameDesc: CurrentSort.nameDesc
|
|
545
|
+
};
|
|
546
|
+
const newSort = sortMap[value] ?? CurrentSort.relevance;
|
|
547
|
+
setSortBy({ currentSort: newSort });
|
|
548
|
+
});
|
|
549
|
+
refs.filters.priceRange.minPrice.oninput(({ event }) => {
|
|
550
|
+
const value = parseFloat(event.target.value);
|
|
551
|
+
const newValue = isNaN(value) ? 0 : value;
|
|
552
|
+
setFilters(patch(filters(), [{ op: REPLACE, path: ["priceRange", "minPrice"], value: newValue }]));
|
|
553
|
+
});
|
|
554
|
+
refs.filters.priceRange.maxPrice.oninput(({ event }) => {
|
|
555
|
+
const value = parseFloat(event.target.value);
|
|
556
|
+
const newValue = isNaN(value) ? 0 : value;
|
|
557
|
+
setFilters(patch(filters(), [{ op: REPLACE, path: ["priceRange", "maxPrice"], value: newValue }]));
|
|
558
|
+
});
|
|
559
|
+
refs.filters.priceRange.ranges.isSelected.oninput(({ event, coordinate }) => {
|
|
560
|
+
const [rangeId] = coordinate;
|
|
561
|
+
const currentFilters = filters();
|
|
562
|
+
const ranges = currentFilters.priceRange.ranges || [];
|
|
563
|
+
const selectedRange = ranges.find((r) => r.rangeId === rangeId);
|
|
564
|
+
if (!selectedRange)
|
|
565
|
+
return;
|
|
566
|
+
const updatedRanges = ranges.map((r) => ({
|
|
567
|
+
...r,
|
|
568
|
+
isSelected: r.rangeId === rangeId
|
|
569
|
+
}));
|
|
570
|
+
const newMinPrice = selectedRange.minValue ?? 0;
|
|
571
|
+
const newMaxPrice = selectedRange.maxValue ?? 0;
|
|
572
|
+
setFilters(patch(currentFilters, [
|
|
573
|
+
{ op: REPLACE, path: ["priceRange", "ranges"], value: updatedRanges },
|
|
574
|
+
{ op: REPLACE, path: ["priceRange", "minPrice"], value: newMinPrice },
|
|
575
|
+
{ op: REPLACE, path: ["priceRange", "maxPrice"], value: newMaxPrice }
|
|
576
|
+
]));
|
|
577
|
+
});
|
|
578
|
+
refs.filters.categoryFilter.categories.isSelected.oninput(({ event, coordinate }) => {
|
|
579
|
+
const [categoryId] = coordinate;
|
|
580
|
+
const currentFilters = filters();
|
|
581
|
+
const categoryIndex = currentFilters.categoryFilter.categories.findIndex((c) => c.categoryId === categoryId);
|
|
582
|
+
if (categoryIndex !== -1) {
|
|
583
|
+
const isChecked = event.target.checked;
|
|
584
|
+
setFilters(patch(currentFilters, [
|
|
585
|
+
{
|
|
586
|
+
op: REPLACE,
|
|
587
|
+
path: ["categoryFilter", "categories", categoryIndex, "isSelected"],
|
|
588
|
+
value: isChecked
|
|
589
|
+
}
|
|
590
|
+
]));
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
refs.filters.clearFilters.onclick(() => {
|
|
594
|
+
const currentFilters = filters();
|
|
595
|
+
const clearedCategories = currentFilters.categoryFilter.categories.map((cat) => ({
|
|
596
|
+
...cat,
|
|
597
|
+
isSelected: false
|
|
598
|
+
}));
|
|
599
|
+
const clearedRanges = (currentFilters.priceRange.ranges || []).map((r, i) => ({
|
|
600
|
+
...r,
|
|
601
|
+
isSelected: i === 0
|
|
602
|
+
}));
|
|
603
|
+
setFilters({
|
|
604
|
+
priceRange: {
|
|
605
|
+
minPrice: 0,
|
|
606
|
+
maxPrice: 0,
|
|
607
|
+
minBound: currentFilters.priceRange.minBound,
|
|
608
|
+
maxBound: currentFilters.priceRange.maxBound,
|
|
609
|
+
ranges: clearedRanges
|
|
610
|
+
},
|
|
611
|
+
categoryFilter: { categories: clearedCategories }
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
refs.loadMoreButton.onclick(() => {
|
|
615
|
+
performLoadMore();
|
|
616
|
+
});
|
|
617
|
+
refs.suggestions?.suggestionButton?.onclick(({ coordinate }) => {
|
|
618
|
+
const [suggestionId] = coordinate;
|
|
619
|
+
const suggestion = suggestions().find((s) => s.suggestionId === suggestionId);
|
|
620
|
+
if (suggestion) {
|
|
621
|
+
setSearchExpression(suggestion.suggestionText);
|
|
622
|
+
setSubmittedSearchTerm(suggestion.suggestionText);
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
refs.searchResults?.addToCartButton?.onclick(async ({ coordinate }) => {
|
|
626
|
+
const [productId] = coordinate;
|
|
627
|
+
const currentResults = searchResults();
|
|
628
|
+
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
629
|
+
if (productIndex === -1)
|
|
630
|
+
return;
|
|
631
|
+
setSearchResults(patch(currentResults, [
|
|
632
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: true }
|
|
633
|
+
]));
|
|
634
|
+
try {
|
|
635
|
+
await storesContext.addToCart(productId, 1);
|
|
636
|
+
} catch (error) {
|
|
637
|
+
console.error("[ProductSearch V1] Failed to add to cart:", error);
|
|
638
|
+
} finally {
|
|
639
|
+
setSearchResults(patch(searchResults(), [
|
|
640
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: false }
|
|
641
|
+
]));
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
refs.searchResults?.quickOption?.choices?.choiceButton?.onclick(async ({ coordinate }) => {
|
|
645
|
+
const [productId, choiceId] = coordinate;
|
|
646
|
+
const currentResults = searchResults();
|
|
647
|
+
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
648
|
+
if (productIndex === -1)
|
|
649
|
+
return;
|
|
650
|
+
const product = currentResults[productIndex];
|
|
651
|
+
const choice = product.quickOption?.choices?.find((c) => c.choiceId === choiceId);
|
|
652
|
+
if (!choice || !choice.inStock) {
|
|
653
|
+
console.warn("[ProductSearch V1] Choice not available or out of stock");
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
setSearchResults(patch(currentResults, [
|
|
657
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: true }
|
|
658
|
+
]));
|
|
659
|
+
try {
|
|
660
|
+
await storesContext.addToCart(productId, 1, choice.variantId);
|
|
661
|
+
} catch (error) {
|
|
662
|
+
console.error("[ProductSearch V1] Failed to add to cart:", error);
|
|
663
|
+
} finally {
|
|
664
|
+
setSearchResults(patch(searchResults(), [
|
|
665
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: false }
|
|
666
|
+
]));
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
refs.searchResults?.viewOptionsButton?.onclick(({ coordinate }) => {
|
|
670
|
+
const [productId] = coordinate;
|
|
671
|
+
const product = searchResults().find((p) => p._id === productId);
|
|
672
|
+
if (product?.productUrl) {
|
|
673
|
+
window.location.href = product.productUrl;
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
return {
|
|
677
|
+
render: () => ({
|
|
678
|
+
searchExpression: searchExpression(),
|
|
679
|
+
isSearching: isSearching(),
|
|
680
|
+
hasSearched: hasSearched(),
|
|
681
|
+
searchResults: searchResults(),
|
|
682
|
+
resultCount: resultCount(),
|
|
683
|
+
hasResults: hasResults(),
|
|
684
|
+
hasSuggestions: hasSuggestions(),
|
|
685
|
+
suggestions: suggestions(),
|
|
686
|
+
filters: filters(),
|
|
687
|
+
sortBy: sortBy(),
|
|
688
|
+
hasMore: hasMore(),
|
|
689
|
+
loadedCount: loadedCount(),
|
|
690
|
+
totalCount: totalCount()
|
|
691
|
+
})
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
const productSearch = makeJayStackComponent().withProps().withContexts(WIX_STORES_V1_CONTEXT).withInteractive(ProductSearchInteractive);
|
|
695
|
+
const PAGE_SIZE = 20;
|
|
696
|
+
function CollectionPageInteractive(_props, refs, viewStateSignals, fastCarryForward, storesContext) {
|
|
697
|
+
const { products: [products2], loadedProducts: [loadedProducts, setLoadedProducts], hasMore: [hasMore, setHasMore], loadedCount: [loadedCount, setLoadedCount], isLoading: [isLoading, setIsLoading], hasProducts: [hasProducts, setHasProducts] } = viewStateSignals;
|
|
698
|
+
const { collectionId, totalProducts } = fastCarryForward;
|
|
699
|
+
let currentOffset = fastCarryForward.currentOffset;
|
|
700
|
+
refs.loadMoreButton?.onclick(async () => {
|
|
701
|
+
if (isLoading() || !hasMore())
|
|
702
|
+
return;
|
|
703
|
+
setIsLoading(true);
|
|
704
|
+
try {
|
|
705
|
+
const response = await storesContext.loadMoreCollectionProducts(collectionId, currentOffset, PAGE_SIZE);
|
|
706
|
+
const currentLoaded = loadedProducts();
|
|
707
|
+
setLoadedProducts([...currentLoaded, ...response.products]);
|
|
708
|
+
currentOffset += response.products.length;
|
|
709
|
+
setLoadedCount(loadedCount() + response.products.length);
|
|
710
|
+
setHasMore(currentOffset < totalProducts);
|
|
711
|
+
setHasProducts(true);
|
|
712
|
+
} catch (error) {
|
|
713
|
+
console.error("[CollectionPage V1] Failed to load more products:", error);
|
|
714
|
+
} finally {
|
|
715
|
+
setIsLoading(false);
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
refs.products?.addToCartButton?.onclick(async ({ coordinate }) => {
|
|
719
|
+
const [productId] = coordinate;
|
|
720
|
+
try {
|
|
721
|
+
await storesContext.addToCart(productId, 1);
|
|
722
|
+
} catch (error) {
|
|
723
|
+
console.error("[CollectionPage V1] Failed to add to cart:", error);
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
refs.loadedProducts?.addToCartButton?.onclick(async ({ coordinate }) => {
|
|
727
|
+
const [productId] = coordinate;
|
|
728
|
+
try {
|
|
729
|
+
await storesContext.addToCart(productId, 1);
|
|
730
|
+
} catch (error) {
|
|
731
|
+
console.error("[CollectionPage V1] Failed to add to cart:", error);
|
|
732
|
+
}
|
|
733
|
+
});
|
|
734
|
+
refs.products?.quickOption?.choices?.choiceButton?.onclick(async ({ coordinate }) => {
|
|
735
|
+
const [productId, choiceId] = coordinate;
|
|
736
|
+
try {
|
|
737
|
+
await storesContext.addToCart(productId, 1, choiceId);
|
|
738
|
+
} catch (error) {
|
|
739
|
+
console.error("[CollectionPage V1] Failed to add to cart:", error);
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
refs.loadedProducts?.quickOption?.choices?.choiceButton?.onclick(async ({ coordinate }) => {
|
|
743
|
+
const [productId, choiceId] = coordinate;
|
|
744
|
+
const product = loadedProducts().find((p) => p._id === productId);
|
|
745
|
+
if (!product)
|
|
746
|
+
return;
|
|
747
|
+
const choice = product.quickOption?.choices?.find((c) => c.choiceId === choiceId);
|
|
748
|
+
if (!choice || !choice.inStock) {
|
|
749
|
+
console.warn("[CollectionPage V1] Choice not available or out of stock");
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
try {
|
|
753
|
+
await storesContext.addToCart(productId, 1, choice.variantId);
|
|
754
|
+
} catch (error) {
|
|
755
|
+
console.error("[CollectionPage V1] Failed to add to cart:", error);
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
refs.loadedProducts?.viewOptionsButton?.onclick(({ coordinate }) => {
|
|
759
|
+
const [productId] = coordinate;
|
|
760
|
+
const product = loadedProducts().find((p) => p._id === productId);
|
|
761
|
+
if (product?.productUrl) {
|
|
762
|
+
window.location.href = product.productUrl;
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
return {
|
|
766
|
+
render: () => ({
|
|
767
|
+
products: products2(),
|
|
768
|
+
loadedProducts: loadedProducts(),
|
|
769
|
+
hasMore: hasMore(),
|
|
770
|
+
loadedCount: loadedCount(),
|
|
771
|
+
isLoading: isLoading(),
|
|
772
|
+
hasProducts: hasProducts()
|
|
773
|
+
})
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
const collectionPage = makeJayStackComponent().withProps().withContexts(WIX_STORES_V1_CONTEXT).withInteractive(CollectionPageInteractive);
|
|
777
|
+
const categoryPage = collectionPage;
|
|
778
|
+
const collectionList = makeJayStackComponent().withProps();
|
|
779
|
+
const categoryList = collectionList;
|
|
780
|
+
const init = makeJayInit().withClient(async (data) => {
|
|
781
|
+
console.log("[wix-stores-v1] Initializing client-side stores context...");
|
|
782
|
+
provideWixStoresV1Context();
|
|
783
|
+
console.log("[wix-stores-v1] Client initialization complete");
|
|
784
|
+
console.log(`[wix-stores-v1] Search enabled: ${data.enableClientSearch}`);
|
|
785
|
+
});
|
|
786
|
+
export {
|
|
787
|
+
WIX_CART_CONTEXT,
|
|
788
|
+
WIX_STORES_V1_CONTEXT,
|
|
789
|
+
cartIndicator,
|
|
790
|
+
cartPage,
|
|
791
|
+
categoryList,
|
|
792
|
+
categoryPage,
|
|
793
|
+
collectionList,
|
|
794
|
+
collectionPage,
|
|
795
|
+
init,
|
|
796
|
+
productPage,
|
|
797
|
+
productSearch,
|
|
798
|
+
provideWixStoresV1Context
|
|
799
|
+
};
|