@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
package/dist/index.js
ADDED
|
@@ -0,0 +1,853 @@
|
|
|
1
|
+
import { getCurrentCartClient } from "@jay-framework/wix-cart";
|
|
2
|
+
import { WIX_CART_CONTEXT, WIX_CART_SERVICE, cartIndicator, cartPage, provideWixCartContext, provideWixCartService } from "@jay-framework/wix-cart";
|
|
3
|
+
import { inventory, collections, products } from "@wix/stores";
|
|
4
|
+
import { createJayService, makeJayQuery, ActionError, makeJayStackComponent, RenderPipeline, makeJayInit } from "@jay-framework/fullstack-component";
|
|
5
|
+
import { registerService, getService } from "@jay-framework/stack-server-runtime";
|
|
6
|
+
import { createJayContext } from "@jay-framework/runtime";
|
|
7
|
+
import "@jay-framework/component";
|
|
8
|
+
import { WIX_CLIENT_SERVICE } from "@jay-framework/wix-server-client";
|
|
9
|
+
const instances = {
|
|
10
|
+
productsClientInstance: void 0,
|
|
11
|
+
collectionsClientInstance: void 0,
|
|
12
|
+
inventoryClientInstance: void 0
|
|
13
|
+
};
|
|
14
|
+
function getProductsClient(wixClient) {
|
|
15
|
+
if (!instances.productsClientInstance) {
|
|
16
|
+
instances.productsClientInstance = wixClient.use(products);
|
|
17
|
+
}
|
|
18
|
+
return instances.productsClientInstance;
|
|
19
|
+
}
|
|
20
|
+
function getCollectionsClient(wixClient) {
|
|
21
|
+
if (!instances.collectionsClientInstance) {
|
|
22
|
+
instances.collectionsClientInstance = wixClient.use(collections);
|
|
23
|
+
}
|
|
24
|
+
return instances.collectionsClientInstance;
|
|
25
|
+
}
|
|
26
|
+
function getInventoryClient(wixClient) {
|
|
27
|
+
if (!instances.inventoryClientInstance) {
|
|
28
|
+
instances.inventoryClientInstance = wixClient.use(inventory);
|
|
29
|
+
}
|
|
30
|
+
return instances.inventoryClientInstance;
|
|
31
|
+
}
|
|
32
|
+
const WIX_STORES_V1_SERVICE_MARKER = createJayService("Wix Store V1 Service");
|
|
33
|
+
function provideWixStoresV1Service(wixClient) {
|
|
34
|
+
const service = {
|
|
35
|
+
products: getProductsClient(wixClient),
|
|
36
|
+
collections: getCollectionsClient(wixClient),
|
|
37
|
+
inventory: getInventoryClient(wixClient),
|
|
38
|
+
// Keep cart for backward compatibility, but prefer WIX_CART_SERVICE
|
|
39
|
+
cart: getCurrentCartClient(wixClient)
|
|
40
|
+
};
|
|
41
|
+
registerService(WIX_STORES_V1_SERVICE_MARKER, service);
|
|
42
|
+
return service;
|
|
43
|
+
}
|
|
44
|
+
var MediaType$2 = /* @__PURE__ */ ((MediaType2) => {
|
|
45
|
+
MediaType2[MediaType2["IMAGE"] = 0] = "IMAGE";
|
|
46
|
+
MediaType2[MediaType2["VIDEO"] = 1] = "VIDEO";
|
|
47
|
+
return MediaType2;
|
|
48
|
+
})(MediaType$2 || {});
|
|
49
|
+
var AvailabilityStatus = /* @__PURE__ */ ((AvailabilityStatus2) => {
|
|
50
|
+
AvailabilityStatus2[AvailabilityStatus2["IN_STOCK"] = 0] = "IN_STOCK";
|
|
51
|
+
AvailabilityStatus2[AvailabilityStatus2["OUT_OF_STOCK"] = 1] = "OUT_OF_STOCK";
|
|
52
|
+
AvailabilityStatus2[AvailabilityStatus2["PARTIALLY_OUT_OF_STOCK"] = 2] = "PARTIALLY_OUT_OF_STOCK";
|
|
53
|
+
return AvailabilityStatus2;
|
|
54
|
+
})(AvailabilityStatus || {});
|
|
55
|
+
var PreorderStatus = /* @__PURE__ */ ((PreorderStatus2) => {
|
|
56
|
+
PreorderStatus2[PreorderStatus2["ENABLED"] = 0] = "ENABLED";
|
|
57
|
+
PreorderStatus2[PreorderStatus2["DISABLED"] = 1] = "DISABLED";
|
|
58
|
+
PreorderStatus2[PreorderStatus2["PARTIALLY_ENABLED"] = 2] = "PARTIALLY_ENABLED";
|
|
59
|
+
return PreorderStatus2;
|
|
60
|
+
})(PreorderStatus || {});
|
|
61
|
+
var ProductType$1 = /* @__PURE__ */ ((ProductType2) => {
|
|
62
|
+
ProductType2[ProductType2["PHYSICAL"] = 0] = "PHYSICAL";
|
|
63
|
+
ProductType2[ProductType2["DIGITAL"] = 1] = "DIGITAL";
|
|
64
|
+
return ProductType2;
|
|
65
|
+
})(ProductType$1 || {});
|
|
66
|
+
var QuickAddType = /* @__PURE__ */ ((QuickAddType2) => {
|
|
67
|
+
QuickAddType2[QuickAddType2["SIMPLE"] = 0] = "SIMPLE";
|
|
68
|
+
QuickAddType2[QuickAddType2["SINGLE_OPTION"] = 1] = "SINGLE_OPTION";
|
|
69
|
+
QuickAddType2[QuickAddType2["NEEDS_CONFIGURATION"] = 2] = "NEEDS_CONFIGURATION";
|
|
70
|
+
return QuickAddType2;
|
|
71
|
+
})(QuickAddType || {});
|
|
72
|
+
var OptionRenderType$1 = /* @__PURE__ */ ((OptionRenderType2) => {
|
|
73
|
+
OptionRenderType2[OptionRenderType2["TEXT_CHOICES"] = 0] = "TEXT_CHOICES";
|
|
74
|
+
OptionRenderType2[OptionRenderType2["COLOR_SWATCH_CHOICES"] = 1] = "COLOR_SWATCH_CHOICES";
|
|
75
|
+
return OptionRenderType2;
|
|
76
|
+
})(OptionRenderType$1 || {});
|
|
77
|
+
var ChoiceType$1 = /* @__PURE__ */ ((ChoiceType2) => {
|
|
78
|
+
ChoiceType2[ChoiceType2["CHOICE_TEXT"] = 0] = "CHOICE_TEXT";
|
|
79
|
+
ChoiceType2[ChoiceType2["ONE_COLOR"] = 1] = "ONE_COLOR";
|
|
80
|
+
return ChoiceType2;
|
|
81
|
+
})(ChoiceType$1 || {});
|
|
82
|
+
function mapAvailabilityStatus(status) {
|
|
83
|
+
switch (status) {
|
|
84
|
+
case "OUT_OF_STOCK":
|
|
85
|
+
return AvailabilityStatus.OUT_OF_STOCK;
|
|
86
|
+
case "PARTIALLY_OUT_OF_STOCK":
|
|
87
|
+
return AvailabilityStatus.PARTIALLY_OUT_OF_STOCK;
|
|
88
|
+
default:
|
|
89
|
+
return AvailabilityStatus.IN_STOCK;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function mapPreorderStatus() {
|
|
93
|
+
return PreorderStatus.DISABLED;
|
|
94
|
+
}
|
|
95
|
+
function mapMediaType(mediaType) {
|
|
96
|
+
return mediaType === "video" ? MediaType$2.VIDEO : MediaType$2.IMAGE;
|
|
97
|
+
}
|
|
98
|
+
function mapProductType$1(productType) {
|
|
99
|
+
return productType === "digital" ? ProductType$1.DIGITAL : ProductType$1.PHYSICAL;
|
|
100
|
+
}
|
|
101
|
+
function hasProductDiscount(product) {
|
|
102
|
+
const price = product.price?.price || 0;
|
|
103
|
+
const discountedPrice = product.price?.discountedPrice || price;
|
|
104
|
+
return discountedPrice < price;
|
|
105
|
+
}
|
|
106
|
+
function getQuickAddType(product) {
|
|
107
|
+
const optionCount = product.productOptions?.length ?? 0;
|
|
108
|
+
if (optionCount > 1) {
|
|
109
|
+
return QuickAddType.NEEDS_CONFIGURATION;
|
|
110
|
+
}
|
|
111
|
+
if (optionCount === 1) {
|
|
112
|
+
return QuickAddType.SINGLE_OPTION;
|
|
113
|
+
}
|
|
114
|
+
return QuickAddType.SIMPLE;
|
|
115
|
+
}
|
|
116
|
+
function mapOptionRenderType(optionType) {
|
|
117
|
+
return optionType === "color" ? OptionRenderType$1.COLOR_SWATCH_CHOICES : OptionRenderType$1.TEXT_CHOICES;
|
|
118
|
+
}
|
|
119
|
+
function mapQuickOption(option, variants) {
|
|
120
|
+
if (!option) return null;
|
|
121
|
+
const choices = option.choices || [];
|
|
122
|
+
return {
|
|
123
|
+
_id: option.name,
|
|
124
|
+
name: option.name || "",
|
|
125
|
+
optionRenderType: mapOptionRenderType(option.optionType),
|
|
126
|
+
choices: choices.map((choice) => {
|
|
127
|
+
const variant = variants?.find((v) => Object.values(v.choices).includes(choice.value));
|
|
128
|
+
return {
|
|
129
|
+
choiceId: choice.description,
|
|
130
|
+
name: choice.value || "",
|
|
131
|
+
choiceType: option.optionType === "color" ? ChoiceType$1.ONE_COLOR : ChoiceType$1.CHOICE_TEXT,
|
|
132
|
+
colorCode: "",
|
|
133
|
+
// V1 doesn't store color code in choices
|
|
134
|
+
inStock: variant?.stock?.inStock ?? choice.inStock ?? true,
|
|
135
|
+
variantId: variant?._id || "",
|
|
136
|
+
isSelected: false
|
|
137
|
+
};
|
|
138
|
+
})
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
const DEFAULT_PRODUCT_PAGE_PATH = "/products";
|
|
142
|
+
function mapProductToCard(product, productPagePath = DEFAULT_PRODUCT_PAGE_PATH) {
|
|
143
|
+
const mainMedia = product.media?.mainMedia;
|
|
144
|
+
const slug = product.slug || "";
|
|
145
|
+
product.price?.discountedPrice ?? product.price?.price ?? 0;
|
|
146
|
+
product.price?.price ?? 0;
|
|
147
|
+
const formattedActualPrice = product.price?.formatted?.discountedPrice || "";
|
|
148
|
+
const formattedCompareAtPrice = product.price?.formatted?.price || "";
|
|
149
|
+
const hasDiscount = hasProductDiscount(product);
|
|
150
|
+
console.log("product", product.name, product.slug);
|
|
151
|
+
return {
|
|
152
|
+
_id: product._id || "",
|
|
153
|
+
name: product.name || "",
|
|
154
|
+
slug,
|
|
155
|
+
productUrl: slug ? `${productPagePath}/${slug}` : "",
|
|
156
|
+
mainMedia: {
|
|
157
|
+
// V1 provides complete URLs
|
|
158
|
+
url: mainMedia?.image?.url || "",
|
|
159
|
+
altText: mainMedia?.title || product.name || "",
|
|
160
|
+
mediaType: mapMediaType(mainMedia?.mediaType)
|
|
161
|
+
},
|
|
162
|
+
thumbnail: {
|
|
163
|
+
// V1 provides complete thumbnail URLs
|
|
164
|
+
url: mainMedia?.thumbnail?.url || "",
|
|
165
|
+
altText: mainMedia?.title || product.name || "",
|
|
166
|
+
width: mainMedia?.thumbnail?.width || 300,
|
|
167
|
+
height: mainMedia?.thumbnail?.height || 300
|
|
168
|
+
},
|
|
169
|
+
// Simplified price fields
|
|
170
|
+
price: formattedActualPrice,
|
|
171
|
+
strikethroughPrice: hasDiscount ? formattedCompareAtPrice : "",
|
|
172
|
+
hasDiscount,
|
|
173
|
+
inventory: {
|
|
174
|
+
// V1 uses stock.inventoryStatus
|
|
175
|
+
availabilityStatus: mapAvailabilityStatus(product.stock?.inventoryStatus),
|
|
176
|
+
preorderStatus: mapPreorderStatus()
|
|
177
|
+
},
|
|
178
|
+
ribbon: {
|
|
179
|
+
_id: product.ribbon || "",
|
|
180
|
+
name: product.ribbon || ""
|
|
181
|
+
},
|
|
182
|
+
hasRibbon: !!product.ribbon,
|
|
183
|
+
brand: {
|
|
184
|
+
_id: product.brand || "",
|
|
185
|
+
name: product.brand || ""
|
|
186
|
+
},
|
|
187
|
+
productType: mapProductType$1(product.productType),
|
|
188
|
+
isAddingToCart: false,
|
|
189
|
+
// Quick add behavior
|
|
190
|
+
quickAddType: getQuickAddType(product),
|
|
191
|
+
quickOption: getQuickAddType(product) === QuickAddType.SINGLE_OPTION ? mapQuickOption(product.productOptions?.[0], product.variants) : null
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function mapCollectionToViewState(collection) {
|
|
195
|
+
return {
|
|
196
|
+
_id: collection._id,
|
|
197
|
+
name: collection.name || "",
|
|
198
|
+
slug: collection.slug || "",
|
|
199
|
+
description: collection.description || "",
|
|
200
|
+
imageUrl: collection.media?.mainMedia?.image?.url || "",
|
|
201
|
+
productCount: collection.numberOfProducts || 0
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
const WIX_STORES_V1_CONTEXT = createJayContext();
|
|
205
|
+
function getNiceBoundaries(minPrice, maxPrice) {
|
|
206
|
+
const multipliers = [1, 2, 5];
|
|
207
|
+
const boundaries = [];
|
|
208
|
+
let magnitude = 1;
|
|
209
|
+
while (magnitude <= maxPrice * 10) {
|
|
210
|
+
for (const mult of multipliers) {
|
|
211
|
+
const value = magnitude * mult;
|
|
212
|
+
if (value > minPrice && value < maxPrice) {
|
|
213
|
+
boundaries.push(value);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
magnitude *= 10;
|
|
217
|
+
}
|
|
218
|
+
return boundaries.sort((a, b) => a - b);
|
|
219
|
+
}
|
|
220
|
+
function generatePriceBuckets(minPrice, maxPrice, currencySymbol = "$") {
|
|
221
|
+
if (maxPrice <= minPrice || maxPrice === 0) {
|
|
222
|
+
return [
|
|
223
|
+
{ rangeId: "all", label: "Show all", minValue: null, maxValue: null, isSelected: true }
|
|
224
|
+
];
|
|
225
|
+
}
|
|
226
|
+
let niceBoundaries = getNiceBoundaries(minPrice, maxPrice);
|
|
227
|
+
while (niceBoundaries.length > 5) {
|
|
228
|
+
niceBoundaries = niceBoundaries.filter((_, i) => i % 2 === 0);
|
|
229
|
+
}
|
|
230
|
+
const allBoundaries = [minPrice, ...niceBoundaries, maxPrice];
|
|
231
|
+
const buckets = [
|
|
232
|
+
{ rangeId: "all", label: "Show all", minValue: null, maxValue: null, isSelected: true }
|
|
233
|
+
];
|
|
234
|
+
for (let i = 0; i < allBoundaries.length - 1; i++) {
|
|
235
|
+
const from = Math.round(allBoundaries[i]);
|
|
236
|
+
const to = Math.round(allBoundaries[i + 1]);
|
|
237
|
+
if (from < to) {
|
|
238
|
+
const label = `${currencySymbol}${from} - ${currencySymbol}${to}`;
|
|
239
|
+
buckets.push({
|
|
240
|
+
rangeId: `${from}-${to}`,
|
|
241
|
+
label,
|
|
242
|
+
minValue: from,
|
|
243
|
+
maxValue: to,
|
|
244
|
+
isSelected: false
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return buckets;
|
|
249
|
+
}
|
|
250
|
+
const searchProducts = makeJayQuery("wixStoresV1.searchProducts").withServices(WIX_STORES_V1_SERVICE_MARKER).withHandler(
|
|
251
|
+
async (input, wixStores) => {
|
|
252
|
+
const { query, filters = {}, sortBy = "relevance", page = 1, pageSize = 12 } = input;
|
|
253
|
+
try {
|
|
254
|
+
const buildBaseQuery = () => {
|
|
255
|
+
let q = wixStores.products.queryProducts();
|
|
256
|
+
if (query && query.trim().length > 0) {
|
|
257
|
+
q = q.startsWith("name", query.trim());
|
|
258
|
+
}
|
|
259
|
+
if (filters.collectionIds && filters.collectionIds.length > 0) {
|
|
260
|
+
q = q.hasSome("collectionIds", filters.collectionIds);
|
|
261
|
+
}
|
|
262
|
+
return q;
|
|
263
|
+
};
|
|
264
|
+
const buildProductsQuery = () => {
|
|
265
|
+
let q = buildBaseQuery().limit(pageSize).skip((page - 1) * pageSize);
|
|
266
|
+
if (filters.minPrice !== void 0 && filters.minPrice > 0) {
|
|
267
|
+
q = q.ge("priceData.price", filters.minPrice);
|
|
268
|
+
}
|
|
269
|
+
if (filters.maxPrice !== void 0 && filters.maxPrice > 0) {
|
|
270
|
+
q = q.le("priceData.price", filters.maxPrice);
|
|
271
|
+
}
|
|
272
|
+
switch (sortBy) {
|
|
273
|
+
case "price_asc":
|
|
274
|
+
q = q.ascending("price");
|
|
275
|
+
break;
|
|
276
|
+
case "price_desc":
|
|
277
|
+
q = q.descending("price");
|
|
278
|
+
break;
|
|
279
|
+
case "name_asc":
|
|
280
|
+
q = q.ascending("name");
|
|
281
|
+
break;
|
|
282
|
+
case "name_desc":
|
|
283
|
+
q = q.descending("name");
|
|
284
|
+
break;
|
|
285
|
+
case "newest":
|
|
286
|
+
q = q.descending("lastUpdated");
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
return q;
|
|
290
|
+
};
|
|
291
|
+
const minPriceQuery = buildBaseQuery().ascending("price").limit(1).find();
|
|
292
|
+
const maxPriceQuery = buildBaseQuery().descending("price").limit(1).find();
|
|
293
|
+
const [result, minPriceResult, maxPriceResult] = await Promise.all([
|
|
294
|
+
buildProductsQuery().find(),
|
|
295
|
+
minPriceQuery,
|
|
296
|
+
maxPriceQuery
|
|
297
|
+
]);
|
|
298
|
+
const products2 = result.items || [];
|
|
299
|
+
const minBound = minPriceResult.items?.[0]?.price?.price ?? minPriceResult.items?.[0]?.priceData?.price ?? 0;
|
|
300
|
+
const maxBound = maxPriceResult.items?.[0]?.price?.price ?? maxPriceResult.items?.[0]?.priceData?.price ?? 0;
|
|
301
|
+
const currency = products2[0]?.price?.currency || products2[0]?.priceData?.currency || minPriceResult.items?.[0]?.price?.currency;
|
|
302
|
+
const currencySymbol = currency === "ILS" ? "₪" : currency === "USD" ? "$" : currency === "EUR" ? "€" : currency === "GBP" ? "£" : "$";
|
|
303
|
+
const ranges = generatePriceBuckets(minBound, maxBound, currencySymbol);
|
|
304
|
+
const totalCount = result.totalCount ?? result.items?.length ?? 0;
|
|
305
|
+
const totalPages = Math.ceil(totalCount / pageSize);
|
|
306
|
+
const mappedProducts = products2.map((p) => mapProductToCard(p));
|
|
307
|
+
return {
|
|
308
|
+
products: mappedProducts,
|
|
309
|
+
totalCount,
|
|
310
|
+
currentPage: page,
|
|
311
|
+
totalPages,
|
|
312
|
+
hasMore: page < totalPages,
|
|
313
|
+
priceAggregation: { minBound, maxBound, ranges }
|
|
314
|
+
};
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error("[wixStoresV1.searchProducts] Search failed:", error);
|
|
317
|
+
throw new ActionError("SEARCH_FAILED", "Failed to search products");
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
);
|
|
321
|
+
const getProductBySlug = makeJayQuery("wixStoresV1.getProductBySlug").withServices(WIX_STORES_V1_SERVICE_MARKER).withCaching({ maxAge: 300, staleWhileRevalidate: 600 }).withHandler(
|
|
322
|
+
async (input, wixStores) => {
|
|
323
|
+
const { slug } = input;
|
|
324
|
+
if (!slug) {
|
|
325
|
+
throw new ActionError("INVALID_INPUT", "Product slug is required");
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
let result = await wixStores.products.queryProducts().eq("slug", slug).limit(1).find();
|
|
329
|
+
if (!result.items?.length) {
|
|
330
|
+
result = await wixStores.products.queryProducts().eq("_id", slug).limit(1).find();
|
|
331
|
+
}
|
|
332
|
+
const product = result.items?.[0];
|
|
333
|
+
if (!product) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
return mapProductToCard(product);
|
|
337
|
+
} catch (error) {
|
|
338
|
+
console.error("[wixStoresV1.getProductBySlug] Failed to get product:", error);
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
);
|
|
343
|
+
const getCollections = makeJayQuery("wixStoresV1.getCollections").withServices(WIX_STORES_V1_SERVICE_MARKER).withCaching({ maxAge: 3600 }).withHandler(
|
|
344
|
+
async (_input, wixStores) => {
|
|
345
|
+
try {
|
|
346
|
+
const result = await wixStores.collections.queryCollections().find();
|
|
347
|
+
return (result.items || []).map((col) => mapCollectionToViewState(col));
|
|
348
|
+
} catch (error) {
|
|
349
|
+
console.error("[wixStoresV1.getCollections] Failed to load collections:", error);
|
|
350
|
+
throw new ActionError("LOAD_FAILED", "Failed to load collections");
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
);
|
|
354
|
+
var ProductType = /* @__PURE__ */ ((ProductType2) => {
|
|
355
|
+
ProductType2[ProductType2["PHYSICAL"] = 0] = "PHYSICAL";
|
|
356
|
+
ProductType2[ProductType2["DIGITAL"] = 1] = "DIGITAL";
|
|
357
|
+
return ProductType2;
|
|
358
|
+
})(ProductType || {});
|
|
359
|
+
var StockStatus = /* @__PURE__ */ ((StockStatus2) => {
|
|
360
|
+
StockStatus2[StockStatus2["OUT_OF_STOCK"] = 0] = "OUT_OF_STOCK";
|
|
361
|
+
StockStatus2[StockStatus2["IN_STOCK"] = 1] = "IN_STOCK";
|
|
362
|
+
return StockStatus2;
|
|
363
|
+
})(StockStatus || {});
|
|
364
|
+
var OptionRenderType = /* @__PURE__ */ ((OptionRenderType2) => {
|
|
365
|
+
OptionRenderType2[OptionRenderType2["TEXT_CHOICES"] = 0] = "TEXT_CHOICES";
|
|
366
|
+
OptionRenderType2[OptionRenderType2["COLOR_SWATCH_CHOICES"] = 1] = "COLOR_SWATCH_CHOICES";
|
|
367
|
+
return OptionRenderType2;
|
|
368
|
+
})(OptionRenderType || {});
|
|
369
|
+
var ChoiceType = /* @__PURE__ */ ((ChoiceType2) => {
|
|
370
|
+
ChoiceType2[ChoiceType2["CHOICE_TEXT"] = 0] = "CHOICE_TEXT";
|
|
371
|
+
ChoiceType2[ChoiceType2["ONE_COLOR"] = 1] = "ONE_COLOR";
|
|
372
|
+
return ChoiceType2;
|
|
373
|
+
})(ChoiceType || {});
|
|
374
|
+
var ChoiceType = /* @__PURE__ */ ((ChoiceType2) => {
|
|
375
|
+
ChoiceType2[ChoiceType2["CHOICE_TEXT"] = 0] = "CHOICE_TEXT";
|
|
376
|
+
ChoiceType2[ChoiceType2["ONE_COLOR"] = 1] = "ONE_COLOR";
|
|
377
|
+
return ChoiceType2;
|
|
378
|
+
})(ChoiceType || {});
|
|
379
|
+
var Selected = /* @__PURE__ */ ((Selected2) => {
|
|
380
|
+
Selected2[Selected2["selected"] = 0] = "selected";
|
|
381
|
+
Selected2[Selected2["notSelected"] = 1] = "notSelected";
|
|
382
|
+
return Selected2;
|
|
383
|
+
})(Selected || {});
|
|
384
|
+
var MediaType$1 = /* @__PURE__ */ ((MediaType2) => {
|
|
385
|
+
MediaType2[MediaType2["IMAGE"] = 0] = "IMAGE";
|
|
386
|
+
MediaType2[MediaType2["VIDEO"] = 1] = "VIDEO";
|
|
387
|
+
return MediaType2;
|
|
388
|
+
})(MediaType$1 || {});
|
|
389
|
+
function mapProductType(productType) {
|
|
390
|
+
return productType === "digital" ? ProductType.DIGITAL : ProductType.PHYSICAL;
|
|
391
|
+
}
|
|
392
|
+
function mapInfoSections(sections) {
|
|
393
|
+
return (sections || []).map((section, index) => ({
|
|
394
|
+
_id: String(index),
|
|
395
|
+
title: section.title || "",
|
|
396
|
+
plainDescription: section.description || "",
|
|
397
|
+
uniqueName: section.title || ""
|
|
398
|
+
}));
|
|
399
|
+
}
|
|
400
|
+
function mapMedia(product) {
|
|
401
|
+
const mainMedia = product.media?.mainMedia;
|
|
402
|
+
const mediaItems = product.media?.items || [];
|
|
403
|
+
const mainUrl = mainMedia?.image?.url || "";
|
|
404
|
+
const mainThumbnail = mainMedia?.thumbnail?.url || "";
|
|
405
|
+
const mainMediaType = mainMedia?.mediaType === "video" ? MediaType$1.VIDEO : MediaType$1.IMAGE;
|
|
406
|
+
return {
|
|
407
|
+
selectedMedia: {
|
|
408
|
+
url: mainUrl,
|
|
409
|
+
mediaType: mainMediaType,
|
|
410
|
+
thumbnail_50x50: mainThumbnail
|
|
411
|
+
},
|
|
412
|
+
availableMedia: mediaItems.map((item, index) => ({
|
|
413
|
+
mediaId: item._id || String(index),
|
|
414
|
+
media: {
|
|
415
|
+
url: item.image?.url || "",
|
|
416
|
+
mediaType: item.mediaType === "video" ? MediaType$1.VIDEO : MediaType$1.IMAGE,
|
|
417
|
+
thumbnail_50x50: item.thumbnail?.url || ""
|
|
418
|
+
},
|
|
419
|
+
selected: item._id === mainMedia?._id ? Selected.selected : Selected.notSelected
|
|
420
|
+
}))
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
function mapOptionsToSlowVS(product) {
|
|
424
|
+
return (product.productOptions || []).map((option) => ({
|
|
425
|
+
_id: option.name || "",
|
|
426
|
+
name: option.name || "",
|
|
427
|
+
optionRenderType: option.optionType === "color" ? OptionRenderType.COLOR_SWATCH_CHOICES : OptionRenderType.TEXT_CHOICES,
|
|
428
|
+
choices: (option.choices || []).map((choice) => ({
|
|
429
|
+
choiceId: choice.value || "",
|
|
430
|
+
name: choice.value || "",
|
|
431
|
+
choiceType: option.optionType === "color" ? ChoiceType.ONE_COLOR : ChoiceType.CHOICE_TEXT,
|
|
432
|
+
inStock: choice.inStock ?? true,
|
|
433
|
+
colorCode: ""
|
|
434
|
+
}))
|
|
435
|
+
}));
|
|
436
|
+
}
|
|
437
|
+
function mapOptionsToFastVS(product) {
|
|
438
|
+
return (product.productOptions || []).map((option) => ({
|
|
439
|
+
_id: option.name || "",
|
|
440
|
+
textChoiceSelection: void 0,
|
|
441
|
+
choices: (option.choices || []).map((choice) => ({
|
|
442
|
+
choiceId: choice.value || "",
|
|
443
|
+
isSelected: false
|
|
444
|
+
}))
|
|
445
|
+
}));
|
|
446
|
+
}
|
|
447
|
+
function mapVariants(product) {
|
|
448
|
+
return (product.variants || []).map((variant) => ({
|
|
449
|
+
_id: variant._id || "",
|
|
450
|
+
sku: variant.variant?.sku || "",
|
|
451
|
+
price: variant.variant?.priceData?.formatted?.discountedPrice || variant.variant?.priceData?.formatted?.price || "",
|
|
452
|
+
strikethroughPrice: variant.variant?.priceData?.discountedPrice < variant.variant?.priceData?.price ? variant.variant?.priceData?.formatted?.price || "" : "",
|
|
453
|
+
choices: variant.choices || {},
|
|
454
|
+
inventoryStatus: variant.stock?.inStock ? StockStatus.IN_STOCK : StockStatus.OUT_OF_STOCK
|
|
455
|
+
}));
|
|
456
|
+
}
|
|
457
|
+
async function* loadProductParams([wixStores]) {
|
|
458
|
+
try {
|
|
459
|
+
let result = await wixStores.products.queryProducts().find();
|
|
460
|
+
yield result.items.map((product) => ({ slug: product.slug || "" }));
|
|
461
|
+
while (result.hasNext()) {
|
|
462
|
+
result = await result.next();
|
|
463
|
+
yield result.items.map((product) => ({ slug: product.slug || "" }));
|
|
464
|
+
}
|
|
465
|
+
} catch (error) {
|
|
466
|
+
console.error("[ProductPage V1] Failed to load product slugs:", error);
|
|
467
|
+
yield [];
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
async function renderSlowlyChanging$3(props, wixStores) {
|
|
471
|
+
const Pipeline = RenderPipeline.for();
|
|
472
|
+
return Pipeline.try(async () => {
|
|
473
|
+
const bySlug = await wixStores.products.queryProducts().eq("slug", props.slug).limit(1).find();
|
|
474
|
+
if (bySlug.items?.length)
|
|
475
|
+
return bySlug;
|
|
476
|
+
return wixStores.products.queryProducts().eq("_id", props.slug).limit(1).find();
|
|
477
|
+
}).recover((error) => {
|
|
478
|
+
console.error("[ProductPage V1] Error loading product:", error);
|
|
479
|
+
return Pipeline.clientError(404, "Product not found");
|
|
480
|
+
}).toPhaseOutput((result) => {
|
|
481
|
+
const product = result.items?.[0];
|
|
482
|
+
if (!product) {
|
|
483
|
+
throw new Error("Product not found");
|
|
484
|
+
}
|
|
485
|
+
const variants = mapVariants(product);
|
|
486
|
+
const stockStatus = product.stock?.inStock ? StockStatus.IN_STOCK : StockStatus.OUT_OF_STOCK;
|
|
487
|
+
return {
|
|
488
|
+
viewState: {
|
|
489
|
+
_id: product._id || "",
|
|
490
|
+
productName: product.name || "",
|
|
491
|
+
description: product.description || "",
|
|
492
|
+
brand: product.brand || "",
|
|
493
|
+
ribbon: product.ribbon || "",
|
|
494
|
+
productType: mapProductType(product.productType),
|
|
495
|
+
options: mapOptionsToSlowVS(product),
|
|
496
|
+
infoSections: mapInfoSections(product.additionalInfoSections),
|
|
497
|
+
modifiers: [],
|
|
498
|
+
// V1 doesn't have modifiers in same format
|
|
499
|
+
seoData: { tags: [], settings: { preventAutoRedirect: false, keywords: [] } }
|
|
500
|
+
},
|
|
501
|
+
carryForward: {
|
|
502
|
+
productId: product._id || "",
|
|
503
|
+
mediaGallery: mapMedia(product),
|
|
504
|
+
options: mapOptionsToFastVS(product),
|
|
505
|
+
pricePerUnit: "",
|
|
506
|
+
stockStatus,
|
|
507
|
+
variants
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
async function renderFastChanging$2(props, slowCarryForward, wixStores) {
|
|
513
|
+
const Pipeline = RenderPipeline.for();
|
|
514
|
+
const isInStock = slowCarryForward.stockStatus === StockStatus.IN_STOCK;
|
|
515
|
+
const firstVariant = slowCarryForward.variants[0];
|
|
516
|
+
return Pipeline.ok({
|
|
517
|
+
actionsEnabled: isInStock,
|
|
518
|
+
options: slowCarryForward.options,
|
|
519
|
+
modifiers: [],
|
|
520
|
+
mediaGallery: slowCarryForward.mediaGallery,
|
|
521
|
+
sku: firstVariant?.sku || "",
|
|
522
|
+
price: firstVariant?.price || "",
|
|
523
|
+
pricePerUnit: slowCarryForward.pricePerUnit,
|
|
524
|
+
stockStatus: slowCarryForward.stockStatus,
|
|
525
|
+
strikethroughPrice: firstVariant?.strikethroughPrice || "",
|
|
526
|
+
quantity: { quantity: 1 }
|
|
527
|
+
}).toPhaseOutput((viewState) => ({
|
|
528
|
+
viewState,
|
|
529
|
+
carryForward: {
|
|
530
|
+
productId: slowCarryForward.productId,
|
|
531
|
+
variants: slowCarryForward.variants
|
|
532
|
+
}
|
|
533
|
+
}));
|
|
534
|
+
}
|
|
535
|
+
const productPage = makeJayStackComponent().withProps().withServices(WIX_STORES_V1_SERVICE_MARKER).withLoadParams(loadProductParams).withSlowlyRender(renderSlowlyChanging$3).withFastRender(renderFastChanging$2);
|
|
536
|
+
var CurrentSort = /* @__PURE__ */ ((CurrentSort2) => {
|
|
537
|
+
CurrentSort2[CurrentSort2["relevance"] = 0] = "relevance";
|
|
538
|
+
CurrentSort2[CurrentSort2["priceAsc"] = 1] = "priceAsc";
|
|
539
|
+
CurrentSort2[CurrentSort2["priceDesc"] = 2] = "priceDesc";
|
|
540
|
+
CurrentSort2[CurrentSort2["newest"] = 3] = "newest";
|
|
541
|
+
CurrentSort2[CurrentSort2["nameAsc"] = 4] = "nameAsc";
|
|
542
|
+
CurrentSort2[CurrentSort2["nameDesc"] = 5] = "nameDesc";
|
|
543
|
+
return CurrentSort2;
|
|
544
|
+
})(CurrentSort || {});
|
|
545
|
+
const PAGE_SIZE$1 = 12;
|
|
546
|
+
async function renderSlowlyChanging$2(props, wixStores) {
|
|
547
|
+
const Pipeline = RenderPipeline.for();
|
|
548
|
+
return Pipeline.try(async () => {
|
|
549
|
+
const collectionsResult = await wixStores.collections.queryCollections().find();
|
|
550
|
+
return collectionsResult.items || [];
|
|
551
|
+
}).recover((error) => {
|
|
552
|
+
console.error("[ProductSearch V1] Failed to load collections:", error);
|
|
553
|
+
return Pipeline.ok([]);
|
|
554
|
+
}).toPhaseOutput((collections2) => {
|
|
555
|
+
const collectionInfos = collections2.map((col) => ({
|
|
556
|
+
categoryId: col._id || "",
|
|
557
|
+
categoryName: col.name || "",
|
|
558
|
+
categorySlug: col.slug || ""
|
|
559
|
+
}));
|
|
560
|
+
return {
|
|
561
|
+
viewState: {
|
|
562
|
+
searchFields: "name,description,sku",
|
|
563
|
+
fuzzySearch: false,
|
|
564
|
+
// V1 doesn't support fuzzy search
|
|
565
|
+
emptyStateMessage: "Enter a search term to find products",
|
|
566
|
+
filters: {
|
|
567
|
+
categoryFilter: {
|
|
568
|
+
categories: collectionInfos
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
carryForward: {
|
|
573
|
+
searchFields: "name,description,sku",
|
|
574
|
+
fuzzySearch: false,
|
|
575
|
+
collections: collectionInfos
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
async function renderFastChanging$1(props, slowCarryForward, _wixStores) {
|
|
581
|
+
const Pipeline = RenderPipeline.for();
|
|
582
|
+
return Pipeline.try(async () => {
|
|
583
|
+
const result = await searchProducts({
|
|
584
|
+
query: "",
|
|
585
|
+
pageSize: PAGE_SIZE$1,
|
|
586
|
+
page: 1
|
|
587
|
+
});
|
|
588
|
+
return result;
|
|
589
|
+
}).recover((error) => {
|
|
590
|
+
console.error("[ProductSearch V1] Failed to load products:", error);
|
|
591
|
+
return Pipeline.ok({
|
|
592
|
+
products: [],
|
|
593
|
+
totalCount: 0,
|
|
594
|
+
currentPage: 1,
|
|
595
|
+
totalPages: 0,
|
|
596
|
+
hasMore: false,
|
|
597
|
+
priceAggregation: {
|
|
598
|
+
minBound: 0,
|
|
599
|
+
maxBound: 1e4,
|
|
600
|
+
ranges: [
|
|
601
|
+
{
|
|
602
|
+
rangeId: "all",
|
|
603
|
+
label: "Show all",
|
|
604
|
+
minValue: null,
|
|
605
|
+
maxValue: null,
|
|
606
|
+
productCount: 0,
|
|
607
|
+
isSelected: true
|
|
608
|
+
}
|
|
609
|
+
]
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
}).toPhaseOutput((result) => {
|
|
613
|
+
return {
|
|
614
|
+
viewState: {
|
|
615
|
+
searchExpression: "",
|
|
616
|
+
isSearching: false,
|
|
617
|
+
hasSearched: false,
|
|
618
|
+
searchResults: result.products,
|
|
619
|
+
resultCount: result.products.length,
|
|
620
|
+
hasResults: result.products.length > 0,
|
|
621
|
+
hasSuggestions: false,
|
|
622
|
+
suggestions: [],
|
|
623
|
+
filters: {
|
|
624
|
+
priceRange: {
|
|
625
|
+
minPrice: 0,
|
|
626
|
+
maxPrice: 0,
|
|
627
|
+
minBound: result.priceAggregation?.minBound ?? 0,
|
|
628
|
+
maxBound: result.priceAggregation?.maxBound ?? 1e4,
|
|
629
|
+
ranges: result.priceAggregation?.ranges ?? [
|
|
630
|
+
{
|
|
631
|
+
rangeId: "all",
|
|
632
|
+
label: "Show all",
|
|
633
|
+
minValue: null,
|
|
634
|
+
maxValue: null,
|
|
635
|
+
isSelected: true
|
|
636
|
+
}
|
|
637
|
+
]
|
|
638
|
+
},
|
|
639
|
+
categoryFilter: {
|
|
640
|
+
categories: slowCarryForward.collections.map((col) => ({
|
|
641
|
+
categoryId: col.categoryId,
|
|
642
|
+
isSelected: false
|
|
643
|
+
}))
|
|
644
|
+
}
|
|
645
|
+
},
|
|
646
|
+
sortBy: {
|
|
647
|
+
currentSort: CurrentSort.relevance
|
|
648
|
+
},
|
|
649
|
+
hasMore: result.hasMore,
|
|
650
|
+
loadedCount: result.products.length,
|
|
651
|
+
totalCount: result.totalCount
|
|
652
|
+
},
|
|
653
|
+
carryForward: {
|
|
654
|
+
searchFields: slowCarryForward.searchFields,
|
|
655
|
+
fuzzySearch: slowCarryForward.fuzzySearch,
|
|
656
|
+
collections: slowCarryForward.collections
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
const productSearch = makeJayStackComponent().withProps().withServices(WIX_STORES_V1_SERVICE_MARKER).withSlowlyRender(renderSlowlyChanging$2).withFastRender(renderFastChanging$1);
|
|
662
|
+
async function renderSlowlyChanging$1(props, wixStores) {
|
|
663
|
+
const Pipeline = RenderPipeline.for();
|
|
664
|
+
return Pipeline.try(async () => {
|
|
665
|
+
const result = await wixStores.collections.queryCollections().find();
|
|
666
|
+
return result.items || [];
|
|
667
|
+
}).recover((error) => {
|
|
668
|
+
console.error("[CollectionList V1] Failed to load collections:", error);
|
|
669
|
+
return Pipeline.ok([]);
|
|
670
|
+
}).toPhaseOutput((collections2) => {
|
|
671
|
+
const collectionItems = collections2.map((col) => {
|
|
672
|
+
const imageUrl = col.media?.mainMedia?.image?.url || "";
|
|
673
|
+
return {
|
|
674
|
+
_id: col._id || "",
|
|
675
|
+
name: col.name || "",
|
|
676
|
+
slug: col.slug || "",
|
|
677
|
+
description: col.description || "",
|
|
678
|
+
productCount: col.numberOfProducts || 0,
|
|
679
|
+
imageUrl,
|
|
680
|
+
hasImage: !!imageUrl
|
|
681
|
+
};
|
|
682
|
+
});
|
|
683
|
+
return {
|
|
684
|
+
viewState: {
|
|
685
|
+
// Reuse 'categories' field from contract for compatibility
|
|
686
|
+
categories: collectionItems,
|
|
687
|
+
hasCategories: collectionItems.length > 0
|
|
688
|
+
},
|
|
689
|
+
carryForward: {}
|
|
690
|
+
};
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
const collectionList = makeJayStackComponent().withProps().withServices(WIX_STORES_V1_SERVICE_MARKER).withSlowlyRender(renderSlowlyChanging$1);
|
|
694
|
+
const categoryList = collectionList;
|
|
695
|
+
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
696
|
+
MediaType2[MediaType2["IMAGE"] = 0] = "IMAGE";
|
|
697
|
+
MediaType2[MediaType2["VIDEO"] = 1] = "VIDEO";
|
|
698
|
+
MediaType2[MediaType2["AUDIO"] = 2] = "AUDIO";
|
|
699
|
+
MediaType2[MediaType2["DOCUMENT"] = 3] = "DOCUMENT";
|
|
700
|
+
MediaType2[MediaType2["ZIP"] = 4] = "ZIP";
|
|
701
|
+
return MediaType2;
|
|
702
|
+
})(MediaType || {});
|
|
703
|
+
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
704
|
+
MediaType2[MediaType2["IMAGE"] = 0] = "IMAGE";
|
|
705
|
+
MediaType2[MediaType2["VIDEO"] = 1] = "VIDEO";
|
|
706
|
+
MediaType2[MediaType2["AUDIO"] = 2] = "AUDIO";
|
|
707
|
+
MediaType2[MediaType2["DOCUMENT"] = 3] = "DOCUMENT";
|
|
708
|
+
MediaType2[MediaType2["ZIP"] = 4] = "ZIP";
|
|
709
|
+
return MediaType2;
|
|
710
|
+
})(MediaType || {});
|
|
711
|
+
const PAGE_SIZE = 20;
|
|
712
|
+
async function* loadCollectionParams([wixStores]) {
|
|
713
|
+
try {
|
|
714
|
+
const result = await wixStores.collections.queryCollections().find();
|
|
715
|
+
yield (result.items || []).filter((col) => col.slug).map((col) => ({ slug: col.slug }));
|
|
716
|
+
} catch (error) {
|
|
717
|
+
console.error("[CollectionPage V1] Failed to load collection slugs:", error);
|
|
718
|
+
yield [];
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
async function loadCollectionProducts(collectionId, wixStores, offset = 0) {
|
|
722
|
+
const result = await wixStores.products.queryProducts().hasSome("collectionIds", [collectionId]).skip(offset).limit(PAGE_SIZE).find();
|
|
723
|
+
const products2 = (result.items || []).map((product) => mapProductToCard(product, "/products"));
|
|
724
|
+
return {
|
|
725
|
+
products: products2,
|
|
726
|
+
total: result.totalCount || products2.length
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
function mapCollectionMedia(collection) {
|
|
730
|
+
const mainMedia = collection.media?.mainMedia;
|
|
731
|
+
return {
|
|
732
|
+
mainMedia: mainMedia?.image?.url ? {
|
|
733
|
+
_id: "",
|
|
734
|
+
url: mainMedia.image.url,
|
|
735
|
+
altText: collection.name || "",
|
|
736
|
+
mediaType: MediaType.IMAGE
|
|
737
|
+
} : void 0,
|
|
738
|
+
items: []
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
async function renderSlowlyChanging(props, wixStores) {
|
|
742
|
+
const Pipeline = RenderPipeline.for();
|
|
743
|
+
return Pipeline.try(async () => {
|
|
744
|
+
const result = await wixStores.collections.queryCollections().find();
|
|
745
|
+
const collection = (result.items || []).find((col) => col.slug === props.slug);
|
|
746
|
+
if (!collection) {
|
|
747
|
+
throw new Error("Collection not found");
|
|
748
|
+
}
|
|
749
|
+
const productData = await loadCollectionProducts(collection._id, wixStores, 0);
|
|
750
|
+
return { collection, productData };
|
|
751
|
+
}).recover((error) => {
|
|
752
|
+
console.error("[CollectionPage V1] Failed to load collection:", error);
|
|
753
|
+
return Pipeline.clientError(404, "Collection not found");
|
|
754
|
+
}).toPhaseOutput((data) => {
|
|
755
|
+
const { collection, productData } = data;
|
|
756
|
+
const breadcrumbs = [
|
|
757
|
+
{
|
|
758
|
+
categoryId: collection._id || "",
|
|
759
|
+
categoryName: collection.name || "",
|
|
760
|
+
categorySlug: collection.slug || ""
|
|
761
|
+
}
|
|
762
|
+
];
|
|
763
|
+
const media = mapCollectionMedia(collection);
|
|
764
|
+
return {
|
|
765
|
+
viewState: {
|
|
766
|
+
_id: collection._id || "",
|
|
767
|
+
name: collection.name || "",
|
|
768
|
+
description: collection.description || "",
|
|
769
|
+
slug: collection.slug || "",
|
|
770
|
+
visible: true,
|
|
771
|
+
numberOfProducts: collection.numberOfProducts || productData.total,
|
|
772
|
+
hasImage: !!media.mainMedia?.url,
|
|
773
|
+
media,
|
|
774
|
+
breadcrumbs,
|
|
775
|
+
products: productData.products
|
|
776
|
+
},
|
|
777
|
+
carryForward: {
|
|
778
|
+
collectionId: collection._id || "",
|
|
779
|
+
collectionSlug: collection.slug || "",
|
|
780
|
+
totalProducts: productData.total,
|
|
781
|
+
products: productData.products,
|
|
782
|
+
currentOffset: productData.products.length
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
async function renderFastChanging(props, slowCarryForward, _wixStores) {
|
|
788
|
+
const Pipeline = RenderPipeline.for();
|
|
789
|
+
const hasMore = slowCarryForward.currentOffset < slowCarryForward.totalProducts;
|
|
790
|
+
return Pipeline.ok(slowCarryForward).toPhaseOutput((data) => {
|
|
791
|
+
return {
|
|
792
|
+
viewState: {
|
|
793
|
+
// Products array with fast+interactive properties for SSR items
|
|
794
|
+
products: data.products.map((p) => ({
|
|
795
|
+
_id: p._id,
|
|
796
|
+
price: p.price,
|
|
797
|
+
strikethroughPrice: p.strikethroughPrice,
|
|
798
|
+
isAddingToCart: false,
|
|
799
|
+
quickOption: p.quickOption ? {
|
|
800
|
+
choices: p.quickOption.choices.map((c) => ({
|
|
801
|
+
choiceId: c.choiceId,
|
|
802
|
+
inStock: c.inStock,
|
|
803
|
+
isSelected: c.isSelected
|
|
804
|
+
}))
|
|
805
|
+
} : { choices: [] }
|
|
806
|
+
})),
|
|
807
|
+
loadedProducts: [],
|
|
808
|
+
hasMore,
|
|
809
|
+
loadedCount: data.products.length,
|
|
810
|
+
isLoading: false,
|
|
811
|
+
hasProducts: data.products.length > 0
|
|
812
|
+
},
|
|
813
|
+
carryForward: {
|
|
814
|
+
collectionId: data.collectionId,
|
|
815
|
+
totalProducts: data.totalProducts,
|
|
816
|
+
currentOffset: data.currentOffset
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
const collectionPage = makeJayStackComponent().withProps().withServices(WIX_STORES_V1_SERVICE_MARKER).withLoadParams(loadCollectionParams).withSlowlyRender(renderSlowlyChanging).withFastRender(renderFastChanging);
|
|
822
|
+
const categoryPage = collectionPage;
|
|
823
|
+
const init = makeJayInit().withServer(async () => {
|
|
824
|
+
console.log("[wix-stores-v1] Initializing Wix Stores V1 service...");
|
|
825
|
+
const wixClient = getService(WIX_CLIENT_SERVICE);
|
|
826
|
+
provideWixStoresV1Service(wixClient);
|
|
827
|
+
console.log("[wix-stores-v1] Server initialization complete");
|
|
828
|
+
return {
|
|
829
|
+
enableClientCart: true,
|
|
830
|
+
enableClientSearch: true
|
|
831
|
+
};
|
|
832
|
+
});
|
|
833
|
+
export {
|
|
834
|
+
WIX_CART_CONTEXT,
|
|
835
|
+
WIX_CART_SERVICE,
|
|
836
|
+
WIX_STORES_V1_CONTEXT,
|
|
837
|
+
WIX_STORES_V1_SERVICE_MARKER,
|
|
838
|
+
cartIndicator,
|
|
839
|
+
cartPage,
|
|
840
|
+
categoryList,
|
|
841
|
+
categoryPage,
|
|
842
|
+
collectionList,
|
|
843
|
+
collectionPage,
|
|
844
|
+
getCollections,
|
|
845
|
+
getProductBySlug,
|
|
846
|
+
init,
|
|
847
|
+
productPage,
|
|
848
|
+
productSearch,
|
|
849
|
+
provideWixCartContext,
|
|
850
|
+
provideWixCartService,
|
|
851
|
+
provideWixStoresV1Service,
|
|
852
|
+
searchProducts
|
|
853
|
+
};
|