@wix/headless-stores 0.0.52 → 0.0.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/dist/astro/actions/custom-checkout.d.ts +1 -1
- package/cjs/dist/astro/actions/custom-checkout.js +2 -2
- package/cjs/dist/astro/actions/index.d.ts +1 -1
- package/cjs/dist/astro/actions/index.js +1 -1
- package/cjs/dist/enums/index.d.ts +2 -2
- package/cjs/dist/enums/index.js +2 -2
- package/cjs/dist/react/Category.d.ts +168 -67
- package/cjs/dist/react/Category.js +166 -50
- package/cjs/dist/react/CategoryList.d.ts +56 -138
- package/cjs/dist/react/CategoryList.js +44 -129
- package/cjs/dist/react/Choice.d.ts +193 -0
- package/cjs/dist/react/Choice.js +259 -0
- package/cjs/dist/react/Option.d.ts +224 -0
- package/cjs/dist/react/Option.js +388 -0
- package/cjs/dist/react/Product.d.ts +339 -96
- package/cjs/dist/react/Product.js +507 -94
- package/cjs/dist/react/{BuyNow.js → core/BuyNow.js} +2 -2
- package/cjs/dist/react/core/Category.d.ts +98 -0
- package/cjs/dist/react/core/Category.js +81 -0
- package/cjs/dist/react/core/CategoryList.d.ts +185 -0
- package/cjs/dist/react/core/CategoryList.js +174 -0
- package/{dist/react → cjs/dist/react/core}/PayNow.js +2 -2
- package/cjs/dist/react/core/Product.d.ts +148 -0
- package/cjs/dist/react/core/Product.js +126 -0
- package/cjs/dist/react/{ProductList.d.ts → core/ProductList.d.ts} +3 -3
- package/cjs/dist/react/{ProductList.js → core/ProductList.js} +10 -10
- package/{dist/react → cjs/dist/react/core}/ProductListFilters.d.ts +3 -3
- package/{dist/react → cjs/dist/react/core}/ProductListFilters.js +7 -7
- package/cjs/dist/react/{ProductListPagination.js → core/ProductListPagination.js} +8 -8
- package/{dist/react → cjs/dist/react/core}/ProductListSort.d.ts +1 -1
- package/cjs/dist/react/{ProductListSort.js → core/ProductListSort.js} +3 -3
- package/{dist/react → cjs/dist/react/core}/ProductModifiers.d.ts +1 -1
- package/{dist/react → cjs/dist/react/core}/ProductModifiers.js +13 -13
- package/{dist/react → cjs/dist/react/core}/ProductVariantSelector.d.ts +2 -2
- package/{dist/react → cjs/dist/react/core}/ProductVariantSelector.js +7 -10
- package/{dist/react → cjs/dist/react/core}/SelectedVariant.d.ts +2 -2
- package/{dist/react → cjs/dist/react/core}/SelectedVariant.js +43 -15
- package/cjs/dist/react/index.d.ts +15 -10
- package/cjs/dist/react/index.js +15 -10
- package/cjs/dist/react/types.d.ts +8 -0
- package/cjs/dist/react/types.js +9 -0
- package/cjs/dist/server-actions/custom-checkout-action.js +14 -10
- package/cjs/dist/server-actions/index.d.ts +1 -1
- package/cjs/dist/server-actions/index.js +1 -1
- package/cjs/dist/services/buy-now-service.d.ts +1 -1
- package/cjs/dist/services/buy-now-service.js +6 -6
- package/cjs/dist/services/categories-list-service.d.ts +4 -4
- package/cjs/dist/services/categories-list-service.js +10 -10
- package/cjs/dist/services/category-service.d.ts +18 -22
- package/cjs/dist/services/category-service.js +12 -10
- package/cjs/dist/services/index.d.ts +7 -7
- package/cjs/dist/services/index.js +7 -7
- package/cjs/dist/services/pay-now-service.d.ts +1 -1
- package/cjs/dist/services/pay-now-service.js +4 -4
- package/cjs/dist/services/product-modifiers-service.d.ts +3 -3
- package/cjs/dist/services/product-modifiers-service.js +7 -7
- package/cjs/dist/services/product-service.d.ts +4 -4
- package/cjs/dist/services/product-service.js +18 -18
- package/cjs/dist/services/products-list-search-service.d.ts +5 -5
- package/cjs/dist/services/products-list-search-service.js +117 -117
- package/cjs/dist/services/products-list-service.d.ts +4 -4
- package/cjs/dist/services/products-list-service.js +12 -12
- package/cjs/dist/services/selected-variant-service.d.ts +6 -2
- package/cjs/dist/services/selected-variant-service.js +86 -83
- package/cjs/dist/utils/index.d.ts +1 -0
- package/cjs/dist/utils/index.js +5 -4
- package/cjs/dist/utils/renderAsChild.d.ts +96 -0
- package/cjs/dist/utils/renderAsChild.js +66 -0
- package/cjs/dist/utils/renderChildren.d.ts +41 -0
- package/cjs/dist/utils/renderChildren.js +44 -0
- package/cjs/dist/utils/url-params.js +3 -3
- package/dist/astro/actions/custom-checkout.d.ts +1 -1
- package/dist/astro/actions/custom-checkout.js +2 -2
- package/dist/astro/actions/index.d.ts +1 -1
- package/dist/astro/actions/index.js +1 -1
- package/dist/enums/index.d.ts +2 -2
- package/dist/enums/index.js +2 -2
- package/dist/react/Category.d.ts +168 -67
- package/dist/react/Category.js +166 -50
- package/dist/react/CategoryList.d.ts +56 -138
- package/dist/react/CategoryList.js +44 -129
- package/dist/react/Choice.d.ts +193 -0
- package/dist/react/Choice.js +259 -0
- package/dist/react/Option.d.ts +224 -0
- package/dist/react/Option.js +388 -0
- package/dist/react/Product.d.ts +339 -96
- package/dist/react/Product.js +507 -94
- package/dist/react/{BuyNow.js → core/BuyNow.js} +2 -2
- package/dist/react/core/Category.d.ts +98 -0
- package/dist/react/core/Category.js +81 -0
- package/dist/react/core/CategoryList.d.ts +185 -0
- package/dist/react/core/CategoryList.js +174 -0
- package/{cjs/dist/react → dist/react/core}/PayNow.js +2 -2
- package/dist/react/core/Product.d.ts +148 -0
- package/dist/react/core/Product.js +126 -0
- package/dist/react/{ProductList.d.ts → core/ProductList.d.ts} +3 -3
- package/dist/react/{ProductList.js → core/ProductList.js} +10 -10
- package/{cjs/dist/react → dist/react/core}/ProductListFilters.d.ts +3 -3
- package/{cjs/dist/react → dist/react/core}/ProductListFilters.js +7 -7
- package/dist/react/{ProductListPagination.js → core/ProductListPagination.js} +8 -8
- package/{cjs/dist/react → dist/react/core}/ProductListSort.d.ts +1 -1
- package/dist/react/{ProductListSort.js → core/ProductListSort.js} +3 -3
- package/{cjs/dist/react → dist/react/core}/ProductModifiers.d.ts +1 -1
- package/{cjs/dist/react → dist/react/core}/ProductModifiers.js +13 -13
- package/{cjs/dist/react → dist/react/core}/ProductVariantSelector.d.ts +2 -2
- package/{cjs/dist/react → dist/react/core}/ProductVariantSelector.js +7 -10
- package/{cjs/dist/react → dist/react/core}/SelectedVariant.d.ts +2 -2
- package/{cjs/dist/react → dist/react/core}/SelectedVariant.js +43 -15
- package/dist/react/index.d.ts +15 -10
- package/dist/react/index.js +15 -10
- package/dist/react/types.d.ts +8 -0
- package/dist/react/types.js +9 -0
- package/dist/server-actions/custom-checkout-action.js +14 -10
- package/dist/server-actions/index.d.ts +1 -1
- package/dist/server-actions/index.js +1 -1
- package/dist/services/buy-now-service.d.ts +1 -1
- package/dist/services/buy-now-service.js +6 -6
- package/dist/services/categories-list-service.d.ts +4 -4
- package/dist/services/categories-list-service.js +10 -10
- package/dist/services/category-service.d.ts +18 -22
- package/dist/services/category-service.js +12 -10
- package/dist/services/index.d.ts +7 -7
- package/dist/services/index.js +7 -7
- package/dist/services/pay-now-service.d.ts +1 -1
- package/dist/services/pay-now-service.js +4 -4
- package/dist/services/product-modifiers-service.d.ts +3 -3
- package/dist/services/product-modifiers-service.js +7 -7
- package/dist/services/product-service.d.ts +4 -4
- package/dist/services/product-service.js +18 -18
- package/dist/services/products-list-search-service.d.ts +5 -5
- package/dist/services/products-list-search-service.js +117 -117
- package/dist/services/products-list-service.d.ts +4 -4
- package/dist/services/products-list-service.js +12 -12
- package/dist/services/selected-variant-service.d.ts +6 -2
- package/dist/services/selected-variant-service.js +86 -83
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +5 -4
- package/dist/utils/renderAsChild.d.ts +96 -0
- package/dist/utils/renderAsChild.js +66 -0
- package/dist/utils/renderChildren.d.ts +41 -0
- package/dist/utils/renderChildren.js +44 -0
- package/dist/utils/url-params.js +3 -3
- package/package.json +7 -3
- /package/cjs/dist/react/{BuyNow.d.ts → core/BuyNow.d.ts} +0 -0
- /package/cjs/dist/react/{PayNow.d.ts → core/PayNow.d.ts} +0 -0
- /package/cjs/dist/react/{ProductListPagination.d.ts → core/ProductListPagination.d.ts} +0 -0
- /package/dist/react/{BuyNow.d.ts → core/BuyNow.d.ts} +0 -0
- /package/dist/react/{PayNow.d.ts → core/PayNow.d.ts} +0 -0
- /package/dist/react/{ProductListPagination.d.ts → core/ProductListPagination.d.ts} +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { defineService, implementService } from
|
|
2
|
-
import { SignalsServiceDefinition } from
|
|
3
|
-
import { DEFAULT_QUERY_LIMIT, ProductsListServiceDefinition, } from
|
|
4
|
-
import { productsV3, customizationsV3 } from
|
|
5
|
-
import { loadCategoriesListServiceConfig } from
|
|
1
|
+
import { defineService, implementService } from '@wix/services-definitions';
|
|
2
|
+
import { SignalsServiceDefinition } from '@wix/services-definitions/core-services/signals';
|
|
3
|
+
import { DEFAULT_QUERY_LIMIT, ProductsListServiceDefinition, } from './products-list-service.js';
|
|
4
|
+
import { productsV3, customizationsV3 } from '@wix/stores';
|
|
5
|
+
import { loadCategoriesListServiceConfig } from './categories-list-service.js';
|
|
6
6
|
const PRICE_FILTER_DEBOUNCE_TIME = 300;
|
|
7
|
-
import { SortType } from
|
|
8
|
-
export { SortType } from
|
|
7
|
+
import { SortType } from './../enums/sort-enums.js';
|
|
8
|
+
export { SortType } from './../enums/sort-enums.js';
|
|
9
9
|
/**
|
|
10
10
|
* Enumeration of inventory status types available for filtering.
|
|
11
11
|
* Re-exports the Wix inventory availability status enum values.
|
|
@@ -15,44 +15,44 @@ export const InventoryStatusType = productsV3.InventoryAvailabilityStatus;
|
|
|
15
15
|
* Service definition for the Products List Search service.
|
|
16
16
|
* This consolidates sort, pagination, and filtering functionality.
|
|
17
17
|
*/
|
|
18
|
-
export const ProductsListSearchServiceDefinition = defineService(
|
|
18
|
+
export const ProductsListSearchServiceDefinition = defineService('products-list-search');
|
|
19
19
|
/**
|
|
20
20
|
* Convert SortType enum to URL format
|
|
21
21
|
*/
|
|
22
22
|
function convertSortTypeToUrl(sortType) {
|
|
23
23
|
switch (sortType) {
|
|
24
24
|
case SortType.NAME_ASC:
|
|
25
|
-
return
|
|
25
|
+
return 'name';
|
|
26
26
|
case SortType.NAME_DESC:
|
|
27
|
-
return
|
|
27
|
+
return 'name:desc';
|
|
28
28
|
case SortType.PRICE_ASC:
|
|
29
|
-
return
|
|
29
|
+
return 'price';
|
|
30
30
|
case SortType.PRICE_DESC:
|
|
31
|
-
return
|
|
31
|
+
return 'price:desc';
|
|
32
32
|
case SortType.NEWEST:
|
|
33
|
-
return
|
|
33
|
+
return 'newest';
|
|
34
34
|
case SortType.RECOMMENDED:
|
|
35
|
-
return
|
|
35
|
+
return 'recommended';
|
|
36
36
|
default:
|
|
37
|
-
return
|
|
37
|
+
return 'name';
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
41
|
* Convert URL sort format to SortType enum
|
|
42
42
|
*/
|
|
43
43
|
export function convertUrlSortToSortType(urlSort) {
|
|
44
|
-
const sortParts = urlSort.split(
|
|
44
|
+
const sortParts = urlSort.split(':');
|
|
45
45
|
const field = sortParts[0]?.toLowerCase();
|
|
46
|
-
const order = sortParts[1]?.toLowerCase() ===
|
|
46
|
+
const order = sortParts[1]?.toLowerCase() === 'desc' ? 'desc' : 'asc';
|
|
47
47
|
switch (field) {
|
|
48
|
-
case
|
|
49
|
-
return order ===
|
|
50
|
-
case
|
|
51
|
-
return order ===
|
|
52
|
-
case
|
|
53
|
-
case
|
|
48
|
+
case 'name':
|
|
49
|
+
return order === 'desc' ? SortType.NAME_DESC : SortType.NAME_ASC;
|
|
50
|
+
case 'price':
|
|
51
|
+
return order === 'desc' ? SortType.PRICE_DESC : SortType.PRICE_ASC;
|
|
52
|
+
case 'newest':
|
|
53
|
+
case 'created':
|
|
54
54
|
return SortType.NEWEST;
|
|
55
|
-
case
|
|
55
|
+
case 'recommended':
|
|
56
56
|
return SortType.RECOMMENDED;
|
|
57
57
|
default:
|
|
58
58
|
return null;
|
|
@@ -62,7 +62,7 @@ export function convertUrlSortToSortType(urlSort) {
|
|
|
62
62
|
* Update URL with current search state (sort, filters, pagination)
|
|
63
63
|
*/
|
|
64
64
|
function updateUrlWithSearchState(searchState) {
|
|
65
|
-
if (typeof window ===
|
|
65
|
+
if (typeof window === 'undefined')
|
|
66
66
|
return;
|
|
67
67
|
const { sort, filters, customizations, catalogBounds, categorySlug } = searchState;
|
|
68
68
|
// Convert filter IDs back to human-readable names for URL
|
|
@@ -86,14 +86,14 @@ function updateUrlWithSearchState(searchState) {
|
|
|
86
86
|
const params = new URLSearchParams(window.location.search);
|
|
87
87
|
// Define search-related parameters that we manage
|
|
88
88
|
const searchParams = [
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
'sort',
|
|
90
|
+
'limit',
|
|
91
|
+
'cursor',
|
|
92
|
+
'minPrice',
|
|
93
|
+
'maxPrice',
|
|
94
|
+
'inventoryStatus',
|
|
95
|
+
'visible',
|
|
96
|
+
'productType',
|
|
97
97
|
// Product option names will be dynamically added below
|
|
98
98
|
// Note: category is NOT included here as it's handled in the URL path
|
|
99
99
|
];
|
|
@@ -110,44 +110,44 @@ function updateUrlWithSearchState(searchState) {
|
|
|
110
110
|
// Add sort parameter (only if not default)
|
|
111
111
|
const urlSort = convertSortTypeToUrl(sort);
|
|
112
112
|
if (sort !== SortType.NAME_ASC) {
|
|
113
|
-
params.set(
|
|
113
|
+
params.set('sort', urlSort);
|
|
114
114
|
}
|
|
115
115
|
// Add price range parameters only if they differ from catalog bounds
|
|
116
116
|
if (filters.priceRange?.min &&
|
|
117
117
|
filters.priceRange.min > catalogBounds.minPrice) {
|
|
118
|
-
params.set(
|
|
118
|
+
params.set('minPrice', filters.priceRange.min.toString());
|
|
119
119
|
}
|
|
120
120
|
if (filters.priceRange?.max &&
|
|
121
121
|
filters.priceRange.max < catalogBounds.maxPrice) {
|
|
122
|
-
params.set(
|
|
122
|
+
params.set('maxPrice', filters.priceRange.max.toString());
|
|
123
123
|
}
|
|
124
124
|
// Add inventory status parameters
|
|
125
125
|
if (filters.inventoryStatuses && filters.inventoryStatuses.length > 0) {
|
|
126
|
-
params.set(
|
|
126
|
+
params.set('inventoryStatus', filters.inventoryStatuses.join(','));
|
|
127
127
|
}
|
|
128
128
|
// Add visibility filter (only if explicitly false, since true is default)
|
|
129
129
|
if (filters.visible === false) {
|
|
130
|
-
params.set(
|
|
130
|
+
params.set('visible', 'false');
|
|
131
131
|
}
|
|
132
132
|
// Add product type filter
|
|
133
133
|
if (filters.productType) {
|
|
134
|
-
params.set(
|
|
134
|
+
params.set('productType', filters.productType);
|
|
135
135
|
}
|
|
136
136
|
// Add product options as individual parameters (Color=Red,Blue&Size=Large)
|
|
137
137
|
for (const [optionName, values] of Object.entries(humanReadableOptions)) {
|
|
138
138
|
if (values.length > 0) {
|
|
139
|
-
params.set(optionName, values.join(
|
|
139
|
+
params.set(optionName, values.join(','));
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
// Handle URL path construction with category
|
|
143
143
|
let baseUrl = window.location.pathname;
|
|
144
144
|
// If categorySlug is provided, replace the last path segment (which represents the category)
|
|
145
145
|
if (categorySlug) {
|
|
146
|
-
const pathSegments = baseUrl.split(
|
|
146
|
+
const pathSegments = baseUrl.split('/').filter(Boolean);
|
|
147
147
|
if (pathSegments.length > 0) {
|
|
148
148
|
// Replace the last segment with the new category slug
|
|
149
149
|
pathSegments[pathSegments.length - 1] = categorySlug;
|
|
150
|
-
baseUrl =
|
|
150
|
+
baseUrl = '/' + pathSegments.join('/');
|
|
151
151
|
}
|
|
152
152
|
else {
|
|
153
153
|
// If no segments, just use the category slug
|
|
@@ -160,7 +160,7 @@ function updateUrlWithSearchState(searchState) {
|
|
|
160
160
|
: baseUrl;
|
|
161
161
|
// Only update if URL actually changed
|
|
162
162
|
if (newUrl !== window.location.pathname + window.location.search) {
|
|
163
|
-
window.history.pushState(null,
|
|
163
|
+
window.history.pushState(null, '', newUrl);
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
/**
|
|
@@ -208,7 +208,7 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
208
208
|
const initialSearchState = {};
|
|
209
209
|
// Extract category slug from URL path
|
|
210
210
|
// The category slug is always the last segment of the path
|
|
211
|
-
const pathSegments = urlObj.pathname.split(
|
|
211
|
+
const pathSegments = urlObj.pathname.split('/').filter(Boolean);
|
|
212
212
|
let category = undefined;
|
|
213
213
|
if (pathSegments.length > 0) {
|
|
214
214
|
const lastSegment = pathSegments[pathSegments.length - 1];
|
|
@@ -219,14 +219,14 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
// Handle text search (q parameter)
|
|
222
|
-
const query = searchParams.get(
|
|
222
|
+
const query = searchParams.get('q');
|
|
223
223
|
if (query) {
|
|
224
224
|
searchOptions.search = {
|
|
225
225
|
expression: query,
|
|
226
226
|
};
|
|
227
227
|
}
|
|
228
228
|
// Handle sorting
|
|
229
|
-
const sort = searchParams.get(
|
|
229
|
+
const sort = searchParams.get('sort');
|
|
230
230
|
if (sort) {
|
|
231
231
|
const sortType = convertUrlSortToSortType(sort);
|
|
232
232
|
if (sortType) {
|
|
@@ -235,18 +235,18 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
235
235
|
switch (sortType) {
|
|
236
236
|
case SortType.NAME_ASC:
|
|
237
237
|
searchOptions.sort = [
|
|
238
|
-
{ fieldName:
|
|
238
|
+
{ fieldName: 'name', order: productsV3.SortDirection.ASC },
|
|
239
239
|
];
|
|
240
240
|
break;
|
|
241
241
|
case SortType.NAME_DESC:
|
|
242
242
|
searchOptions.sort = [
|
|
243
|
-
{ fieldName:
|
|
243
|
+
{ fieldName: 'name', order: productsV3.SortDirection.DESC },
|
|
244
244
|
];
|
|
245
245
|
break;
|
|
246
246
|
case SortType.PRICE_ASC:
|
|
247
247
|
searchOptions.sort = [
|
|
248
248
|
{
|
|
249
|
-
fieldName:
|
|
249
|
+
fieldName: 'actualPriceRange.minValue.amount',
|
|
250
250
|
order: productsV3.SortDirection.ASC,
|
|
251
251
|
},
|
|
252
252
|
];
|
|
@@ -254,7 +254,7 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
254
254
|
case SortType.PRICE_DESC:
|
|
255
255
|
searchOptions.sort = [
|
|
256
256
|
{
|
|
257
|
-
fieldName:
|
|
257
|
+
fieldName: 'actualPriceRange.minValue.amount',
|
|
258
258
|
order: productsV3.SortDirection.DESC,
|
|
259
259
|
},
|
|
260
260
|
];
|
|
@@ -262,7 +262,7 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
262
262
|
case SortType.RECOMMENDED:
|
|
263
263
|
searchOptions.sort = [
|
|
264
264
|
{
|
|
265
|
-
fieldName:
|
|
265
|
+
fieldName: 'name',
|
|
266
266
|
order: productsV3.SortDirection.DESC,
|
|
267
267
|
},
|
|
268
268
|
];
|
|
@@ -271,8 +271,8 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
273
|
// Handle pagination
|
|
274
|
-
const limit = searchParams.get(
|
|
275
|
-
const cursor = searchParams.get(
|
|
274
|
+
const limit = searchParams.get('limit');
|
|
275
|
+
const cursor = searchParams.get('cursor');
|
|
276
276
|
if (limit || cursor) {
|
|
277
277
|
searchOptions.cursorPaging = {};
|
|
278
278
|
if (limit) {
|
|
@@ -289,54 +289,54 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
289
289
|
}
|
|
290
290
|
// Handle filtering for search options
|
|
291
291
|
const filter = {};
|
|
292
|
-
const visible = searchParams.get(
|
|
292
|
+
const visible = searchParams.get('visible');
|
|
293
293
|
if (visible !== null) {
|
|
294
|
-
filter[
|
|
295
|
-
initialSearchState.visible = visible ===
|
|
294
|
+
filter['visible'] = visible === 'true';
|
|
295
|
+
initialSearchState.visible = visible === 'true';
|
|
296
296
|
}
|
|
297
|
-
const productType = searchParams.get(
|
|
297
|
+
const productType = searchParams.get('productType');
|
|
298
298
|
if (productType) {
|
|
299
|
-
filter[
|
|
299
|
+
filter['productType'] = productType;
|
|
300
300
|
initialSearchState.productType = productType;
|
|
301
301
|
}
|
|
302
302
|
// Add category filter if found
|
|
303
303
|
if (category) {
|
|
304
|
-
filter[
|
|
304
|
+
filter['allCategoriesInfo.categories'] = {
|
|
305
305
|
$matchItems: [{ _id: { $in: [category._id] } }],
|
|
306
306
|
};
|
|
307
307
|
}
|
|
308
308
|
// Price range filtering
|
|
309
|
-
const minPrice = searchParams.get(
|
|
310
|
-
const maxPrice = searchParams.get(
|
|
309
|
+
const minPrice = searchParams.get('minPrice');
|
|
310
|
+
const maxPrice = searchParams.get('maxPrice');
|
|
311
311
|
if (minPrice || maxPrice) {
|
|
312
312
|
initialSearchState.priceRange = {};
|
|
313
313
|
if (minPrice) {
|
|
314
314
|
const minPriceNum = parseFloat(minPrice);
|
|
315
315
|
if (!isNaN(minPriceNum)) {
|
|
316
|
-
filter[
|
|
316
|
+
filter['actualPriceRange.minValue.amount'] = { $gte: minPriceNum };
|
|
317
317
|
initialSearchState.priceRange.min = minPriceNum;
|
|
318
318
|
}
|
|
319
319
|
}
|
|
320
320
|
if (maxPrice) {
|
|
321
321
|
const maxPriceNum = parseFloat(maxPrice);
|
|
322
322
|
if (!isNaN(maxPriceNum)) {
|
|
323
|
-
filter[
|
|
323
|
+
filter['actualPriceRange.maxValue.amount'] = { $lte: maxPriceNum };
|
|
324
324
|
initialSearchState.priceRange.max = maxPriceNum;
|
|
325
325
|
}
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
// Parse product options from URL parameters
|
|
329
329
|
const reservedParams = [
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
330
|
+
'minPrice',
|
|
331
|
+
'maxPrice',
|
|
332
|
+
'inventory_status',
|
|
333
|
+
'inventoryStatus',
|
|
334
|
+
'visible',
|
|
335
|
+
'productType',
|
|
336
|
+
'q',
|
|
337
|
+
'limit',
|
|
338
|
+
'cursor',
|
|
339
|
+
'sort',
|
|
340
340
|
];
|
|
341
341
|
const productOptionsById = {};
|
|
342
342
|
for (const [optionName, optionValues] of searchParams.entries()) {
|
|
@@ -347,7 +347,7 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
347
347
|
c.customizationType ===
|
|
348
348
|
customizationsV3.CustomizationType.PRODUCT_OPTION);
|
|
349
349
|
if (option && option._id) {
|
|
350
|
-
const choiceValues = optionValues.split(
|
|
350
|
+
const choiceValues = optionValues.split(',').filter(Boolean);
|
|
351
351
|
const choiceIds = [];
|
|
352
352
|
// Convert choice names to IDs
|
|
353
353
|
for (const choiceName of choiceValues) {
|
|
@@ -375,20 +375,20 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
375
375
|
// Add aggregations for getting filter options
|
|
376
376
|
searchOptions.aggregations = [
|
|
377
377
|
{
|
|
378
|
-
name:
|
|
379
|
-
fieldPath:
|
|
380
|
-
type:
|
|
381
|
-
scalar: { type:
|
|
378
|
+
name: 'minPrice',
|
|
379
|
+
fieldPath: 'actualPriceRange.minValue.amount',
|
|
380
|
+
type: 'SCALAR',
|
|
381
|
+
scalar: { type: 'MIN' },
|
|
382
382
|
},
|
|
383
383
|
{
|
|
384
|
-
name:
|
|
385
|
-
fieldPath:
|
|
386
|
-
type:
|
|
387
|
-
scalar: { type:
|
|
384
|
+
name: 'maxPrice',
|
|
385
|
+
fieldPath: 'actualPriceRange.maxValue.amount',
|
|
386
|
+
type: 'SCALAR',
|
|
387
|
+
scalar: { type: 'MAX' },
|
|
388
388
|
},
|
|
389
389
|
{
|
|
390
|
-
name:
|
|
391
|
-
fieldPath:
|
|
390
|
+
name: 'optionNames',
|
|
391
|
+
fieldPath: 'options.name',
|
|
392
392
|
type: productsV3.SortType.VALUE,
|
|
393
393
|
value: {
|
|
394
394
|
limit: 20,
|
|
@@ -397,8 +397,8 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
397
397
|
},
|
|
398
398
|
},
|
|
399
399
|
{
|
|
400
|
-
name:
|
|
401
|
-
fieldPath:
|
|
400
|
+
name: 'choiceNames',
|
|
401
|
+
fieldPath: 'options.choicesSettings.choices.name',
|
|
402
402
|
type: productsV3.SortType.VALUE,
|
|
403
403
|
value: {
|
|
404
404
|
limit: 50,
|
|
@@ -407,8 +407,8 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
407
407
|
},
|
|
408
408
|
},
|
|
409
409
|
{
|
|
410
|
-
name:
|
|
411
|
-
fieldPath:
|
|
410
|
+
name: 'inventoryStatus',
|
|
411
|
+
fieldPath: 'inventory.availabilityStatus',
|
|
412
412
|
type: productsV3.SortType.VALUE,
|
|
413
413
|
value: {
|
|
414
414
|
limit: 10,
|
|
@@ -456,7 +456,7 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
456
456
|
*/
|
|
457
457
|
export async function loadProductsListSearchServiceConfig(input) {
|
|
458
458
|
let initialSearchState;
|
|
459
|
-
if (typeof input ===
|
|
459
|
+
if (typeof input === 'string') {
|
|
460
460
|
// URL input - parse it
|
|
461
461
|
const categoriesListConfig = await loadCategoriesListServiceConfig();
|
|
462
462
|
const { initialSearchState: parsedState } = await parseUrlToSearchOptions(input, categoriesListConfig.categories);
|
|
@@ -535,12 +535,12 @@ export const ProductsListSearchService = implementService.withConfig()(ProductsL
|
|
|
535
535
|
});
|
|
536
536
|
const hasPrevPageSignal = signalsService.computed(() => {
|
|
537
537
|
const pagingMetadata = productsListService.pagingMetadata.get();
|
|
538
|
-
return typeof pagingMetadata.cursors?.prev !==
|
|
538
|
+
return typeof pagingMetadata.cursors?.prev !== 'undefined';
|
|
539
539
|
});
|
|
540
540
|
// Debounce timeout IDs for price filters
|
|
541
541
|
let minPriceTimeoutId = null;
|
|
542
542
|
let maxPriceTimeoutId = null;
|
|
543
|
-
if (typeof window !==
|
|
543
|
+
if (typeof window !== 'undefined') {
|
|
544
544
|
// Watch for changes in any search parameters and update search options
|
|
545
545
|
signalsService.effect(() => {
|
|
546
546
|
// Read all signals to establish dependencies
|
|
@@ -576,18 +576,18 @@ export const ProductsListSearchService = implementService.withConfig()(ProductsL
|
|
|
576
576
|
switch (sort) {
|
|
577
577
|
case SortType.NAME_ASC:
|
|
578
578
|
newSearchOptions.sort = [
|
|
579
|
-
{ fieldName:
|
|
579
|
+
{ fieldName: 'name', order: productsV3.SortDirection.ASC },
|
|
580
580
|
];
|
|
581
581
|
break;
|
|
582
582
|
case SortType.NAME_DESC:
|
|
583
583
|
newSearchOptions.sort = [
|
|
584
|
-
{ fieldName:
|
|
584
|
+
{ fieldName: 'name', order: productsV3.SortDirection.DESC },
|
|
585
585
|
];
|
|
586
586
|
break;
|
|
587
587
|
case SortType.PRICE_ASC:
|
|
588
588
|
newSearchOptions.sort = [
|
|
589
589
|
{
|
|
590
|
-
fieldName:
|
|
590
|
+
fieldName: 'actualPriceRange.minValue.amount',
|
|
591
591
|
order: productsV3.SortDirection.ASC,
|
|
592
592
|
},
|
|
593
593
|
];
|
|
@@ -595,7 +595,7 @@ export const ProductsListSearchService = implementService.withConfig()(ProductsL
|
|
|
595
595
|
case SortType.PRICE_DESC:
|
|
596
596
|
newSearchOptions.sort = [
|
|
597
597
|
{
|
|
598
|
-
fieldName:
|
|
598
|
+
fieldName: 'actualPriceRange.minValue.amount',
|
|
599
599
|
order: productsV3.SortDirection.DESC,
|
|
600
600
|
},
|
|
601
601
|
];
|
|
@@ -603,7 +603,7 @@ export const ProductsListSearchService = implementService.withConfig()(ProductsL
|
|
|
603
603
|
case SortType.RECOMMENDED:
|
|
604
604
|
newSearchOptions.sort = [
|
|
605
605
|
{
|
|
606
|
-
fieldName:
|
|
606
|
+
fieldName: 'name',
|
|
607
607
|
order: productsV3.SortDirection.DESC,
|
|
608
608
|
},
|
|
609
609
|
];
|
|
@@ -617,32 +617,32 @@ export const ProductsListSearchService = implementService.withConfig()(ProductsL
|
|
|
617
617
|
newSearchOptions.filter = { ...newSearchOptions.filter };
|
|
618
618
|
}
|
|
619
619
|
// Remove existing filters
|
|
620
|
-
delete newSearchOptions.filter[
|
|
621
|
-
delete newSearchOptions.filter[
|
|
622
|
-
delete newSearchOptions.filter[
|
|
623
|
-
delete newSearchOptions.filter[
|
|
624
|
-
delete newSearchOptions.filter[
|
|
625
|
-
delete newSearchOptions.filter[
|
|
620
|
+
delete newSearchOptions.filter['actualPriceRange.minValue.amount'];
|
|
621
|
+
delete newSearchOptions.filter['actualPriceRange.maxValue.amount'];
|
|
622
|
+
delete newSearchOptions.filter['inventory.availabilityStatus'];
|
|
623
|
+
delete newSearchOptions.filter['allCategoriesInfo.categories'];
|
|
624
|
+
delete newSearchOptions.filter['visible'];
|
|
625
|
+
delete newSearchOptions.filter['productType'];
|
|
626
626
|
// Remove existing product option filters
|
|
627
627
|
Object.keys(newSearchOptions.filter).forEach((key) => {
|
|
628
|
-
if (key.startsWith(
|
|
628
|
+
if (key.startsWith('options.')) {
|
|
629
629
|
delete newSearchOptions.filter[key];
|
|
630
630
|
}
|
|
631
631
|
});
|
|
632
632
|
// Add new filters
|
|
633
633
|
if (minPrice > 0) {
|
|
634
|
-
newSearchOptions.filter[
|
|
634
|
+
newSearchOptions.filter['actualPriceRange.minValue.amount'] = { $gte: minPrice };
|
|
635
635
|
}
|
|
636
636
|
if (maxPrice > 0) {
|
|
637
|
-
newSearchOptions.filter[
|
|
637
|
+
newSearchOptions.filter['actualPriceRange.maxValue.amount'] = { $lte: maxPrice };
|
|
638
638
|
}
|
|
639
639
|
if (selectedInventoryStatuses.length > 0) {
|
|
640
640
|
if (selectedInventoryStatuses.length === 1) {
|
|
641
|
-
newSearchOptions.filter[
|
|
641
|
+
newSearchOptions.filter['inventory.availabilityStatus'] =
|
|
642
642
|
selectedInventoryStatuses[0];
|
|
643
643
|
}
|
|
644
644
|
else {
|
|
645
|
-
newSearchOptions.filter[
|
|
645
|
+
newSearchOptions.filter['inventory.availabilityStatus'] =
|
|
646
646
|
{ $in: selectedInventoryStatuses };
|
|
647
647
|
}
|
|
648
648
|
}
|
|
@@ -653,19 +653,19 @@ export const ProductsListSearchService = implementService.withConfig()(ProductsL
|
|
|
653
653
|
allChoiceIds.push(...choiceIds);
|
|
654
654
|
}
|
|
655
655
|
if (allChoiceIds.length > 0) {
|
|
656
|
-
newSearchOptions.filter[
|
|
656
|
+
newSearchOptions.filter['options.choicesSettings.choices.choiceId'] = { $hasSome: allChoiceIds };
|
|
657
657
|
}
|
|
658
658
|
}
|
|
659
659
|
if (selectedCategory) {
|
|
660
|
-
newSearchOptions.filter[
|
|
660
|
+
newSearchOptions.filter['allCategoriesInfo.categories'] = {
|
|
661
661
|
$matchItems: [{ _id: { $in: [selectedCategory._id] } }],
|
|
662
662
|
};
|
|
663
663
|
}
|
|
664
664
|
if (selectedVisible !== null) {
|
|
665
|
-
newSearchOptions.filter[
|
|
665
|
+
newSearchOptions.filter['visible'] = selectedVisible;
|
|
666
666
|
}
|
|
667
667
|
if (selectedProductType) {
|
|
668
|
-
newSearchOptions.filter[
|
|
668
|
+
newSearchOptions.filter['productType'] =
|
|
669
669
|
selectedProductType;
|
|
670
670
|
}
|
|
671
671
|
// Update the products list service
|
|
@@ -825,14 +825,14 @@ function getCatalogPriceRange(aggregationData) {
|
|
|
825
825
|
return { minPrice, maxPrice };
|
|
826
826
|
}
|
|
827
827
|
function getMinPrice(aggregationData) {
|
|
828
|
-
const minPriceAggregation = aggregationData.find((data) => data.fieldPath ===
|
|
828
|
+
const minPriceAggregation = aggregationData.find((data) => data.fieldPath === 'actualPriceRange.minValue.amount');
|
|
829
829
|
if (minPriceAggregation?.scalar?.value) {
|
|
830
830
|
return Number(minPriceAggregation.scalar.value) || 0;
|
|
831
831
|
}
|
|
832
832
|
return 0;
|
|
833
833
|
}
|
|
834
834
|
function getMaxPrice(aggregationData) {
|
|
835
|
-
const maxPriceAggregation = aggregationData.find((data) => data.fieldPath ===
|
|
835
|
+
const maxPriceAggregation = aggregationData.find((data) => data.fieldPath === 'actualPriceRange.maxValue.amount');
|
|
836
836
|
if (maxPriceAggregation?.scalar?.value) {
|
|
837
837
|
return Number(maxPriceAggregation.scalar.value) || 0;
|
|
838
838
|
}
|
|
@@ -859,15 +859,15 @@ function getAvailableProductOptions(aggregationData = [], customizations = []) {
|
|
|
859
859
|
const optionNames = [];
|
|
860
860
|
const choiceNames = [];
|
|
861
861
|
aggregationData.forEach((result) => {
|
|
862
|
-
if (result.name ===
|
|
862
|
+
if (result.name === 'optionNames' && result.values?.results) {
|
|
863
863
|
optionNames.push(...result.values.results
|
|
864
864
|
.map((item) => item.value)
|
|
865
|
-
.filter((value) => typeof value ===
|
|
865
|
+
.filter((value) => typeof value === 'string'));
|
|
866
866
|
}
|
|
867
|
-
if (result.name ===
|
|
867
|
+
if (result.name === 'choiceNames' && result.values?.results) {
|
|
868
868
|
choiceNames.push(...result.values.results
|
|
869
869
|
.map((item) => item.value)
|
|
870
|
-
.filter((value) => typeof value ===
|
|
870
|
+
.filter((value) => typeof value === 'string'));
|
|
871
871
|
}
|
|
872
872
|
});
|
|
873
873
|
const options = customizations
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type Signal } from
|
|
2
|
-
import { productsV3 } from
|
|
3
|
-
import { type InitialSearchState } from
|
|
1
|
+
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
2
|
+
import { productsV3 } from '@wix/stores';
|
|
3
|
+
import { type InitialSearchState } from './products-list-search-service.js';
|
|
4
4
|
export declare const DEFAULT_QUERY_LIMIT = 100;
|
|
5
5
|
/**
|
|
6
6
|
* Configuration interface for the Products List service.
|
|
@@ -115,7 +115,7 @@ export type ProductsListServiceConfig = {
|
|
|
115
115
|
* }
|
|
116
116
|
* ```
|
|
117
117
|
*
|
|
118
|
-
|
|
118
|
+
* @example
|
|
119
119
|
* ```tsx
|
|
120
120
|
* // Advanced: Performance optimization when using both services
|
|
121
121
|
* import { parseUrlToSearchOptions, loadProductsListServiceConfig, loadProductsListSearchServiceConfig, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { defineService, implementService } from
|
|
2
|
-
import { SignalsServiceDefinition, } from
|
|
3
|
-
import { productsV3, readOnlyVariantsV3 } from
|
|
4
|
-
import { loadCategoriesListServiceConfig } from
|
|
5
|
-
import { parseUrlToSearchOptions } from
|
|
1
|
+
import { defineService, implementService } from '@wix/services-definitions';
|
|
2
|
+
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
3
|
+
import { productsV3, readOnlyVariantsV3 } from '@wix/stores';
|
|
4
|
+
import { loadCategoriesListServiceConfig } from './categories-list-service.js';
|
|
5
|
+
import { parseUrlToSearchOptions, } from './products-list-search-service.js';
|
|
6
6
|
export const DEFAULT_QUERY_LIMIT = 100;
|
|
7
7
|
/**
|
|
8
8
|
* Loads products list service configuration from the Wix Stores API for SSR initialization.
|
|
@@ -101,7 +101,7 @@ export const DEFAULT_QUERY_LIMIT = 100;
|
|
|
101
101
|
* }
|
|
102
102
|
* ```
|
|
103
103
|
*
|
|
104
|
-
|
|
104
|
+
* @example
|
|
105
105
|
* ```tsx
|
|
106
106
|
* // Advanced: Performance optimization when using both services
|
|
107
107
|
* import { parseUrlToSearchOptions, loadProductsListServiceConfig, loadProductsListSearchServiceConfig, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
@@ -183,7 +183,7 @@ const fetchMissingVariants = async (products) => {
|
|
|
183
183
|
const items = [];
|
|
184
184
|
const res = await readOnlyVariantsV3
|
|
185
185
|
.queryVariants({})
|
|
186
|
-
.in(
|
|
186
|
+
.in('productData.productId', productIds)
|
|
187
187
|
.limit(DEFAULT_QUERY_LIMIT)
|
|
188
188
|
.find();
|
|
189
189
|
items.push(...res.items);
|
|
@@ -207,7 +207,7 @@ const fetchMissingVariants = async (products) => {
|
|
|
207
207
|
});
|
|
208
208
|
// Update products with their variants
|
|
209
209
|
return products.map((product) => {
|
|
210
|
-
const variants = variantsByProductId.get(product._id ||
|
|
210
|
+
const variants = variantsByProductId.get(product._id || '');
|
|
211
211
|
if (variants && variants.length > 0) {
|
|
212
212
|
return {
|
|
213
213
|
...product,
|
|
@@ -221,7 +221,7 @@ const fetchMissingVariants = async (products) => {
|
|
|
221
221
|
});
|
|
222
222
|
}
|
|
223
223
|
catch (error) {
|
|
224
|
-
console.error(
|
|
224
|
+
console.error('Failed to fetch missing variants:', error);
|
|
225
225
|
return products;
|
|
226
226
|
}
|
|
227
227
|
};
|
|
@@ -231,7 +231,7 @@ const fetchMissingVariants = async (products) => {
|
|
|
231
231
|
*
|
|
232
232
|
* @constant
|
|
233
233
|
*/
|
|
234
|
-
export const ProductsListServiceDefinition = defineService(
|
|
234
|
+
export const ProductsListServiceDefinition = defineService('products-list');
|
|
235
235
|
/**
|
|
236
236
|
* Implementation of the Products List service that manages reactive products data.
|
|
237
237
|
* This service provides signals for products data, search options, pagination, aggregations,
|
|
@@ -295,7 +295,7 @@ export const ProductListService = implementService.withConfig()(ProductsListServ
|
|
|
295
295
|
const aggregationsSignal = signalsService.signal(config.aggregations);
|
|
296
296
|
const isLoadingSignal = signalsService.signal(false);
|
|
297
297
|
const errorSignal = signalsService.signal(null);
|
|
298
|
-
if (typeof window !==
|
|
298
|
+
if (typeof window !== 'undefined') {
|
|
299
299
|
signalsService.effect(async () => {
|
|
300
300
|
// CRITICAL: Read the signals FIRST to establish dependencies, even on first run
|
|
301
301
|
const searchOptions = searchOptionsSignal.get();
|
|
@@ -318,7 +318,7 @@ export const ProductListService = implementService.withConfig()(ProductsListServ
|
|
|
318
318
|
pagingMetadataSignal.set(result.pagingMetadata);
|
|
319
319
|
}
|
|
320
320
|
catch (error) {
|
|
321
|
-
errorSignal.set(error instanceof Error ? error.message :
|
|
321
|
+
errorSignal.set(error instanceof Error ? error.message : 'Unknown error');
|
|
322
322
|
}
|
|
323
323
|
finally {
|
|
324
324
|
isLoadingSignal.set(false);
|