@jay-framework/wix-stores-v1 0.19.7 → 0.21.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/dist/index.client.js +92 -30
- package/dist/index.d.ts +33 -164
- package/dist/index.js +194 -127
- package/package.json +15 -17
package/dist/index.client.js
CHANGED
|
@@ -4,8 +4,7 @@ import { makeJayStackComponent, makeJayInit } from "@jay-framework/fullstack-com
|
|
|
4
4
|
import { registerReactiveGlobalContext, createSignal, createMemo, createEffect } from "@jay-framework/component";
|
|
5
5
|
import { patch, REPLACE } from "@jay-framework/json-patch";
|
|
6
6
|
import { createJayContext, useGlobalContext } from "@jay-framework/runtime";
|
|
7
|
-
import { WIX_CLIENT_CONTEXT } from "@jay-framework/wix-server-client/client";
|
|
8
|
-
import { products, collections } from "@wix/stores";
|
|
7
|
+
import { wixFetch, WIX_CLIENT_CONTEXT } from "@jay-framework/wix-server-client/client";
|
|
9
8
|
import { createActionCaller } from "@jay-framework/stack-client-runtime";
|
|
10
9
|
var StockStatus = /* @__PURE__ */ ((StockStatus2) => {
|
|
11
10
|
StockStatus2[StockStatus2["OUT_OF_STOCK"] = 0] = "OUT_OF_STOCK";
|
|
@@ -17,21 +16,82 @@ var Selected = /* @__PURE__ */ ((Selected2) => {
|
|
|
17
16
|
Selected2[Selected2["notSelected"] = 1] = "notSelected";
|
|
18
17
|
return Selected2;
|
|
19
18
|
})(Selected || {});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
function normalizeProduct(product) {
|
|
20
|
+
const p = { ...product };
|
|
21
|
+
const raw = product;
|
|
22
|
+
if (raw.id && !p._id) {
|
|
23
|
+
p._id = raw.id;
|
|
24
|
+
}
|
|
25
|
+
return p;
|
|
26
|
+
}
|
|
27
|
+
async function queryProducts(client, request) {
|
|
28
|
+
const query = {};
|
|
29
|
+
if (request?.filter) query.filter = JSON.stringify(request.filter);
|
|
30
|
+
if (request?.sort) {
|
|
31
|
+
const v1Sort = request.sort.map((s) => ({
|
|
32
|
+
[s.fieldName]: (s.order || "ASC").toLowerCase()
|
|
33
|
+
}));
|
|
34
|
+
query.sort = JSON.stringify(v1Sort);
|
|
27
35
|
}
|
|
28
|
-
|
|
36
|
+
if (request?.paging) query.paging = request.paging;
|
|
37
|
+
const result = await wixFetch(client, "/stores/v1/products/query", {
|
|
38
|
+
method: "POST",
|
|
39
|
+
body: {
|
|
40
|
+
query,
|
|
41
|
+
includeVariants: request?.includeVariants ?? true,
|
|
42
|
+
includeMerchantSpecificData: request?.includeMerchantSpecificData ?? true
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
if (result.products) {
|
|
46
|
+
result.products = result.products.map(
|
|
47
|
+
(p) => normalizeProduct(p)
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
29
51
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
52
|
+
async function getProduct(client, productId, options) {
|
|
53
|
+
const params = new URLSearchParams();
|
|
54
|
+
const qs = params.toString();
|
|
55
|
+
const result = await wixFetch(
|
|
56
|
+
client,
|
|
57
|
+
`/stores/v1/products/${productId}${qs ? "?" + qs : ""}`,
|
|
58
|
+
{ method: "GET" }
|
|
59
|
+
);
|
|
60
|
+
if (result.product) {
|
|
61
|
+
const raw = result.product;
|
|
62
|
+
if (raw.id && !result.product._id) {
|
|
63
|
+
result.product._id = raw.id;
|
|
64
|
+
}
|
|
33
65
|
}
|
|
34
|
-
return
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
function normalizeCollection(col) {
|
|
69
|
+
const c = { ...col };
|
|
70
|
+
if (col.id && !c._id) {
|
|
71
|
+
c._id = col.id;
|
|
72
|
+
}
|
|
73
|
+
return c;
|
|
74
|
+
}
|
|
75
|
+
async function queryCollections(client, request) {
|
|
76
|
+
const query = {};
|
|
77
|
+
const result = await wixFetch(
|
|
78
|
+
client,
|
|
79
|
+
"/stores/v1/collections/query",
|
|
80
|
+
{
|
|
81
|
+
method: "POST",
|
|
82
|
+
body: {
|
|
83
|
+
query,
|
|
84
|
+
includeNumberOfProducts: true,
|
|
85
|
+
includeDescription: true
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
if (result.collections) {
|
|
90
|
+
result.collections = result.collections.map(
|
|
91
|
+
(c) => normalizeCollection(c)
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
35
95
|
}
|
|
36
96
|
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
37
97
|
MediaType2[MediaType2["IMAGE"] = 0] = "IMAGE";
|
|
@@ -71,6 +131,9 @@ var ChoiceType = /* @__PURE__ */ ((ChoiceType2) => {
|
|
|
71
131
|
ChoiceType2[ChoiceType2["ONE_COLOR"] = 1] = "ONE_COLOR";
|
|
72
132
|
return ChoiceType2;
|
|
73
133
|
})(ChoiceType || {});
|
|
134
|
+
function stripWixMediaResize(url) {
|
|
135
|
+
return url.replace(/\/v1\/(?:fit|fill|crop)\/[^/]+\/file\.\w+$/, "");
|
|
136
|
+
}
|
|
74
137
|
function mapAvailabilityStatus(status) {
|
|
75
138
|
switch (status) {
|
|
76
139
|
case "OUT_OF_STOCK":
|
|
@@ -145,14 +208,12 @@ function mapProductToCard(product, productPagePath = DEFAULT_PRODUCT_PAGE_PATH)
|
|
|
145
208
|
slug,
|
|
146
209
|
productUrl: slug ? `${productPagePath}/${slug}` : "",
|
|
147
210
|
mainMedia: {
|
|
148
|
-
|
|
149
|
-
url: mainMedia?.image?.url || "",
|
|
211
|
+
url: stripWixMediaResize(mainMedia?.image?.url || ""),
|
|
150
212
|
altText: mainMedia?.title || product.name || "",
|
|
151
213
|
mediaType: mapMediaType(mainMedia?.mediaType)
|
|
152
214
|
},
|
|
153
215
|
thumbnail: {
|
|
154
|
-
|
|
155
|
-
url: mainMedia?.thumbnail?.url || "",
|
|
216
|
+
url: stripWixMediaResize(mainMedia?.thumbnail?.url || ""),
|
|
156
217
|
altText: mainMedia?.title || product.name || "",
|
|
157
218
|
width: mainMedia?.thumbnail?.width || 300,
|
|
158
219
|
height: mainMedia?.thumbnail?.height || 300
|
|
@@ -188,7 +249,7 @@ function mapCollectionToViewState(collection) {
|
|
|
188
249
|
name: collection.name || "",
|
|
189
250
|
slug: collection.slug || "",
|
|
190
251
|
description: collection.description || "",
|
|
191
|
-
imageUrl: collection.media?.mainMedia?.image?.url || "",
|
|
252
|
+
imageUrl: stripWixMediaResize(collection.media?.mainMedia?.image?.url || ""),
|
|
192
253
|
productCount: collection.numberOfProducts || 0
|
|
193
254
|
};
|
|
194
255
|
}
|
|
@@ -197,15 +258,13 @@ function provideWixStoresV1Context() {
|
|
|
197
258
|
const wixClientContext = useGlobalContext(WIX_CLIENT_CONTEXT);
|
|
198
259
|
const wixClient = wixClientContext.client;
|
|
199
260
|
const cartContext = useGlobalContext(WIX_CART_CONTEXT);
|
|
200
|
-
const productsClient = getProductsClient(wixClient);
|
|
201
|
-
const collectionsClient = getCollectionsClient(wixClient);
|
|
202
261
|
const storesContext = registerReactiveGlobalContext(WIX_STORES_V1_CONTEXT, () => {
|
|
203
262
|
async function addToCart(productId, quantity = 1, variantId) {
|
|
204
263
|
console.log(`[WixStoresV1] Adding to cart: ${productId} x ${quantity}`);
|
|
205
264
|
let finalVariantId = variantId;
|
|
206
265
|
let productSlug;
|
|
207
266
|
try {
|
|
208
|
-
const productResult = await
|
|
267
|
+
const productResult = await getProduct(wixClient, productId);
|
|
209
268
|
const product = productResult.product;
|
|
210
269
|
productSlug = product?.slug;
|
|
211
270
|
if (!finalVariantId && product?.variants?.[0]) {
|
|
@@ -221,11 +280,14 @@ function provideWixStoresV1Context() {
|
|
|
221
280
|
}
|
|
222
281
|
async function loadMoreCollectionProducts(collectionId, page, pageSize) {
|
|
223
282
|
try {
|
|
224
|
-
const result = await
|
|
225
|
-
|
|
226
|
-
|
|
283
|
+
const result = await queryProducts(wixClient, {
|
|
284
|
+
filter: { "collections.id": { $hasSome: [collectionId] } },
|
|
285
|
+
paging: { limit: pageSize, offset: (page - 1) * pageSize }
|
|
286
|
+
});
|
|
287
|
+
const products = (result.products || []).map((p) => mapProductToCard(p));
|
|
288
|
+
const totalProducts = result.totalResults ?? products.length;
|
|
227
289
|
const hasMore = page * pageSize < totalProducts;
|
|
228
|
-
return { products
|
|
290
|
+
return { products, hasMore, totalProducts };
|
|
229
291
|
} catch (error) {
|
|
230
292
|
console.error("[WixStoresV1] Failed to load collection products:", error);
|
|
231
293
|
return { products: [], hasMore: false, totalProducts: 0 };
|
|
@@ -233,8 +295,8 @@ function provideWixStoresV1Context() {
|
|
|
233
295
|
}
|
|
234
296
|
async function getCollections() {
|
|
235
297
|
try {
|
|
236
|
-
const result = await
|
|
237
|
-
return (result.
|
|
298
|
+
const result = await queryCollections(wixClient);
|
|
299
|
+
return (result.collections || []).map((col) => mapCollectionToViewState(col));
|
|
238
300
|
} catch (error) {
|
|
239
301
|
console.error("[WixStoresV1] Failed to load collections:", error);
|
|
240
302
|
return [];
|
|
@@ -693,7 +755,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
693
755
|
const productSearch = makeJayStackComponent().withProps().withContexts(WIX_STORES_V1_CONTEXT).withInteractive(ProductSearchInteractive);
|
|
694
756
|
const PAGE_SIZE = 20;
|
|
695
757
|
function CollectionPageInteractive(_props, refs, viewStateSignals, fastCarryForward, storesContext) {
|
|
696
|
-
const { products: [
|
|
758
|
+
const { products: [products], loadedProducts: [loadedProducts, setLoadedProducts], hasMore: [hasMore, setHasMore], loadedCount: [loadedCount, setLoadedCount], isLoading: [isLoading, setIsLoading], hasProducts: [hasProducts, setHasProducts] } = viewStateSignals;
|
|
697
759
|
const { collectionId, totalProducts } = fastCarryForward;
|
|
698
760
|
let currentOffset = fastCarryForward.currentOffset;
|
|
699
761
|
refs.loadMoreButton?.onclick(async () => {
|
|
@@ -763,7 +825,7 @@ function CollectionPageInteractive(_props, refs, viewStateSignals, fastCarryForw
|
|
|
763
825
|
});
|
|
764
826
|
return {
|
|
765
827
|
render: () => ({
|
|
766
|
-
products:
|
|
828
|
+
products: products(),
|
|
767
829
|
loadedProducts: loadedProducts(),
|
|
768
830
|
hasMore: hasMore(),
|
|
769
831
|
loadedCount: loadedCount(),
|
package/dist/index.d.ts
CHANGED
|
@@ -1,73 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CartState } from '@jay-framework/wix-cart';
|
|
2
2
|
export { AddToCartOptions, CartIndicatorState, CartLineItem, CartState, CartSummary, WIX_CART_CONTEXT, WIX_CART_SERVICE, WixCartContext, WixCartService, cartIndicator, cartPage, provideWixCartContext, provideWixCartService } from '@jay-framework/wix-cart';
|
|
3
3
|
import * as _jay_framework_fullstack_component from '@jay-framework/fullstack-component';
|
|
4
4
|
import { Signals, PageProps, UrlParams } from '@jay-framework/fullstack-component';
|
|
5
5
|
import { WixClient } from '@wix/sdk';
|
|
6
|
-
import { products, collections, inventory } from '@wix/stores';
|
|
7
|
-
import { BuildDescriptors } from '@wix/sdk-types';
|
|
8
6
|
import * as _jay_framework_runtime from '@jay-framework/runtime';
|
|
9
7
|
import { HTMLElementCollectionProxy, HTMLElementProxy } from '@jay-framework/runtime';
|
|
10
8
|
import { Getter } from '@jay-framework/reactive';
|
|
11
9
|
import * as _jay_framework_component from '@jay-framework/component';
|
|
12
10
|
|
|
13
|
-
/**
|
|
14
|
-
* Wix Store V1 API Client Factories
|
|
15
|
-
*
|
|
16
|
-
* These functions create singleton instances of Wix Catalog V1 API clients.
|
|
17
|
-
* Used by both the server service and client context.
|
|
18
|
-
*
|
|
19
|
-
* Key difference from V3:
|
|
20
|
-
* - Uses `products` module instead of `productsV3`
|
|
21
|
-
* - Uses `collections` module instead of `@wix/categories`
|
|
22
|
-
*
|
|
23
|
-
* Note: Cart client is provided by @jay-framework/wix-cart package.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Get a configured Wix Stores Products client (Catalog V1) (singleton)
|
|
28
|
-
*
|
|
29
|
-
* The Products API (V1) is the original Wix Stores catalog API.
|
|
30
|
-
*
|
|
31
|
-
* @returns Products client instance from @wix/stores
|
|
32
|
-
* @see https://dev.wix.com/docs/sdk/backend-modules/stores/products/introduction
|
|
33
|
-
*/
|
|
34
|
-
declare function getProductsClient(wixClient: WixClient): BuildDescriptors<typeof products, {}>;
|
|
35
|
-
/**
|
|
36
|
-
* Get a configured Wix Stores Collections client (singleton)
|
|
37
|
-
*
|
|
38
|
-
* The Collections API allows you to manage product Collections in your Wix store.
|
|
39
|
-
* Note: V3 uses @wix/categories instead.
|
|
40
|
-
*
|
|
41
|
-
* @returns Collections client instance from @wix/stores
|
|
42
|
-
* @see https://dev.wix.com/docs/sdk/backend-modules/stores/collections/introduction
|
|
43
|
-
*/
|
|
44
|
-
declare function getCollectionsClient(wixClient: WixClient): BuildDescriptors<typeof collections, {}>;
|
|
45
|
-
/**
|
|
46
|
-
* Get a configured Wix Stores Inventory client (singleton)
|
|
47
|
-
*
|
|
48
|
-
* The Inventory API allows you to manage product inventory in your Wix store.
|
|
49
|
-
*
|
|
50
|
-
* @returns Inventory client instance from @wix/stores
|
|
51
|
-
* @see https://dev.wix.com/docs/sdk/backend-modules/stores/inventory/introduction
|
|
52
|
-
*/
|
|
53
|
-
declare function getInventoryClient(wixClient: WixClient): BuildDescriptors<typeof inventory, {}>;
|
|
54
|
-
|
|
55
11
|
interface WixStoresV1Service {
|
|
56
|
-
|
|
57
|
-
collections: ReturnType<typeof getCollectionsClient>;
|
|
58
|
-
inventory: ReturnType<typeof getInventoryClient>;
|
|
59
|
-
/** @deprecated Use WIX_CART_SERVICE from @jay-framework/wix-cart instead */
|
|
60
|
-
cart: ReturnType<typeof getCurrentCartClient>;
|
|
12
|
+
wixClient: WixClient;
|
|
61
13
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Server service marker for Wix Stores V1.
|
|
64
|
-
* Use with `.withServices(WIX_STORES_V1_SERVICE_MARKER)` in component definitions.
|
|
65
|
-
*/
|
|
66
14
|
declare const WIX_STORES_V1_SERVICE_MARKER: _jay_framework_fullstack_component.ServiceMarker<WixStoresV1Service>;
|
|
67
|
-
/**
|
|
68
|
-
* Creates, registers, and returns a Wix Stores V1 service instance.
|
|
69
|
-
* Called during server initialization.
|
|
70
|
-
*/
|
|
71
15
|
declare function provideWixStoresV1Service(wixClient: WixClient): WixStoresV1Service;
|
|
72
16
|
|
|
73
17
|
declare enum OptionRenderType$1 {
|
|
@@ -188,6 +132,37 @@ interface ProductCardRepeatedRefs {
|
|
|
188
132
|
quickOption: ProductOptionsRepeatedRefs
|
|
189
133
|
}
|
|
190
134
|
|
|
135
|
+
interface V1Media {
|
|
136
|
+
mainMedia?: V1MediaItem;
|
|
137
|
+
items?: V1MediaItem[];
|
|
138
|
+
}
|
|
139
|
+
interface V1MediaItem {
|
|
140
|
+
_id?: string;
|
|
141
|
+
mediaType?: string;
|
|
142
|
+
title?: string;
|
|
143
|
+
image?: {
|
|
144
|
+
url?: string;
|
|
145
|
+
width?: number;
|
|
146
|
+
height?: number;
|
|
147
|
+
};
|
|
148
|
+
video?: {
|
|
149
|
+
url?: string;
|
|
150
|
+
};
|
|
151
|
+
thumbnail?: {
|
|
152
|
+
url?: string;
|
|
153
|
+
width?: number;
|
|
154
|
+
height?: number;
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
interface V1Collection {
|
|
158
|
+
_id?: string;
|
|
159
|
+
name?: string;
|
|
160
|
+
slug?: string;
|
|
161
|
+
description?: string;
|
|
162
|
+
media?: V1Media;
|
|
163
|
+
numberOfProducts?: number;
|
|
164
|
+
}
|
|
165
|
+
|
|
191
166
|
/**
|
|
192
167
|
* Wix Stores Catalog V1 Product Mapping Utilities
|
|
193
168
|
*
|
|
@@ -203,20 +178,6 @@ interface ProductCardRepeatedRefs {
|
|
|
203
178
|
* Reference: wix/exploration/query-products-catalog-v1/output/individual/*.json
|
|
204
179
|
*/
|
|
205
180
|
|
|
206
|
-
interface V1Collection {
|
|
207
|
-
_id?: string;
|
|
208
|
-
name?: string;
|
|
209
|
-
slug?: string;
|
|
210
|
-
description?: string;
|
|
211
|
-
media?: {
|
|
212
|
-
mainMedia?: {
|
|
213
|
-
image?: {
|
|
214
|
-
url: string;
|
|
215
|
-
};
|
|
216
|
-
};
|
|
217
|
-
};
|
|
218
|
-
numberOfProducts?: number;
|
|
219
|
-
}
|
|
220
181
|
interface CollectionViewState {
|
|
221
182
|
_id: string;
|
|
222
183
|
name: string;
|
|
@@ -273,39 +234,19 @@ interface WixStoresV1Context {
|
|
|
273
234
|
*/
|
|
274
235
|
declare const WIX_STORES_V1_CONTEXT: _jay_framework_runtime.ContextMarker<WixStoresV1Context>;
|
|
275
236
|
|
|
276
|
-
/**
|
|
277
|
-
* Sort options for product search
|
|
278
|
-
*/
|
|
279
237
|
type ProductSortField = 'relevance' | 'price_asc' | 'price_desc' | 'name_asc' | 'name_desc' | 'newest';
|
|
280
|
-
/**
|
|
281
|
-
* Product search filters
|
|
282
|
-
*/
|
|
283
238
|
interface ProductSearchFilters {
|
|
284
|
-
/** Minimum price filter */
|
|
285
239
|
minPrice?: number;
|
|
286
|
-
/** Maximum price filter */
|
|
287
240
|
maxPrice?: number;
|
|
288
|
-
/** Filter by collection IDs (V1 uses collections, not categories) */
|
|
289
241
|
collectionIds?: string[];
|
|
290
242
|
}
|
|
291
|
-
/**
|
|
292
|
-
* Input for searchProducts action
|
|
293
|
-
*/
|
|
294
243
|
interface SearchProductsInput {
|
|
295
|
-
/** Search query text */
|
|
296
244
|
query: string;
|
|
297
|
-
/** Filters to apply */
|
|
298
245
|
filters?: ProductSearchFilters;
|
|
299
|
-
/** Sort order */
|
|
300
246
|
sortBy?: ProductSortField;
|
|
301
|
-
/** Page number for pagination (1-based) */
|
|
302
247
|
page?: number;
|
|
303
|
-
/** Items per page (default: 12) */
|
|
304
248
|
pageSize?: number;
|
|
305
249
|
}
|
|
306
|
-
/**
|
|
307
|
-
* Price range bucket for filter UI
|
|
308
|
-
*/
|
|
309
250
|
interface PriceRangeBucket {
|
|
310
251
|
rangeId: string;
|
|
311
252
|
label: string;
|
|
@@ -313,96 +254,24 @@ interface PriceRangeBucket {
|
|
|
313
254
|
maxValue: number | null;
|
|
314
255
|
isSelected: boolean;
|
|
315
256
|
}
|
|
316
|
-
/**
|
|
317
|
-
* Price aggregation data for filter UI
|
|
318
|
-
*/
|
|
319
257
|
interface PriceAggregationData {
|
|
320
|
-
/** Minimum price across all products */
|
|
321
258
|
minBound: number;
|
|
322
|
-
/** Maximum price across all products */
|
|
323
259
|
maxBound: number;
|
|
324
|
-
/** Computed price range buckets */
|
|
325
260
|
ranges: PriceRangeBucket[];
|
|
326
261
|
}
|
|
327
|
-
/**
|
|
328
|
-
* Output for searchProducts action
|
|
329
|
-
*/
|
|
330
262
|
interface SearchProductsOutput {
|
|
331
|
-
/** List of matching products */
|
|
332
263
|
products: ProductCardViewState[];
|
|
333
|
-
/** Total number of matching products */
|
|
334
264
|
totalCount: number;
|
|
335
|
-
/** Current page number */
|
|
336
265
|
currentPage: number;
|
|
337
|
-
/** Total number of pages */
|
|
338
266
|
totalPages: number;
|
|
339
|
-
/** Whether there are more results */
|
|
340
267
|
hasMore: boolean;
|
|
341
|
-
/** Price aggregation data (bounds and computed ranges) */
|
|
342
268
|
priceAggregation: PriceAggregationData;
|
|
343
269
|
}
|
|
344
|
-
/**
|
|
345
|
-
* Input for getProductBySlug action
|
|
346
|
-
*/
|
|
347
270
|
interface GetProductBySlugInput {
|
|
348
|
-
/** Product URL slug */
|
|
349
271
|
slug: string;
|
|
350
272
|
}
|
|
351
|
-
/**
|
|
352
|
-
* Search products using the Wix Stores Catalog V1 queryProducts API.
|
|
353
|
-
*
|
|
354
|
-
* V1 uses skip-based pagination and query builder syntax.
|
|
355
|
-
*
|
|
356
|
-
* Server-side filtering/sorting:
|
|
357
|
-
* - name: startsWith() for text search
|
|
358
|
-
* - collectionIds: hasSome() for collection filtering
|
|
359
|
-
* - priceData.price: ge()/le() for price range filtering
|
|
360
|
-
* - Sorting: ascending()/descending() on price, name, lastUpdated
|
|
361
|
-
*
|
|
362
|
-
* Also fetches min/max prices in parallel for price range filter UI.
|
|
363
|
-
*
|
|
364
|
-
* @see https://dev.wix.com/docs/sdk/backend-modules/stores/products/query-products
|
|
365
|
-
*
|
|
366
|
-
* @example
|
|
367
|
-
* ```typescript
|
|
368
|
-
* const results = await searchProducts({
|
|
369
|
-
* query: 'whisky',
|
|
370
|
-
* filters: { minPrice: 50, maxPrice: 200 },
|
|
371
|
-
* sortBy: 'price_asc',
|
|
372
|
-
* pageSize: 12,
|
|
373
|
-
* page: 1
|
|
374
|
-
* });
|
|
375
|
-
* // results.priceAggregation = {
|
|
376
|
-
* // minBound: 25,
|
|
377
|
-
* // maxBound: 500,
|
|
378
|
-
* // ranges: [
|
|
379
|
-
* // { rangeId: 'all', label: 'Show all', minValue: null, maxValue: null, isSelected: true },
|
|
380
|
-
* // { rangeId: '0-100', label: '$0 - $100', minValue: 0, maxValue: 100, isSelected: false },
|
|
381
|
-
* // { rangeId: '100-200', label: '$100 - $200', ... },
|
|
382
|
-
* // ...
|
|
383
|
-
* // ]
|
|
384
|
-
* // }
|
|
385
|
-
* ```
|
|
386
|
-
*/
|
|
387
273
|
declare const searchProducts: _jay_framework_fullstack_component.JayAction<SearchProductsInput, SearchProductsOutput> & _jay_framework_fullstack_component.JayActionDefinition<SearchProductsInput, SearchProductsOutput, [WixStoresV1Service]>;
|
|
388
|
-
/**
|
|
389
|
-
* Get a single product by its URL slug.
|
|
390
|
-
*
|
|
391
|
-
* @example
|
|
392
|
-
* ```typescript
|
|
393
|
-
* const product = await getProductBySlug({ slug: 'peat-s-beast-px-finish-54-1' });
|
|
394
|
-
* ```
|
|
395
|
-
*/
|
|
396
274
|
declare const getProductBySlug: _jay_framework_fullstack_component.JayAction<GetProductBySlugInput, ProductCardViewState> & _jay_framework_fullstack_component.JayActionDefinition<GetProductBySlugInput, ProductCardViewState, [WixStoresV1Service]>;
|
|
397
|
-
/**
|
|
398
|
-
* Get available collections for filtering.
|
|
399
|
-
* V1 uses collections instead of categories.
|
|
400
|
-
*
|
|
401
|
-
* @example
|
|
402
|
-
* ```typescript
|
|
403
|
-
* const collections = await getCollections();
|
|
404
|
-
* ```
|
|
405
|
-
*/
|
|
406
275
|
declare const getCollections: _jay_framework_fullstack_component.JayAction<Record<string, never>, CollectionViewState[]> & _jay_framework_fullstack_component.JayActionDefinition<Record<string, never>, CollectionViewState[], [WixStoresV1Service]>;
|
|
407
276
|
|
|
408
277
|
declare enum MediaType$1 {
|
package/dist/index.js
CHANGED
|
@@ -1,46 +1,76 @@
|
|
|
1
|
-
import { getCurrentCartClient } from "@jay-framework/wix-cart";
|
|
2
1
|
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
2
|
import { createJayService, makeJayQuery, ActionError, makeJayStackComponent, RenderPipeline, makeJayInit } from "@jay-framework/fullstack-component";
|
|
5
3
|
import { registerService, getService } from "@jay-framework/stack-server-runtime";
|
|
6
4
|
import { createJayContext } from "@jay-framework/runtime";
|
|
7
5
|
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
|
-
}
|
|
6
|
+
import { wixFetch, WIX_CLIENT_SERVICE } from "@jay-framework/wix-server-client";
|
|
32
7
|
const WIX_STORES_V1_SERVICE_MARKER = createJayService("Wix Store V1 Service");
|
|
33
8
|
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
|
-
};
|
|
9
|
+
const service = { wixClient };
|
|
41
10
|
registerService(WIX_STORES_V1_SERVICE_MARKER, service);
|
|
42
11
|
return service;
|
|
43
12
|
}
|
|
13
|
+
function normalizeProduct(product) {
|
|
14
|
+
const p = { ...product };
|
|
15
|
+
const raw = product;
|
|
16
|
+
if (raw.id && !p._id) {
|
|
17
|
+
p._id = raw.id;
|
|
18
|
+
}
|
|
19
|
+
return p;
|
|
20
|
+
}
|
|
21
|
+
async function queryProducts(client, request) {
|
|
22
|
+
const query = {};
|
|
23
|
+
if (request?.filter) query.filter = JSON.stringify(request.filter);
|
|
24
|
+
if (request?.sort) {
|
|
25
|
+
const v1Sort = request.sort.map((s) => ({
|
|
26
|
+
[s.fieldName]: (s.order || "ASC").toLowerCase()
|
|
27
|
+
}));
|
|
28
|
+
query.sort = JSON.stringify(v1Sort);
|
|
29
|
+
}
|
|
30
|
+
if (request?.paging) query.paging = request.paging;
|
|
31
|
+
const result = await wixFetch(client, "/stores/v1/products/query", {
|
|
32
|
+
method: "POST",
|
|
33
|
+
body: {
|
|
34
|
+
query,
|
|
35
|
+
includeVariants: request?.includeVariants ?? true,
|
|
36
|
+
includeMerchantSpecificData: request?.includeMerchantSpecificData ?? true
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
if (result.products) {
|
|
40
|
+
result.products = result.products.map(
|
|
41
|
+
(p) => normalizeProduct(p)
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
function normalizeCollection(col) {
|
|
47
|
+
const c = { ...col };
|
|
48
|
+
if (col.id && !c._id) {
|
|
49
|
+
c._id = col.id;
|
|
50
|
+
}
|
|
51
|
+
return c;
|
|
52
|
+
}
|
|
53
|
+
async function queryCollections(client, request) {
|
|
54
|
+
const query = {};
|
|
55
|
+
const result = await wixFetch(
|
|
56
|
+
client,
|
|
57
|
+
"/stores/v1/collections/query",
|
|
58
|
+
{
|
|
59
|
+
method: "POST",
|
|
60
|
+
body: {
|
|
61
|
+
query,
|
|
62
|
+
includeNumberOfProducts: true,
|
|
63
|
+
includeDescription: true
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
if (result.collections) {
|
|
68
|
+
result.collections = result.collections.map(
|
|
69
|
+
(c) => normalizeCollection(c)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
44
74
|
var MediaType$2 = /* @__PURE__ */ ((MediaType2) => {
|
|
45
75
|
MediaType2[MediaType2["IMAGE"] = 0] = "IMAGE";
|
|
46
76
|
MediaType2[MediaType2["VIDEO"] = 1] = "VIDEO";
|
|
@@ -79,6 +109,9 @@ var ChoiceType$1 = /* @__PURE__ */ ((ChoiceType2) => {
|
|
|
79
109
|
ChoiceType2[ChoiceType2["ONE_COLOR"] = 1] = "ONE_COLOR";
|
|
80
110
|
return ChoiceType2;
|
|
81
111
|
})(ChoiceType$1 || {});
|
|
112
|
+
function stripWixMediaResize(url) {
|
|
113
|
+
return url.replace(/\/v1\/(?:fit|fill|crop)\/[^/]+\/file\.\w+$/, "");
|
|
114
|
+
}
|
|
82
115
|
function mapAvailabilityStatus(status) {
|
|
83
116
|
switch (status) {
|
|
84
117
|
case "OUT_OF_STOCK":
|
|
@@ -153,14 +186,12 @@ function mapProductToCard(product, productPagePath = DEFAULT_PRODUCT_PAGE_PATH)
|
|
|
153
186
|
slug,
|
|
154
187
|
productUrl: slug ? `${productPagePath}/${slug}` : "",
|
|
155
188
|
mainMedia: {
|
|
156
|
-
|
|
157
|
-
url: mainMedia?.image?.url || "",
|
|
189
|
+
url: stripWixMediaResize(mainMedia?.image?.url || ""),
|
|
158
190
|
altText: mainMedia?.title || product.name || "",
|
|
159
191
|
mediaType: mapMediaType(mainMedia?.mediaType)
|
|
160
192
|
},
|
|
161
193
|
thumbnail: {
|
|
162
|
-
|
|
163
|
-
url: mainMedia?.thumbnail?.url || "",
|
|
194
|
+
url: stripWixMediaResize(mainMedia?.thumbnail?.url || ""),
|
|
164
195
|
altText: mainMedia?.title || product.name || "",
|
|
165
196
|
width: mainMedia?.thumbnail?.width || 300,
|
|
166
197
|
height: mainMedia?.thumbnail?.height || 300
|
|
@@ -196,7 +227,7 @@ function mapCollectionToViewState(collection) {
|
|
|
196
227
|
name: collection.name || "",
|
|
197
228
|
slug: collection.slug || "",
|
|
198
229
|
description: collection.description || "",
|
|
199
|
-
imageUrl: collection.media?.mainMedia?.image?.url || "",
|
|
230
|
+
imageUrl: stripWixMediaResize(collection.media?.mainMedia?.image?.url || ""),
|
|
200
231
|
productCount: collection.numberOfProducts || 0
|
|
201
232
|
};
|
|
202
233
|
}
|
|
@@ -234,10 +265,9 @@ function generatePriceBuckets(minPrice, maxPrice, currencySymbol = "$") {
|
|
|
234
265
|
const from = Math.round(allBoundaries[i]);
|
|
235
266
|
const to = Math.round(allBoundaries[i + 1]);
|
|
236
267
|
if (from < to) {
|
|
237
|
-
const label = `${currencySymbol}${from} - ${currencySymbol}${to}`;
|
|
238
268
|
buckets.push({
|
|
239
269
|
rangeId: `${from}-${to}`,
|
|
240
|
-
label
|
|
270
|
+
label: `${currencySymbol}${from} - ${currencySymbol}${to}`,
|
|
241
271
|
minValue: from,
|
|
242
272
|
maxValue: to,
|
|
243
273
|
isSelected: false
|
|
@@ -246,63 +276,81 @@ function generatePriceBuckets(minPrice, maxPrice, currencySymbol = "$") {
|
|
|
246
276
|
}
|
|
247
277
|
return buckets;
|
|
248
278
|
}
|
|
279
|
+
function buildBaseFilter(query, filters) {
|
|
280
|
+
const conditions = [];
|
|
281
|
+
if (query && query.trim().length > 0) {
|
|
282
|
+
conditions.push({ name: { $startsWith: query.trim() } });
|
|
283
|
+
}
|
|
284
|
+
if (filters.collectionIds && filters.collectionIds.length > 0) {
|
|
285
|
+
conditions.push({ "collections.id": { $hasSome: filters.collectionIds } });
|
|
286
|
+
}
|
|
287
|
+
if (conditions.length === 0) return {};
|
|
288
|
+
if (conditions.length === 1) return conditions[0];
|
|
289
|
+
return { $and: conditions };
|
|
290
|
+
}
|
|
291
|
+
function buildPriceFilter(baseFilter, minPrice, maxPrice) {
|
|
292
|
+
const priceFilter = {};
|
|
293
|
+
if (minPrice !== void 0 && minPrice > 0) {
|
|
294
|
+
priceFilter.price = { $gte: minPrice };
|
|
295
|
+
}
|
|
296
|
+
if (maxPrice !== void 0 && maxPrice > 0) {
|
|
297
|
+
const existing = priceFilter.price;
|
|
298
|
+
priceFilter.price = typeof existing === "object" && existing !== null ? { ...existing, $lte: maxPrice } : { $lte: maxPrice };
|
|
299
|
+
}
|
|
300
|
+
if (Object.keys(priceFilter).length === 0) return baseFilter;
|
|
301
|
+
if (Object.keys(baseFilter).length === 0) return priceFilter;
|
|
302
|
+
return { $and: [baseFilter, priceFilter] };
|
|
303
|
+
}
|
|
249
304
|
const searchProducts = makeJayQuery("wixStoresV1.searchProducts").withServices(WIX_STORES_V1_SERVICE_MARKER).withHandler(
|
|
250
305
|
async (input, wixStores) => {
|
|
251
306
|
const { query, filters = {}, sortBy = "relevance", page = 1, pageSize = 12 } = input;
|
|
252
307
|
try {
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
q = q.ascending("price");
|
|
274
|
-
break;
|
|
275
|
-
case "price_desc":
|
|
276
|
-
q = q.descending("price");
|
|
277
|
-
break;
|
|
278
|
-
case "name_asc":
|
|
279
|
-
q = q.ascending("name");
|
|
280
|
-
break;
|
|
281
|
-
case "name_desc":
|
|
282
|
-
q = q.descending("name");
|
|
283
|
-
break;
|
|
284
|
-
case "newest":
|
|
285
|
-
q = q.descending("lastUpdated");
|
|
286
|
-
break;
|
|
287
|
-
}
|
|
288
|
-
return q;
|
|
289
|
-
};
|
|
290
|
-
const minPriceQuery = buildBaseQuery().ascending("price").limit(1).find();
|
|
291
|
-
const maxPriceQuery = buildBaseQuery().descending("price").limit(1).find();
|
|
308
|
+
const baseFilter = buildBaseFilter(query, filters);
|
|
309
|
+
const fullFilter = buildPriceFilter(baseFilter, filters.minPrice, filters.maxPrice);
|
|
310
|
+
const sort = [];
|
|
311
|
+
switch (sortBy) {
|
|
312
|
+
case "price_asc":
|
|
313
|
+
sort.push({ fieldName: "price", order: "ASC" });
|
|
314
|
+
break;
|
|
315
|
+
case "price_desc":
|
|
316
|
+
sort.push({ fieldName: "price", order: "DESC" });
|
|
317
|
+
break;
|
|
318
|
+
case "name_asc":
|
|
319
|
+
sort.push({ fieldName: "name", order: "ASC" });
|
|
320
|
+
break;
|
|
321
|
+
case "name_desc":
|
|
322
|
+
sort.push({ fieldName: "name", order: "DESC" });
|
|
323
|
+
break;
|
|
324
|
+
case "newest":
|
|
325
|
+
sort.push({ fieldName: "lastUpdated", order: "DESC" });
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
292
328
|
const [result, minPriceResult, maxPriceResult] = await Promise.all([
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
329
|
+
queryProducts(wixStores.wixClient, {
|
|
330
|
+
filter: fullFilter,
|
|
331
|
+
sort: sort.length > 0 ? sort : void 0,
|
|
332
|
+
paging: { limit: pageSize, offset: (page - 1) * pageSize }
|
|
333
|
+
}),
|
|
334
|
+
queryProducts(wixStores.wixClient, {
|
|
335
|
+
filter: baseFilter,
|
|
336
|
+
sort: [{ fieldName: "price", order: "ASC" }],
|
|
337
|
+
paging: { limit: 1 }
|
|
338
|
+
}),
|
|
339
|
+
queryProducts(wixStores.wixClient, {
|
|
340
|
+
filter: baseFilter,
|
|
341
|
+
sort: [{ fieldName: "price", order: "DESC" }],
|
|
342
|
+
paging: { limit: 1 }
|
|
343
|
+
})
|
|
296
344
|
]);
|
|
297
|
-
const
|
|
298
|
-
const minBound = minPriceResult.
|
|
299
|
-
const maxBound = maxPriceResult.
|
|
300
|
-
const currency =
|
|
345
|
+
const products = result.products || [];
|
|
346
|
+
const minBound = minPriceResult.products?.[0]?.price?.price ?? 0;
|
|
347
|
+
const maxBound = maxPriceResult.products?.[0]?.price?.price ?? 0;
|
|
348
|
+
const currency = products[0]?.price?.currency || minPriceResult.products?.[0]?.price?.currency;
|
|
301
349
|
const currencySymbol = currency === "ILS" ? "₪" : currency === "USD" ? "$" : currency === "EUR" ? "€" : currency === "GBP" ? "£" : "$";
|
|
302
350
|
const ranges = generatePriceBuckets(minBound, maxBound, currencySymbol);
|
|
303
|
-
const totalCount = result.
|
|
351
|
+
const totalCount = result.totalResults ?? products.length;
|
|
304
352
|
const totalPages = Math.ceil(totalCount / pageSize);
|
|
305
|
-
const mappedProducts =
|
|
353
|
+
const mappedProducts = products.map((p) => mapProductToCard(p));
|
|
306
354
|
return {
|
|
307
355
|
products: mappedProducts,
|
|
308
356
|
totalCount,
|
|
@@ -324,14 +372,18 @@ const getProductBySlug = makeJayQuery("wixStoresV1.getProductBySlug").withServic
|
|
|
324
372
|
throw new ActionError("INVALID_INPUT", "Product slug is required");
|
|
325
373
|
}
|
|
326
374
|
try {
|
|
327
|
-
let result = await
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
375
|
+
let result = await queryProducts(wixStores.wixClient, {
|
|
376
|
+
filter: { slug },
|
|
377
|
+
paging: { limit: 1 }
|
|
378
|
+
});
|
|
379
|
+
if (!result.products?.length) {
|
|
380
|
+
result = await queryProducts(wixStores.wixClient, {
|
|
381
|
+
filter: { id: slug },
|
|
382
|
+
paging: { limit: 1 }
|
|
383
|
+
});
|
|
334
384
|
}
|
|
385
|
+
const product = result.products?.[0];
|
|
386
|
+
if (!product) return null;
|
|
335
387
|
return mapProductToCard(product);
|
|
336
388
|
} catch (error) {
|
|
337
389
|
console.error("[wixStoresV1.getProductBySlug] Failed to get product:", error);
|
|
@@ -342,8 +394,8 @@ const getProductBySlug = makeJayQuery("wixStoresV1.getProductBySlug").withServic
|
|
|
342
394
|
const getCollections = makeJayQuery("wixStoresV1.getCollections").withServices(WIX_STORES_V1_SERVICE_MARKER).withCaching({ maxAge: 3600 }).withHandler(
|
|
343
395
|
async (_input, wixStores) => {
|
|
344
396
|
try {
|
|
345
|
-
const result = await
|
|
346
|
-
return (result.
|
|
397
|
+
const result = await queryCollections(wixStores.wixClient);
|
|
398
|
+
return (result.collections || []).map((col) => mapCollectionToViewState(col));
|
|
347
399
|
} catch (error) {
|
|
348
400
|
console.error("[wixStoresV1.getCollections] Failed to load collections:", error);
|
|
349
401
|
throw new ActionError("LOAD_FAILED", "Failed to load collections");
|
|
@@ -399,7 +451,7 @@ function mapInfoSections(sections) {
|
|
|
399
451
|
function mapMedia(product) {
|
|
400
452
|
const mainMedia = product.media?.mainMedia;
|
|
401
453
|
const mediaItems = product.media?.items || [];
|
|
402
|
-
const mainUrl = mainMedia?.image?.url || "";
|
|
454
|
+
const mainUrl = stripWixMediaResize(mainMedia?.image?.url || "");
|
|
403
455
|
const mainMediaType = mainMedia?.mediaType === "video" ? MediaType$1.VIDEO : MediaType$1.IMAGE;
|
|
404
456
|
return {
|
|
405
457
|
selectedMedia: {
|
|
@@ -409,7 +461,7 @@ function mapMedia(product) {
|
|
|
409
461
|
availableMedia: mediaItems.map((item, index) => ({
|
|
410
462
|
mediaId: item._id || String(index),
|
|
411
463
|
media: {
|
|
412
|
-
url: item.image?.url || "",
|
|
464
|
+
url: stripWixMediaResize(item.image?.url || ""),
|
|
413
465
|
mediaType: item.mediaType === "video" ? MediaType$1.VIDEO : MediaType$1.IMAGE
|
|
414
466
|
},
|
|
415
467
|
selected: item._id === mainMedia?._id ? Selected.selected : Selected.notSelected
|
|
@@ -478,12 +530,18 @@ function mapSeoHeadTags(product, seoData) {
|
|
|
478
530
|
return headTags;
|
|
479
531
|
}
|
|
480
532
|
async function* loadProductParams([wixStores]) {
|
|
533
|
+
const PAGE_SIZE2 = 100;
|
|
481
534
|
try {
|
|
482
|
-
let
|
|
483
|
-
|
|
484
|
-
while (
|
|
485
|
-
result = await
|
|
486
|
-
|
|
535
|
+
let offset = 0;
|
|
536
|
+
let hasMore = true;
|
|
537
|
+
while (hasMore) {
|
|
538
|
+
const result = await queryProducts(wixStores.wixClient, {
|
|
539
|
+
paging: { limit: PAGE_SIZE2, offset }
|
|
540
|
+
});
|
|
541
|
+
const products = result.products || [];
|
|
542
|
+
yield products.map((product) => ({ slug: product.slug || "" }));
|
|
543
|
+
offset += products.length;
|
|
544
|
+
hasMore = products.length === PAGE_SIZE2;
|
|
487
545
|
}
|
|
488
546
|
} catch (error) {
|
|
489
547
|
console.error("[ProductPage V1] Failed to load product slugs:", error);
|
|
@@ -493,15 +551,21 @@ async function* loadProductParams([wixStores]) {
|
|
|
493
551
|
async function renderSlowlyChanging$3(props, wixStores) {
|
|
494
552
|
const Pipeline = RenderPipeline.for();
|
|
495
553
|
return Pipeline.try(async () => {
|
|
496
|
-
const bySlug = await
|
|
497
|
-
|
|
554
|
+
const bySlug = await queryProducts(wixStores.wixClient, {
|
|
555
|
+
filter: { slug: props.slug },
|
|
556
|
+
paging: { limit: 1 }
|
|
557
|
+
});
|
|
558
|
+
if (bySlug.products?.length)
|
|
498
559
|
return bySlug;
|
|
499
|
-
return
|
|
560
|
+
return queryProducts(wixStores.wixClient, {
|
|
561
|
+
filter: { id: props.slug },
|
|
562
|
+
paging: { limit: 1 }
|
|
563
|
+
});
|
|
500
564
|
}).recover((error) => {
|
|
501
565
|
console.error("[ProductPage V1] Error loading product:", error);
|
|
502
566
|
return Pipeline.clientError(404, "Product not found");
|
|
503
567
|
}).toPhaseOutput((result) => {
|
|
504
|
-
const product = result.
|
|
568
|
+
const product = result.products?.[0];
|
|
505
569
|
if (!product) {
|
|
506
570
|
throw new Error("Product not found");
|
|
507
571
|
}
|
|
@@ -570,13 +634,13 @@ const PAGE_SIZE$1 = 12;
|
|
|
570
634
|
async function renderSlowlyChanging$2(props, wixStores) {
|
|
571
635
|
const Pipeline = RenderPipeline.for();
|
|
572
636
|
return Pipeline.try(async () => {
|
|
573
|
-
const collectionsResult = await
|
|
574
|
-
return collectionsResult.
|
|
637
|
+
const collectionsResult = await queryCollections(wixStores.wixClient);
|
|
638
|
+
return collectionsResult.collections || [];
|
|
575
639
|
}).recover((error) => {
|
|
576
640
|
console.error("[ProductSearch V1] Failed to load collections:", error);
|
|
577
641
|
return Pipeline.ok([]);
|
|
578
|
-
}).toPhaseOutput((
|
|
579
|
-
const collectionInfos =
|
|
642
|
+
}).toPhaseOutput((collections) => {
|
|
643
|
+
const collectionInfos = collections.map((col) => ({
|
|
580
644
|
categoryId: col._id || "",
|
|
581
645
|
categoryName: col.name || "",
|
|
582
646
|
categorySlug: col.slug || ""
|
|
@@ -686,14 +750,14 @@ const productSearch = makeJayStackComponent().withProps().withServices(WIX_STORE
|
|
|
686
750
|
async function renderSlowlyChanging$1(props, wixStores) {
|
|
687
751
|
const Pipeline = RenderPipeline.for();
|
|
688
752
|
return Pipeline.try(async () => {
|
|
689
|
-
const result = await
|
|
690
|
-
return result.
|
|
753
|
+
const result = await queryCollections(wixStores.wixClient);
|
|
754
|
+
return result.collections || [];
|
|
691
755
|
}).recover((error) => {
|
|
692
756
|
console.error("[CollectionList V1] Failed to load collections:", error);
|
|
693
757
|
return Pipeline.ok([]);
|
|
694
|
-
}).toPhaseOutput((
|
|
695
|
-
const collectionItems =
|
|
696
|
-
const imageUrl = col.media?.mainMedia?.image?.url || "";
|
|
758
|
+
}).toPhaseOutput((collections) => {
|
|
759
|
+
const collectionItems = collections.map((col) => {
|
|
760
|
+
const imageUrl = stripWixMediaResize(col.media?.mainMedia?.image?.url || "");
|
|
697
761
|
return {
|
|
698
762
|
_id: col._id || "",
|
|
699
763
|
name: col.name || "",
|
|
@@ -735,19 +799,22 @@ var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
|
735
799
|
const PAGE_SIZE = 20;
|
|
736
800
|
async function* loadCollectionParams([wixStores]) {
|
|
737
801
|
try {
|
|
738
|
-
const result = await
|
|
739
|
-
yield (result.
|
|
802
|
+
const result = await queryCollections(wixStores.wixClient);
|
|
803
|
+
yield (result.collections || []).filter((col) => col.slug).map((col) => ({ slug: col.slug }));
|
|
740
804
|
} catch (error) {
|
|
741
805
|
console.error("[CollectionPage V1] Failed to load collection slugs:", error);
|
|
742
806
|
yield [];
|
|
743
807
|
}
|
|
744
808
|
}
|
|
745
809
|
async function loadCollectionProducts(collectionId, wixStores, offset = 0) {
|
|
746
|
-
const result = await
|
|
747
|
-
|
|
810
|
+
const result = await queryProducts(wixStores.wixClient, {
|
|
811
|
+
filter: { "collections.id": { $hasSome: [collectionId] } },
|
|
812
|
+
paging: { limit: PAGE_SIZE, offset }
|
|
813
|
+
});
|
|
814
|
+
const products = (result.products || []).map((product) => mapProductToCard(product, "/products"));
|
|
748
815
|
return {
|
|
749
|
-
products
|
|
750
|
-
total: result.
|
|
816
|
+
products,
|
|
817
|
+
total: result.totalResults || products.length
|
|
751
818
|
};
|
|
752
819
|
}
|
|
753
820
|
function mapCollectionMedia(collection) {
|
|
@@ -755,7 +822,7 @@ function mapCollectionMedia(collection) {
|
|
|
755
822
|
return {
|
|
756
823
|
mainMedia: mainMedia?.image?.url ? {
|
|
757
824
|
_id: "",
|
|
758
|
-
url: mainMedia.image.url,
|
|
825
|
+
url: stripWixMediaResize(mainMedia.image.url),
|
|
759
826
|
altText: collection.name || "",
|
|
760
827
|
mediaType: MediaType.IMAGE
|
|
761
828
|
} : void 0,
|
|
@@ -765,8 +832,8 @@ function mapCollectionMedia(collection) {
|
|
|
765
832
|
async function renderSlowlyChanging(props, wixStores) {
|
|
766
833
|
const Pipeline = RenderPipeline.for();
|
|
767
834
|
return Pipeline.try(async () => {
|
|
768
|
-
const result = await
|
|
769
|
-
const collection = (result.
|
|
835
|
+
const result = await queryCollections(wixStores.wixClient);
|
|
836
|
+
const collection = (result.collections || []).find((col) => col.slug === props.slug);
|
|
770
837
|
if (!collection) {
|
|
771
838
|
throw new Error("Collection not found");
|
|
772
839
|
}
|
|
@@ -871,7 +938,7 @@ async function setupWixStoresV1(ctx) {
|
|
|
871
938
|
};
|
|
872
939
|
}
|
|
873
940
|
try {
|
|
874
|
-
await
|
|
941
|
+
await queryProducts(service.wixClient, { paging: { limit: 1 } });
|
|
875
942
|
} catch (e) {
|
|
876
943
|
const msg = e.message || "";
|
|
877
944
|
const hint = msg.includes("404") || msg.includes("not found") ? "Wix Stores may not be installed on this site" : msg.includes("403") || msg.includes("permission") ? "API key may lack Wix Stores permissions" : "This package requires the Stores Catalog V1 API — if using Catalog V3, use @jay-framework/wix-stores instead";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/wix-stores-v1",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Wix Stores Catalog V1 API client for Jay Framework",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -35,27 +35,25 @@
|
|
|
35
35
|
"test": ":"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@jay-framework/component": "^0.
|
|
39
|
-
"@jay-framework/fullstack-component": "^0.
|
|
40
|
-
"@jay-framework/reactive": "^0.
|
|
41
|
-
"@jay-framework/runtime": "^0.
|
|
42
|
-
"@jay-framework/secure": "^0.
|
|
43
|
-
"@jay-framework/stack-client-runtime": "^0.
|
|
44
|
-
"@jay-framework/stack-server-runtime": "^0.
|
|
45
|
-
"@jay-framework/wix-cart": "^0.
|
|
46
|
-
"@jay-framework/wix-server-client": "^0.
|
|
47
|
-
"@jay-framework/wix-utils": "^0.
|
|
48
|
-
"@wix/sdk": "^1.21.5"
|
|
49
|
-
"@wix/sdk-runtime": "^1.0.11",
|
|
50
|
-
"@wix/stores": "^1.0.742"
|
|
38
|
+
"@jay-framework/component": "^0.21.0",
|
|
39
|
+
"@jay-framework/fullstack-component": "^0.21.0",
|
|
40
|
+
"@jay-framework/reactive": "^0.21.0",
|
|
41
|
+
"@jay-framework/runtime": "^0.21.0",
|
|
42
|
+
"@jay-framework/secure": "^0.21.0",
|
|
43
|
+
"@jay-framework/stack-client-runtime": "^0.21.0",
|
|
44
|
+
"@jay-framework/stack-server-runtime": "^0.21.0",
|
|
45
|
+
"@jay-framework/wix-cart": "^0.21.0",
|
|
46
|
+
"@jay-framework/wix-server-client": "^0.21.0",
|
|
47
|
+
"@jay-framework/wix-utils": "^0.21.0",
|
|
48
|
+
"@wix/sdk": "^1.21.5"
|
|
51
49
|
},
|
|
52
50
|
"devDependencies": {
|
|
53
51
|
"@babel/core": "^7.23.7",
|
|
54
52
|
"@babel/preset-env": "^7.23.8",
|
|
55
53
|
"@babel/preset-typescript": "^7.23.3",
|
|
56
|
-
"@jay-framework/compiler-jay-stack": "^0.
|
|
57
|
-
"@jay-framework/jay-cli": "^0.
|
|
58
|
-
"@jay-framework/vite-plugin": "^0.
|
|
54
|
+
"@jay-framework/compiler-jay-stack": "^0.21.0",
|
|
55
|
+
"@jay-framework/jay-cli": "^0.21.0",
|
|
56
|
+
"@jay-framework/vite-plugin": "^0.21.0",
|
|
59
57
|
"nodemon": "^3.0.3",
|
|
60
58
|
"rimraf": "^5.0.5",
|
|
61
59
|
"tslib": "^2.6.2",
|