@wix/headless-stores 0.0.47 → 0.0.49
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/services/index.d.ts +1 -1
- package/cjs/dist/services/index.js +1 -1
- package/cjs/dist/services/products-list-search-service.d.ts +64 -5
- package/cjs/dist/services/products-list-search-service.js +77 -17
- package/cjs/dist/services/products-list-service.d.ts +55 -22
- package/cjs/dist/services/products-list-service.js +64 -22
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/products-list-search-service.d.ts +64 -5
- package/dist/services/products-list-search-service.js +77 -17
- package/dist/services/products-list-service.d.ts +55 -22
- package/dist/services/products-list-service.js +64 -22
- package/package.json +1 -1
|
@@ -4,4 +4,4 @@ export { ProductModifiersService, ProductModifiersServiceDefinition, } from "./p
|
|
|
4
4
|
export { ProductService, ProductServiceDefinition, loadProductServiceConfig, } from "./product-service.js";
|
|
5
5
|
export { SelectedVariantService, SelectedVariantServiceDefinition, } from "./selected-variant-service.js";
|
|
6
6
|
export { ProductListService, ProductsListServiceDefinition, loadProductsListServiceConfig, ProductsListServiceConfig, } from "./products-list-service.js";
|
|
7
|
-
export { ProductOption, InventoryStatusType, SortType, ProductChoice, ProductsListSearchService, ProductsListSearchServiceDefinition, ProductsListSearchServiceConfig, loadProductsListSearchServiceConfig,
|
|
7
|
+
export { ProductOption, InventoryStatusType, SortType, ProductChoice, ProductsListSearchService, ProductsListSearchServiceDefinition, ProductsListSearchServiceConfig, loadProductsListSearchServiceConfig, parseUrlToSearchOptions, convertUrlSortToSortType, } from "./products-list-search-service.js";
|
|
@@ -4,4 +4,4 @@ export { ProductModifiersService, ProductModifiersServiceDefinition, } from "./p
|
|
|
4
4
|
export { ProductService, ProductServiceDefinition, loadProductServiceConfig, } from "./product-service.js";
|
|
5
5
|
export { SelectedVariantService, SelectedVariantServiceDefinition, } from "./selected-variant-service.js";
|
|
6
6
|
export { ProductListService, ProductsListServiceDefinition, loadProductsListServiceConfig, } from "./products-list-service.js";
|
|
7
|
-
export { InventoryStatusType, SortType, ProductsListSearchService, ProductsListSearchServiceDefinition, loadProductsListSearchServiceConfig,
|
|
7
|
+
export { InventoryStatusType, SortType, ProductsListSearchService, ProductsListSearchServiceDefinition, loadProductsListSearchServiceConfig, parseUrlToSearchOptions, convertUrlSortToSortType, } from "./products-list-search-service.js";
|
|
@@ -33,7 +33,7 @@ export interface ProductChoice {
|
|
|
33
33
|
/**
|
|
34
34
|
* Initial search state that can be loaded from URL parameters.
|
|
35
35
|
*/
|
|
36
|
-
type InitialSearchState = {
|
|
36
|
+
export type InitialSearchState = {
|
|
37
37
|
sort?: SortType;
|
|
38
38
|
limit?: number;
|
|
39
39
|
cursor?: string | null;
|
|
@@ -138,16 +138,75 @@ export declare const ProductsListSearchServiceDefinition: string & {
|
|
|
138
138
|
*/
|
|
139
139
|
export declare function convertUrlSortToSortType(urlSort: string): SortType | null;
|
|
140
140
|
/**
|
|
141
|
-
* Parse URL and build complete search options with all filters, sort, and pagination
|
|
141
|
+
* Parse URL and build complete search options with all filters, sort, and pagination.
|
|
142
|
+
* This function extracts search parameters, filters, sorting, and pagination from a URL
|
|
143
|
+
* and converts them into the format expected by the Wix Stores API.
|
|
144
|
+
*
|
|
145
|
+
* @param {string} url - The URL to parse search parameters from
|
|
146
|
+
* @param {Category[]} categoriesList - List of available categories for category slug resolution
|
|
147
|
+
* @param {productsV3.V3ProductSearch} [defaultSearchOptions] - Default search options to merge with parsed URL parameters
|
|
148
|
+
* @returns {Promise<{searchOptions: productsV3.V3ProductSearch, initialSearchState: InitialSearchState}>}
|
|
149
|
+
* Object containing both API-ready search options and UI-ready initial state
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```tsx
|
|
153
|
+
* // Parse URL with filters, sort, and pagination
|
|
154
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
155
|
+
* const { searchOptions, initialSearchState } = await parseUrlToSearchOptions(
|
|
156
|
+
* 'https://example.com/products?sort=price:desc&Color=red,blue&minPrice=50',
|
|
157
|
+
* categories.categories
|
|
158
|
+
* );
|
|
159
|
+
*
|
|
160
|
+
* // Use searchOptions for API calls
|
|
161
|
+
* const products = await productsV3.searchProducts(searchOptions);
|
|
162
|
+
*
|
|
163
|
+
* // Use initialSearchState for UI initialization
|
|
164
|
+
* const filterState = initialSearchState.productOptions; // { colorId: ['red-id', 'blue-id'] }
|
|
165
|
+
* ```
|
|
142
166
|
*/
|
|
143
|
-
export declare function
|
|
167
|
+
export declare function parseUrlToSearchOptions(url: string, categoriesList: Category[], defaultSearchOptions?: productsV3.V3ProductSearch): Promise<{
|
|
144
168
|
searchOptions: productsV3.V3ProductSearch;
|
|
145
169
|
initialSearchState: InitialSearchState;
|
|
146
170
|
}>;
|
|
147
171
|
/**
|
|
148
|
-
* Load search service configuration from URL
|
|
172
|
+
* Load search service configuration from URL or parsed URL result.
|
|
173
|
+
* This function provides the configuration for the Products List Search service,
|
|
174
|
+
* including customizations and initial search state.
|
|
175
|
+
*
|
|
176
|
+
* @param {string | { searchOptions: productsV3.V3ProductSearch; initialSearchState: InitialSearchState }} input - Either a URL to parse or parsed URL result from parseUrlToSearchOptions
|
|
177
|
+
* @returns {Promise<ProductsListSearchServiceConfig>} Promise that resolves to the search service configuration
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```tsx
|
|
181
|
+
* // Option 1: Load from URL (will parse filters, sort, pagination from URL params)
|
|
182
|
+
* const searchConfig = await loadProductsListSearchServiceConfig(window.location.href);
|
|
183
|
+
*
|
|
184
|
+
* // Option 2: Custom parsing with defaults
|
|
185
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
186
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
187
|
+
* window.location.href,
|
|
188
|
+
* categories.categories,
|
|
189
|
+
* {
|
|
190
|
+
* cursorPaging: { limit: 12 },
|
|
191
|
+
* filter: { 'categoryIds': ['123'] },
|
|
192
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
193
|
+
* }
|
|
194
|
+
* );
|
|
195
|
+
* const searchConfig = await loadProductsListSearchServiceConfig(parsed);
|
|
196
|
+
*
|
|
197
|
+
* // Option 3: Performance optimization - use parsed result for both services (no duplicate parsing)
|
|
198
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
199
|
+
* const parsed = await parseUrlToSearchOptions(url, categories.categories);
|
|
200
|
+
* const [productsConfig, searchConfig] = await Promise.all([
|
|
201
|
+
* loadProductsListServiceConfig(parsed),
|
|
202
|
+
* loadProductsListSearchServiceConfig(parsed),
|
|
203
|
+
* ]);
|
|
204
|
+
* ```
|
|
149
205
|
*/
|
|
150
|
-
export declare function loadProductsListSearchServiceConfig(
|
|
206
|
+
export declare function loadProductsListSearchServiceConfig(input: string | {
|
|
207
|
+
searchOptions: productsV3.V3ProductSearch;
|
|
208
|
+
initialSearchState: InitialSearchState;
|
|
209
|
+
}): Promise<ProductsListSearchServiceConfig>;
|
|
151
210
|
/**
|
|
152
211
|
* Implementation of the Products List Search service
|
|
153
212
|
*/
|
|
@@ -141,21 +141,17 @@ function updateUrlWithSearchState(searchState) {
|
|
|
141
141
|
}
|
|
142
142
|
// Handle URL path construction with category
|
|
143
143
|
let baseUrl = window.location.pathname;
|
|
144
|
-
// If categorySlug is provided,
|
|
144
|
+
// If categorySlug is provided, replace the last path segment (which represents the category)
|
|
145
145
|
if (categorySlug) {
|
|
146
|
-
// Find if there's already a /category/ segment in the current path
|
|
147
146
|
const pathSegments = baseUrl.split("/").filter(Boolean);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
pathSegments[categoryIndex + 1] = categorySlug;
|
|
147
|
+
if (pathSegments.length > 0) {
|
|
148
|
+
// Replace the last segment with the new category slug
|
|
149
|
+
pathSegments[pathSegments.length - 1] = categorySlug;
|
|
152
150
|
baseUrl = "/" + pathSegments.join("/");
|
|
153
151
|
}
|
|
154
152
|
else {
|
|
155
|
-
//
|
|
156
|
-
baseUrl =
|
|
157
|
-
? `${baseUrl}category/${categorySlug}`
|
|
158
|
-
: `${baseUrl}/category/${categorySlug}`;
|
|
153
|
+
// If no segments, just use the category slug
|
|
154
|
+
baseUrl = `/${categorySlug}`;
|
|
159
155
|
}
|
|
160
156
|
}
|
|
161
157
|
// Build the new URL
|
|
@@ -168,9 +164,33 @@ function updateUrlWithSearchState(searchState) {
|
|
|
168
164
|
}
|
|
169
165
|
}
|
|
170
166
|
/**
|
|
171
|
-
* Parse URL and build complete search options with all filters, sort, and pagination
|
|
167
|
+
* Parse URL and build complete search options with all filters, sort, and pagination.
|
|
168
|
+
* This function extracts search parameters, filters, sorting, and pagination from a URL
|
|
169
|
+
* and converts them into the format expected by the Wix Stores API.
|
|
170
|
+
*
|
|
171
|
+
* @param {string} url - The URL to parse search parameters from
|
|
172
|
+
* @param {Category[]} categoriesList - List of available categories for category slug resolution
|
|
173
|
+
* @param {productsV3.V3ProductSearch} [defaultSearchOptions] - Default search options to merge with parsed URL parameters
|
|
174
|
+
* @returns {Promise<{searchOptions: productsV3.V3ProductSearch, initialSearchState: InitialSearchState}>}
|
|
175
|
+
* Object containing both API-ready search options and UI-ready initial state
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```tsx
|
|
179
|
+
* // Parse URL with filters, sort, and pagination
|
|
180
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
181
|
+
* const { searchOptions, initialSearchState } = await parseUrlToSearchOptions(
|
|
182
|
+
* 'https://example.com/products?sort=price:desc&Color=red,blue&minPrice=50',
|
|
183
|
+
* categories.categories
|
|
184
|
+
* );
|
|
185
|
+
*
|
|
186
|
+
* // Use searchOptions for API calls
|
|
187
|
+
* const products = await productsV3.searchProducts(searchOptions);
|
|
188
|
+
*
|
|
189
|
+
* // Use initialSearchState for UI initialization
|
|
190
|
+
* const filterState = initialSearchState.productOptions; // { colorId: ['red-id', 'blue-id'] }
|
|
191
|
+
* ```
|
|
172
192
|
*/
|
|
173
|
-
export async function
|
|
193
|
+
export async function parseUrlToSearchOptions(url, categoriesList, defaultSearchOptions) {
|
|
174
194
|
const urlObj = new URL(url);
|
|
175
195
|
const searchParams = urlObj.searchParams;
|
|
176
196
|
// Get customizations for product option parsing
|
|
@@ -403,12 +423,52 @@ export async function parseUrlForProductsListSearch(url, categoriesList, default
|
|
|
403
423
|
return { searchOptions, initialSearchState };
|
|
404
424
|
}
|
|
405
425
|
/**
|
|
406
|
-
* Load search service configuration from URL
|
|
426
|
+
* Load search service configuration from URL or parsed URL result.
|
|
427
|
+
* This function provides the configuration for the Products List Search service,
|
|
428
|
+
* including customizations and initial search state.
|
|
429
|
+
*
|
|
430
|
+
* @param {string | { searchOptions: productsV3.V3ProductSearch; initialSearchState: InitialSearchState }} input - Either a URL to parse or parsed URL result from parseUrlToSearchOptions
|
|
431
|
+
* @returns {Promise<ProductsListSearchServiceConfig>} Promise that resolves to the search service configuration
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* ```tsx
|
|
435
|
+
* // Option 1: Load from URL (will parse filters, sort, pagination from URL params)
|
|
436
|
+
* const searchConfig = await loadProductsListSearchServiceConfig(window.location.href);
|
|
437
|
+
*
|
|
438
|
+
* // Option 2: Custom parsing with defaults
|
|
439
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
440
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
441
|
+
* window.location.href,
|
|
442
|
+
* categories.categories,
|
|
443
|
+
* {
|
|
444
|
+
* cursorPaging: { limit: 12 },
|
|
445
|
+
* filter: { 'categoryIds': ['123'] },
|
|
446
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
447
|
+
* }
|
|
448
|
+
* );
|
|
449
|
+
* const searchConfig = await loadProductsListSearchServiceConfig(parsed);
|
|
450
|
+
*
|
|
451
|
+
* // Option 3: Performance optimization - use parsed result for both services (no duplicate parsing)
|
|
452
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
453
|
+
* const parsed = await parseUrlToSearchOptions(url, categories.categories);
|
|
454
|
+
* const [productsConfig, searchConfig] = await Promise.all([
|
|
455
|
+
* loadProductsListServiceConfig(parsed),
|
|
456
|
+
* loadProductsListSearchServiceConfig(parsed),
|
|
457
|
+
* ]);
|
|
458
|
+
* ```
|
|
407
459
|
*/
|
|
408
|
-
export async function loadProductsListSearchServiceConfig(
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
460
|
+
export async function loadProductsListSearchServiceConfig(input) {
|
|
461
|
+
let initialSearchState;
|
|
462
|
+
if (typeof input === 'string') {
|
|
463
|
+
// URL input - parse it
|
|
464
|
+
const categoriesListConfig = await loadCategoriesListServiceConfig();
|
|
465
|
+
const { initialSearchState: parsedState } = await parseUrlToSearchOptions(input, categoriesListConfig.categories);
|
|
466
|
+
initialSearchState = parsedState;
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
// Parsed URL result - use initialSearchState directly (no duplicate work)
|
|
470
|
+
initialSearchState = input.initialSearchState;
|
|
471
|
+
}
|
|
412
472
|
const { items: customizations = [] } = await customizationsV3
|
|
413
473
|
.queryCustomizations()
|
|
414
474
|
.find();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Signal } from "@wix/services-definitions/core-services/signals";
|
|
2
2
|
import { productsV3 } from "@wix/stores";
|
|
3
|
+
import { type InitialSearchState } from "./products-list-search-service.js";
|
|
3
4
|
export declare const DEFAULT_QUERY_LIMIT = 100;
|
|
4
5
|
/**
|
|
5
6
|
* Configuration interface for the Products List service.
|
|
@@ -20,27 +21,33 @@ export type ProductsListServiceConfig = {
|
|
|
20
21
|
/**
|
|
21
22
|
* Loads products list service configuration from the Wix Stores API for SSR initialization.
|
|
22
23
|
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
23
|
-
* a list of products based on search criteria.
|
|
24
|
+
* a list of products based on search criteria or URL parameters.
|
|
24
25
|
*
|
|
25
|
-
* @param {productsV3.V3ProductSearch}
|
|
26
|
+
* @param {string | { searchOptions: productsV3.V3ProductSearch; initialSearchState: InitialSearchState }} input - Either a URL to parse or parsed URL result from parseUrlToSearchOptions
|
|
26
27
|
* @returns {Promise<ProductsListServiceConfig>} Promise that resolves to the products list configuration
|
|
27
28
|
*
|
|
28
29
|
* @example
|
|
29
30
|
* ```astro
|
|
30
31
|
* ---
|
|
31
32
|
* // Astro page example - pages/products.astro
|
|
32
|
-
* import { loadProductsListServiceConfig } from '@wix/stores/services';
|
|
33
|
+
* import { loadProductsListServiceConfig, parseUrlToSearchOptions, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
33
34
|
* import { ProductList } from '@wix/stores/components';
|
|
34
35
|
*
|
|
35
|
-
* //
|
|
36
|
-
* const
|
|
37
|
-
* cursorPaging: { limit: 12 },
|
|
38
|
-
* filter: {},
|
|
39
|
-
* sort: [{ fieldName: 'name', order: 'ASC' }]
|
|
40
|
-
* };
|
|
36
|
+
* // Option 1: Load from URL (will parse filters, sort, pagination from URL params)
|
|
37
|
+
* const productsConfig = await loadProductsListServiceConfig(Astro.url.href);
|
|
41
38
|
*
|
|
42
|
-
* //
|
|
43
|
-
* const
|
|
39
|
+
* // Option 2: Custom parsing with defaults
|
|
40
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
41
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
42
|
+
* Astro.url.href,
|
|
43
|
+
* categories.categories,
|
|
44
|
+
* {
|
|
45
|
+
* cursorPaging: { limit: 12 },
|
|
46
|
+
* filter: {},
|
|
47
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
48
|
+
* }
|
|
49
|
+
* );
|
|
50
|
+
* const productsConfig = await loadProductsListServiceConfig(parsed);
|
|
44
51
|
* ---
|
|
45
52
|
*
|
|
46
53
|
* <ProductList.Root productsConfig={productsConfig}>
|
|
@@ -59,23 +66,31 @@ export type ProductsListServiceConfig = {
|
|
|
59
66
|
* ```tsx
|
|
60
67
|
* // Next.js page example - pages/products.tsx
|
|
61
68
|
* import { GetServerSideProps } from 'next';
|
|
62
|
-
* import { loadProductsListServiceConfig } from '@wix/stores/services';
|
|
69
|
+
* import { loadProductsListServiceConfig, parseUrlToSearchOptions, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
63
70
|
* import { ProductsList } from '@wix/stores/components';
|
|
64
71
|
*
|
|
65
72
|
* interface ProductsPageProps {
|
|
66
73
|
* productsConfig: Awaited<ReturnType<typeof loadProductsListServiceConfig>>;
|
|
67
74
|
* }
|
|
68
75
|
*
|
|
69
|
-
* export const getServerSideProps: GetServerSideProps<ProductsPageProps> = async () => {
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* filter: {
|
|
73
|
-
* 'allCategoriesInfo.categories': { $matchItems: [{ _id: { $in: [category._id] } }] }
|
|
74
|
-
* },
|
|
75
|
-
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
76
|
-
* };
|
|
76
|
+
* export const getServerSideProps: GetServerSideProps<ProductsPageProps> = async ({ req }) => {
|
|
77
|
+
* // Option 1: Parse from URL
|
|
78
|
+
* const productsConfig = await loadProductsListServiceConfig(`${req.url}`);
|
|
77
79
|
*
|
|
78
|
-
*
|
|
80
|
+
* // Option 2: Custom parsing with filters
|
|
81
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
82
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
83
|
+
* `${req.url}`,
|
|
84
|
+
* categories.categories,
|
|
85
|
+
* {
|
|
86
|
+
* cursorPaging: { limit: 12 },
|
|
87
|
+
* filter: {
|
|
88
|
+
* 'allCategoriesInfo.categories': { $matchItems: [{ _id: { $in: [category._id] } }] }
|
|
89
|
+
* },
|
|
90
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
91
|
+
* }
|
|
92
|
+
* );
|
|
93
|
+
* const productsConfig = await loadProductsListServiceConfig(parsed);
|
|
79
94
|
*
|
|
80
95
|
* return {
|
|
81
96
|
* props: {
|
|
@@ -99,8 +114,26 @@ export type ProductsListServiceConfig = {
|
|
|
99
114
|
* );
|
|
100
115
|
* }
|
|
101
116
|
* ```
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```tsx
|
|
120
|
+
* // Advanced: Performance optimization when using both services
|
|
121
|
+
* import { parseUrlToSearchOptions, loadProductsListServiceConfig, loadProductsListSearchServiceConfig, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
122
|
+
*
|
|
123
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
124
|
+
* const parsed = await parseUrlToSearchOptions(url, categories.categories);
|
|
125
|
+
*
|
|
126
|
+
* // Both services use the same parsed result (no duplicate URL parsing)
|
|
127
|
+
* const [productsConfig, searchConfig] = await Promise.all([
|
|
128
|
+
* loadProductsListServiceConfig(parsed),
|
|
129
|
+
* loadProductsListSearchServiceConfig(parsed)
|
|
130
|
+
* ]);
|
|
131
|
+
* ```
|
|
102
132
|
*/
|
|
103
|
-
export declare function loadProductsListServiceConfig(
|
|
133
|
+
export declare function loadProductsListServiceConfig(input: string | {
|
|
134
|
+
searchOptions: productsV3.V3ProductSearch;
|
|
135
|
+
initialSearchState: InitialSearchState;
|
|
136
|
+
}): Promise<ProductsListServiceConfig>;
|
|
104
137
|
/**
|
|
105
138
|
* Service definition for the Products List service.
|
|
106
139
|
* This defines the reactive API contract for managing a list of products with search, pagination, and filtering capabilities.
|
|
@@ -1,31 +1,39 @@
|
|
|
1
1
|
import { defineService, implementService } from "@wix/services-definitions";
|
|
2
2
|
import { SignalsServiceDefinition, } from "@wix/services-definitions/core-services/signals";
|
|
3
3
|
import { productsV3, readOnlyVariantsV3 } from "@wix/stores";
|
|
4
|
+
import { loadCategoriesListServiceConfig } from "./categories-list-service.js";
|
|
5
|
+
import { parseUrlToSearchOptions } from "./products-list-search-service.js";
|
|
4
6
|
export const DEFAULT_QUERY_LIMIT = 100;
|
|
5
7
|
/**
|
|
6
8
|
* Loads products list service configuration from the Wix Stores API for SSR initialization.
|
|
7
9
|
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
8
|
-
* a list of products based on search criteria.
|
|
10
|
+
* a list of products based on search criteria or URL parameters.
|
|
9
11
|
*
|
|
10
|
-
* @param {productsV3.V3ProductSearch}
|
|
12
|
+
* @param {string | { searchOptions: productsV3.V3ProductSearch; initialSearchState: InitialSearchState }} input - Either a URL to parse or parsed URL result from parseUrlToSearchOptions
|
|
11
13
|
* @returns {Promise<ProductsListServiceConfig>} Promise that resolves to the products list configuration
|
|
12
14
|
*
|
|
13
15
|
* @example
|
|
14
16
|
* ```astro
|
|
15
17
|
* ---
|
|
16
18
|
* // Astro page example - pages/products.astro
|
|
17
|
-
* import { loadProductsListServiceConfig } from '@wix/stores/services';
|
|
19
|
+
* import { loadProductsListServiceConfig, parseUrlToSearchOptions, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
18
20
|
* import { ProductList } from '@wix/stores/components';
|
|
19
21
|
*
|
|
20
|
-
* //
|
|
21
|
-
* const
|
|
22
|
-
* cursorPaging: { limit: 12 },
|
|
23
|
-
* filter: {},
|
|
24
|
-
* sort: [{ fieldName: 'name', order: 'ASC' }]
|
|
25
|
-
* };
|
|
22
|
+
* // Option 1: Load from URL (will parse filters, sort, pagination from URL params)
|
|
23
|
+
* const productsConfig = await loadProductsListServiceConfig(Astro.url.href);
|
|
26
24
|
*
|
|
27
|
-
* //
|
|
28
|
-
* const
|
|
25
|
+
* // Option 2: Custom parsing with defaults
|
|
26
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
27
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
28
|
+
* Astro.url.href,
|
|
29
|
+
* categories.categories,
|
|
30
|
+
* {
|
|
31
|
+
* cursorPaging: { limit: 12 },
|
|
32
|
+
* filter: {},
|
|
33
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
34
|
+
* }
|
|
35
|
+
* );
|
|
36
|
+
* const productsConfig = await loadProductsListServiceConfig(parsed);
|
|
29
37
|
* ---
|
|
30
38
|
*
|
|
31
39
|
* <ProductList.Root productsConfig={productsConfig}>
|
|
@@ -44,23 +52,31 @@ export const DEFAULT_QUERY_LIMIT = 100;
|
|
|
44
52
|
* ```tsx
|
|
45
53
|
* // Next.js page example - pages/products.tsx
|
|
46
54
|
* import { GetServerSideProps } from 'next';
|
|
47
|
-
* import { loadProductsListServiceConfig } from '@wix/stores/services';
|
|
55
|
+
* import { loadProductsListServiceConfig, parseUrlToSearchOptions, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
48
56
|
* import { ProductsList } from '@wix/stores/components';
|
|
49
57
|
*
|
|
50
58
|
* interface ProductsPageProps {
|
|
51
59
|
* productsConfig: Awaited<ReturnType<typeof loadProductsListServiceConfig>>;
|
|
52
60
|
* }
|
|
53
61
|
*
|
|
54
|
-
* export const getServerSideProps: GetServerSideProps<ProductsPageProps> = async () => {
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* filter: {
|
|
58
|
-
* 'allCategoriesInfo.categories': { $matchItems: [{ _id: { $in: [category._id] } }] }
|
|
59
|
-
* },
|
|
60
|
-
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
61
|
-
* };
|
|
62
|
+
* export const getServerSideProps: GetServerSideProps<ProductsPageProps> = async ({ req }) => {
|
|
63
|
+
* // Option 1: Parse from URL
|
|
64
|
+
* const productsConfig = await loadProductsListServiceConfig(`${req.url}`);
|
|
62
65
|
*
|
|
63
|
-
*
|
|
66
|
+
* // Option 2: Custom parsing with filters
|
|
67
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
68
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
69
|
+
* `${req.url}`,
|
|
70
|
+
* categories.categories,
|
|
71
|
+
* {
|
|
72
|
+
* cursorPaging: { limit: 12 },
|
|
73
|
+
* filter: {
|
|
74
|
+
* 'allCategoriesInfo.categories': { $matchItems: [{ _id: { $in: [category._id] } }] }
|
|
75
|
+
* },
|
|
76
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
77
|
+
* }
|
|
78
|
+
* );
|
|
79
|
+
* const productsConfig = await loadProductsListServiceConfig(parsed);
|
|
64
80
|
*
|
|
65
81
|
* return {
|
|
66
82
|
* props: {
|
|
@@ -84,8 +100,34 @@ export const DEFAULT_QUERY_LIMIT = 100;
|
|
|
84
100
|
* );
|
|
85
101
|
* }
|
|
86
102
|
* ```
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```tsx
|
|
106
|
+
* // Advanced: Performance optimization when using both services
|
|
107
|
+
* import { parseUrlToSearchOptions, loadProductsListServiceConfig, loadProductsListSearchServiceConfig, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
108
|
+
*
|
|
109
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
110
|
+
* const parsed = await parseUrlToSearchOptions(url, categories.categories);
|
|
111
|
+
*
|
|
112
|
+
* // Both services use the same parsed result (no duplicate URL parsing)
|
|
113
|
+
* const [productsConfig, searchConfig] = await Promise.all([
|
|
114
|
+
* loadProductsListServiceConfig(parsed),
|
|
115
|
+
* loadProductsListSearchServiceConfig(parsed)
|
|
116
|
+
* ]);
|
|
117
|
+
* ```
|
|
87
118
|
*/
|
|
88
|
-
export async function loadProductsListServiceConfig(
|
|
119
|
+
export async function loadProductsListServiceConfig(input) {
|
|
120
|
+
let searchOptions;
|
|
121
|
+
if (typeof input === 'string') {
|
|
122
|
+
// URL input - parse it
|
|
123
|
+
const categoriesListConfig = await loadCategoriesListServiceConfig();
|
|
124
|
+
const { searchOptions: parsedOptions } = await parseUrlToSearchOptions(input, categoriesListConfig.categories);
|
|
125
|
+
searchOptions = parsedOptions;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Parsed URL result - use searchOptions directly
|
|
129
|
+
searchOptions = input.searchOptions;
|
|
130
|
+
}
|
|
89
131
|
const searchWithoutFilter = { ...searchOptions, filter: {} };
|
|
90
132
|
const [resultWithoutFilter, resultWithFilter] = await Promise.all([
|
|
91
133
|
fetchProducts(searchWithoutFilter),
|
package/dist/services/index.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export { ProductModifiersService, ProductModifiersServiceDefinition, } from "./p
|
|
|
4
4
|
export { ProductService, ProductServiceDefinition, loadProductServiceConfig, } from "./product-service.js";
|
|
5
5
|
export { SelectedVariantService, SelectedVariantServiceDefinition, } from "./selected-variant-service.js";
|
|
6
6
|
export { ProductListService, ProductsListServiceDefinition, loadProductsListServiceConfig, ProductsListServiceConfig, } from "./products-list-service.js";
|
|
7
|
-
export { ProductOption, InventoryStatusType, SortType, ProductChoice, ProductsListSearchService, ProductsListSearchServiceDefinition, ProductsListSearchServiceConfig, loadProductsListSearchServiceConfig,
|
|
7
|
+
export { ProductOption, InventoryStatusType, SortType, ProductChoice, ProductsListSearchService, ProductsListSearchServiceDefinition, ProductsListSearchServiceConfig, loadProductsListSearchServiceConfig, parseUrlToSearchOptions, convertUrlSortToSortType, } from "./products-list-search-service.js";
|
package/dist/services/index.js
CHANGED
|
@@ -4,4 +4,4 @@ export { ProductModifiersService, ProductModifiersServiceDefinition, } from "./p
|
|
|
4
4
|
export { ProductService, ProductServiceDefinition, loadProductServiceConfig, } from "./product-service.js";
|
|
5
5
|
export { SelectedVariantService, SelectedVariantServiceDefinition, } from "./selected-variant-service.js";
|
|
6
6
|
export { ProductListService, ProductsListServiceDefinition, loadProductsListServiceConfig, } from "./products-list-service.js";
|
|
7
|
-
export { InventoryStatusType, SortType, ProductsListSearchService, ProductsListSearchServiceDefinition, loadProductsListSearchServiceConfig,
|
|
7
|
+
export { InventoryStatusType, SortType, ProductsListSearchService, ProductsListSearchServiceDefinition, loadProductsListSearchServiceConfig, parseUrlToSearchOptions, convertUrlSortToSortType, } from "./products-list-search-service.js";
|
|
@@ -33,7 +33,7 @@ export interface ProductChoice {
|
|
|
33
33
|
/**
|
|
34
34
|
* Initial search state that can be loaded from URL parameters.
|
|
35
35
|
*/
|
|
36
|
-
type InitialSearchState = {
|
|
36
|
+
export type InitialSearchState = {
|
|
37
37
|
sort?: SortType;
|
|
38
38
|
limit?: number;
|
|
39
39
|
cursor?: string | null;
|
|
@@ -138,16 +138,75 @@ export declare const ProductsListSearchServiceDefinition: string & {
|
|
|
138
138
|
*/
|
|
139
139
|
export declare function convertUrlSortToSortType(urlSort: string): SortType | null;
|
|
140
140
|
/**
|
|
141
|
-
* Parse URL and build complete search options with all filters, sort, and pagination
|
|
141
|
+
* Parse URL and build complete search options with all filters, sort, and pagination.
|
|
142
|
+
* This function extracts search parameters, filters, sorting, and pagination from a URL
|
|
143
|
+
* and converts them into the format expected by the Wix Stores API.
|
|
144
|
+
*
|
|
145
|
+
* @param {string} url - The URL to parse search parameters from
|
|
146
|
+
* @param {Category[]} categoriesList - List of available categories for category slug resolution
|
|
147
|
+
* @param {productsV3.V3ProductSearch} [defaultSearchOptions] - Default search options to merge with parsed URL parameters
|
|
148
|
+
* @returns {Promise<{searchOptions: productsV3.V3ProductSearch, initialSearchState: InitialSearchState}>}
|
|
149
|
+
* Object containing both API-ready search options and UI-ready initial state
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```tsx
|
|
153
|
+
* // Parse URL with filters, sort, and pagination
|
|
154
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
155
|
+
* const { searchOptions, initialSearchState } = await parseUrlToSearchOptions(
|
|
156
|
+
* 'https://example.com/products?sort=price:desc&Color=red,blue&minPrice=50',
|
|
157
|
+
* categories.categories
|
|
158
|
+
* );
|
|
159
|
+
*
|
|
160
|
+
* // Use searchOptions for API calls
|
|
161
|
+
* const products = await productsV3.searchProducts(searchOptions);
|
|
162
|
+
*
|
|
163
|
+
* // Use initialSearchState for UI initialization
|
|
164
|
+
* const filterState = initialSearchState.productOptions; // { colorId: ['red-id', 'blue-id'] }
|
|
165
|
+
* ```
|
|
142
166
|
*/
|
|
143
|
-
export declare function
|
|
167
|
+
export declare function parseUrlToSearchOptions(url: string, categoriesList: Category[], defaultSearchOptions?: productsV3.V3ProductSearch): Promise<{
|
|
144
168
|
searchOptions: productsV3.V3ProductSearch;
|
|
145
169
|
initialSearchState: InitialSearchState;
|
|
146
170
|
}>;
|
|
147
171
|
/**
|
|
148
|
-
* Load search service configuration from URL
|
|
172
|
+
* Load search service configuration from URL or parsed URL result.
|
|
173
|
+
* This function provides the configuration for the Products List Search service,
|
|
174
|
+
* including customizations and initial search state.
|
|
175
|
+
*
|
|
176
|
+
* @param {string | { searchOptions: productsV3.V3ProductSearch; initialSearchState: InitialSearchState }} input - Either a URL to parse or parsed URL result from parseUrlToSearchOptions
|
|
177
|
+
* @returns {Promise<ProductsListSearchServiceConfig>} Promise that resolves to the search service configuration
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```tsx
|
|
181
|
+
* // Option 1: Load from URL (will parse filters, sort, pagination from URL params)
|
|
182
|
+
* const searchConfig = await loadProductsListSearchServiceConfig(window.location.href);
|
|
183
|
+
*
|
|
184
|
+
* // Option 2: Custom parsing with defaults
|
|
185
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
186
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
187
|
+
* window.location.href,
|
|
188
|
+
* categories.categories,
|
|
189
|
+
* {
|
|
190
|
+
* cursorPaging: { limit: 12 },
|
|
191
|
+
* filter: { 'categoryIds': ['123'] },
|
|
192
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
193
|
+
* }
|
|
194
|
+
* );
|
|
195
|
+
* const searchConfig = await loadProductsListSearchServiceConfig(parsed);
|
|
196
|
+
*
|
|
197
|
+
* // Option 3: Performance optimization - use parsed result for both services (no duplicate parsing)
|
|
198
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
199
|
+
* const parsed = await parseUrlToSearchOptions(url, categories.categories);
|
|
200
|
+
* const [productsConfig, searchConfig] = await Promise.all([
|
|
201
|
+
* loadProductsListServiceConfig(parsed),
|
|
202
|
+
* loadProductsListSearchServiceConfig(parsed),
|
|
203
|
+
* ]);
|
|
204
|
+
* ```
|
|
149
205
|
*/
|
|
150
|
-
export declare function loadProductsListSearchServiceConfig(
|
|
206
|
+
export declare function loadProductsListSearchServiceConfig(input: string | {
|
|
207
|
+
searchOptions: productsV3.V3ProductSearch;
|
|
208
|
+
initialSearchState: InitialSearchState;
|
|
209
|
+
}): Promise<ProductsListSearchServiceConfig>;
|
|
151
210
|
/**
|
|
152
211
|
* Implementation of the Products List Search service
|
|
153
212
|
*/
|
|
@@ -141,21 +141,17 @@ function updateUrlWithSearchState(searchState) {
|
|
|
141
141
|
}
|
|
142
142
|
// Handle URL path construction with category
|
|
143
143
|
let baseUrl = window.location.pathname;
|
|
144
|
-
// If categorySlug is provided,
|
|
144
|
+
// If categorySlug is provided, replace the last path segment (which represents the category)
|
|
145
145
|
if (categorySlug) {
|
|
146
|
-
// Find if there's already a /category/ segment in the current path
|
|
147
146
|
const pathSegments = baseUrl.split("/").filter(Boolean);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
pathSegments[categoryIndex + 1] = categorySlug;
|
|
147
|
+
if (pathSegments.length > 0) {
|
|
148
|
+
// Replace the last segment with the new category slug
|
|
149
|
+
pathSegments[pathSegments.length - 1] = categorySlug;
|
|
152
150
|
baseUrl = "/" + pathSegments.join("/");
|
|
153
151
|
}
|
|
154
152
|
else {
|
|
155
|
-
//
|
|
156
|
-
baseUrl =
|
|
157
|
-
? `${baseUrl}category/${categorySlug}`
|
|
158
|
-
: `${baseUrl}/category/${categorySlug}`;
|
|
153
|
+
// If no segments, just use the category slug
|
|
154
|
+
baseUrl = `/${categorySlug}`;
|
|
159
155
|
}
|
|
160
156
|
}
|
|
161
157
|
// Build the new URL
|
|
@@ -168,9 +164,33 @@ function updateUrlWithSearchState(searchState) {
|
|
|
168
164
|
}
|
|
169
165
|
}
|
|
170
166
|
/**
|
|
171
|
-
* Parse URL and build complete search options with all filters, sort, and pagination
|
|
167
|
+
* Parse URL and build complete search options with all filters, sort, and pagination.
|
|
168
|
+
* This function extracts search parameters, filters, sorting, and pagination from a URL
|
|
169
|
+
* and converts them into the format expected by the Wix Stores API.
|
|
170
|
+
*
|
|
171
|
+
* @param {string} url - The URL to parse search parameters from
|
|
172
|
+
* @param {Category[]} categoriesList - List of available categories for category slug resolution
|
|
173
|
+
* @param {productsV3.V3ProductSearch} [defaultSearchOptions] - Default search options to merge with parsed URL parameters
|
|
174
|
+
* @returns {Promise<{searchOptions: productsV3.V3ProductSearch, initialSearchState: InitialSearchState}>}
|
|
175
|
+
* Object containing both API-ready search options and UI-ready initial state
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```tsx
|
|
179
|
+
* // Parse URL with filters, sort, and pagination
|
|
180
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
181
|
+
* const { searchOptions, initialSearchState } = await parseUrlToSearchOptions(
|
|
182
|
+
* 'https://example.com/products?sort=price:desc&Color=red,blue&minPrice=50',
|
|
183
|
+
* categories.categories
|
|
184
|
+
* );
|
|
185
|
+
*
|
|
186
|
+
* // Use searchOptions for API calls
|
|
187
|
+
* const products = await productsV3.searchProducts(searchOptions);
|
|
188
|
+
*
|
|
189
|
+
* // Use initialSearchState for UI initialization
|
|
190
|
+
* const filterState = initialSearchState.productOptions; // { colorId: ['red-id', 'blue-id'] }
|
|
191
|
+
* ```
|
|
172
192
|
*/
|
|
173
|
-
export async function
|
|
193
|
+
export async function parseUrlToSearchOptions(url, categoriesList, defaultSearchOptions) {
|
|
174
194
|
const urlObj = new URL(url);
|
|
175
195
|
const searchParams = urlObj.searchParams;
|
|
176
196
|
// Get customizations for product option parsing
|
|
@@ -403,12 +423,52 @@ export async function parseUrlForProductsListSearch(url, categoriesList, default
|
|
|
403
423
|
return { searchOptions, initialSearchState };
|
|
404
424
|
}
|
|
405
425
|
/**
|
|
406
|
-
* Load search service configuration from URL
|
|
426
|
+
* Load search service configuration from URL or parsed URL result.
|
|
427
|
+
* This function provides the configuration for the Products List Search service,
|
|
428
|
+
* including customizations and initial search state.
|
|
429
|
+
*
|
|
430
|
+
* @param {string | { searchOptions: productsV3.V3ProductSearch; initialSearchState: InitialSearchState }} input - Either a URL to parse or parsed URL result from parseUrlToSearchOptions
|
|
431
|
+
* @returns {Promise<ProductsListSearchServiceConfig>} Promise that resolves to the search service configuration
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* ```tsx
|
|
435
|
+
* // Option 1: Load from URL (will parse filters, sort, pagination from URL params)
|
|
436
|
+
* const searchConfig = await loadProductsListSearchServiceConfig(window.location.href);
|
|
437
|
+
*
|
|
438
|
+
* // Option 2: Custom parsing with defaults
|
|
439
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
440
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
441
|
+
* window.location.href,
|
|
442
|
+
* categories.categories,
|
|
443
|
+
* {
|
|
444
|
+
* cursorPaging: { limit: 12 },
|
|
445
|
+
* filter: { 'categoryIds': ['123'] },
|
|
446
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
447
|
+
* }
|
|
448
|
+
* );
|
|
449
|
+
* const searchConfig = await loadProductsListSearchServiceConfig(parsed);
|
|
450
|
+
*
|
|
451
|
+
* // Option 3: Performance optimization - use parsed result for both services (no duplicate parsing)
|
|
452
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
453
|
+
* const parsed = await parseUrlToSearchOptions(url, categories.categories);
|
|
454
|
+
* const [productsConfig, searchConfig] = await Promise.all([
|
|
455
|
+
* loadProductsListServiceConfig(parsed),
|
|
456
|
+
* loadProductsListSearchServiceConfig(parsed),
|
|
457
|
+
* ]);
|
|
458
|
+
* ```
|
|
407
459
|
*/
|
|
408
|
-
export async function loadProductsListSearchServiceConfig(
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
460
|
+
export async function loadProductsListSearchServiceConfig(input) {
|
|
461
|
+
let initialSearchState;
|
|
462
|
+
if (typeof input === 'string') {
|
|
463
|
+
// URL input - parse it
|
|
464
|
+
const categoriesListConfig = await loadCategoriesListServiceConfig();
|
|
465
|
+
const { initialSearchState: parsedState } = await parseUrlToSearchOptions(input, categoriesListConfig.categories);
|
|
466
|
+
initialSearchState = parsedState;
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
// Parsed URL result - use initialSearchState directly (no duplicate work)
|
|
470
|
+
initialSearchState = input.initialSearchState;
|
|
471
|
+
}
|
|
412
472
|
const { items: customizations = [] } = await customizationsV3
|
|
413
473
|
.queryCustomizations()
|
|
414
474
|
.find();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Signal } from "@wix/services-definitions/core-services/signals";
|
|
2
2
|
import { productsV3 } from "@wix/stores";
|
|
3
|
+
import { type InitialSearchState } from "./products-list-search-service.js";
|
|
3
4
|
export declare const DEFAULT_QUERY_LIMIT = 100;
|
|
4
5
|
/**
|
|
5
6
|
* Configuration interface for the Products List service.
|
|
@@ -20,27 +21,33 @@ export type ProductsListServiceConfig = {
|
|
|
20
21
|
/**
|
|
21
22
|
* Loads products list service configuration from the Wix Stores API for SSR initialization.
|
|
22
23
|
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
23
|
-
* a list of products based on search criteria.
|
|
24
|
+
* a list of products based on search criteria or URL parameters.
|
|
24
25
|
*
|
|
25
|
-
* @param {productsV3.V3ProductSearch}
|
|
26
|
+
* @param {string | { searchOptions: productsV3.V3ProductSearch; initialSearchState: InitialSearchState }} input - Either a URL to parse or parsed URL result from parseUrlToSearchOptions
|
|
26
27
|
* @returns {Promise<ProductsListServiceConfig>} Promise that resolves to the products list configuration
|
|
27
28
|
*
|
|
28
29
|
* @example
|
|
29
30
|
* ```astro
|
|
30
31
|
* ---
|
|
31
32
|
* // Astro page example - pages/products.astro
|
|
32
|
-
* import { loadProductsListServiceConfig } from '@wix/stores/services';
|
|
33
|
+
* import { loadProductsListServiceConfig, parseUrlToSearchOptions, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
33
34
|
* import { ProductList } from '@wix/stores/components';
|
|
34
35
|
*
|
|
35
|
-
* //
|
|
36
|
-
* const
|
|
37
|
-
* cursorPaging: { limit: 12 },
|
|
38
|
-
* filter: {},
|
|
39
|
-
* sort: [{ fieldName: 'name', order: 'ASC' }]
|
|
40
|
-
* };
|
|
36
|
+
* // Option 1: Load from URL (will parse filters, sort, pagination from URL params)
|
|
37
|
+
* const productsConfig = await loadProductsListServiceConfig(Astro.url.href);
|
|
41
38
|
*
|
|
42
|
-
* //
|
|
43
|
-
* const
|
|
39
|
+
* // Option 2: Custom parsing with defaults
|
|
40
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
41
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
42
|
+
* Astro.url.href,
|
|
43
|
+
* categories.categories,
|
|
44
|
+
* {
|
|
45
|
+
* cursorPaging: { limit: 12 },
|
|
46
|
+
* filter: {},
|
|
47
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
48
|
+
* }
|
|
49
|
+
* );
|
|
50
|
+
* const productsConfig = await loadProductsListServiceConfig(parsed);
|
|
44
51
|
* ---
|
|
45
52
|
*
|
|
46
53
|
* <ProductList.Root productsConfig={productsConfig}>
|
|
@@ -59,23 +66,31 @@ export type ProductsListServiceConfig = {
|
|
|
59
66
|
* ```tsx
|
|
60
67
|
* // Next.js page example - pages/products.tsx
|
|
61
68
|
* import { GetServerSideProps } from 'next';
|
|
62
|
-
* import { loadProductsListServiceConfig } from '@wix/stores/services';
|
|
69
|
+
* import { loadProductsListServiceConfig, parseUrlToSearchOptions, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
63
70
|
* import { ProductsList } from '@wix/stores/components';
|
|
64
71
|
*
|
|
65
72
|
* interface ProductsPageProps {
|
|
66
73
|
* productsConfig: Awaited<ReturnType<typeof loadProductsListServiceConfig>>;
|
|
67
74
|
* }
|
|
68
75
|
*
|
|
69
|
-
* export const getServerSideProps: GetServerSideProps<ProductsPageProps> = async () => {
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* filter: {
|
|
73
|
-
* 'allCategoriesInfo.categories': { $matchItems: [{ _id: { $in: [category._id] } }] }
|
|
74
|
-
* },
|
|
75
|
-
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
76
|
-
* };
|
|
76
|
+
* export const getServerSideProps: GetServerSideProps<ProductsPageProps> = async ({ req }) => {
|
|
77
|
+
* // Option 1: Parse from URL
|
|
78
|
+
* const productsConfig = await loadProductsListServiceConfig(`${req.url}`);
|
|
77
79
|
*
|
|
78
|
-
*
|
|
80
|
+
* // Option 2: Custom parsing with filters
|
|
81
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
82
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
83
|
+
* `${req.url}`,
|
|
84
|
+
* categories.categories,
|
|
85
|
+
* {
|
|
86
|
+
* cursorPaging: { limit: 12 },
|
|
87
|
+
* filter: {
|
|
88
|
+
* 'allCategoriesInfo.categories': { $matchItems: [{ _id: { $in: [category._id] } }] }
|
|
89
|
+
* },
|
|
90
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
91
|
+
* }
|
|
92
|
+
* );
|
|
93
|
+
* const productsConfig = await loadProductsListServiceConfig(parsed);
|
|
79
94
|
*
|
|
80
95
|
* return {
|
|
81
96
|
* props: {
|
|
@@ -99,8 +114,26 @@ export type ProductsListServiceConfig = {
|
|
|
99
114
|
* );
|
|
100
115
|
* }
|
|
101
116
|
* ```
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```tsx
|
|
120
|
+
* // Advanced: Performance optimization when using both services
|
|
121
|
+
* import { parseUrlToSearchOptions, loadProductsListServiceConfig, loadProductsListSearchServiceConfig, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
122
|
+
*
|
|
123
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
124
|
+
* const parsed = await parseUrlToSearchOptions(url, categories.categories);
|
|
125
|
+
*
|
|
126
|
+
* // Both services use the same parsed result (no duplicate URL parsing)
|
|
127
|
+
* const [productsConfig, searchConfig] = await Promise.all([
|
|
128
|
+
* loadProductsListServiceConfig(parsed),
|
|
129
|
+
* loadProductsListSearchServiceConfig(parsed)
|
|
130
|
+
* ]);
|
|
131
|
+
* ```
|
|
102
132
|
*/
|
|
103
|
-
export declare function loadProductsListServiceConfig(
|
|
133
|
+
export declare function loadProductsListServiceConfig(input: string | {
|
|
134
|
+
searchOptions: productsV3.V3ProductSearch;
|
|
135
|
+
initialSearchState: InitialSearchState;
|
|
136
|
+
}): Promise<ProductsListServiceConfig>;
|
|
104
137
|
/**
|
|
105
138
|
* Service definition for the Products List service.
|
|
106
139
|
* This defines the reactive API contract for managing a list of products with search, pagination, and filtering capabilities.
|
|
@@ -1,31 +1,39 @@
|
|
|
1
1
|
import { defineService, implementService } from "@wix/services-definitions";
|
|
2
2
|
import { SignalsServiceDefinition, } from "@wix/services-definitions/core-services/signals";
|
|
3
3
|
import { productsV3, readOnlyVariantsV3 } from "@wix/stores";
|
|
4
|
+
import { loadCategoriesListServiceConfig } from "./categories-list-service.js";
|
|
5
|
+
import { parseUrlToSearchOptions } from "./products-list-search-service.js";
|
|
4
6
|
export const DEFAULT_QUERY_LIMIT = 100;
|
|
5
7
|
/**
|
|
6
8
|
* Loads products list service configuration from the Wix Stores API for SSR initialization.
|
|
7
9
|
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
8
|
-
* a list of products based on search criteria.
|
|
10
|
+
* a list of products based on search criteria or URL parameters.
|
|
9
11
|
*
|
|
10
|
-
* @param {productsV3.V3ProductSearch}
|
|
12
|
+
* @param {string | { searchOptions: productsV3.V3ProductSearch; initialSearchState: InitialSearchState }} input - Either a URL to parse or parsed URL result from parseUrlToSearchOptions
|
|
11
13
|
* @returns {Promise<ProductsListServiceConfig>} Promise that resolves to the products list configuration
|
|
12
14
|
*
|
|
13
15
|
* @example
|
|
14
16
|
* ```astro
|
|
15
17
|
* ---
|
|
16
18
|
* // Astro page example - pages/products.astro
|
|
17
|
-
* import { loadProductsListServiceConfig } from '@wix/stores/services';
|
|
19
|
+
* import { loadProductsListServiceConfig, parseUrlToSearchOptions, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
18
20
|
* import { ProductList } from '@wix/stores/components';
|
|
19
21
|
*
|
|
20
|
-
* //
|
|
21
|
-
* const
|
|
22
|
-
* cursorPaging: { limit: 12 },
|
|
23
|
-
* filter: {},
|
|
24
|
-
* sort: [{ fieldName: 'name', order: 'ASC' }]
|
|
25
|
-
* };
|
|
22
|
+
* // Option 1: Load from URL (will parse filters, sort, pagination from URL params)
|
|
23
|
+
* const productsConfig = await loadProductsListServiceConfig(Astro.url.href);
|
|
26
24
|
*
|
|
27
|
-
* //
|
|
28
|
-
* const
|
|
25
|
+
* // Option 2: Custom parsing with defaults
|
|
26
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
27
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
28
|
+
* Astro.url.href,
|
|
29
|
+
* categories.categories,
|
|
30
|
+
* {
|
|
31
|
+
* cursorPaging: { limit: 12 },
|
|
32
|
+
* filter: {},
|
|
33
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
34
|
+
* }
|
|
35
|
+
* );
|
|
36
|
+
* const productsConfig = await loadProductsListServiceConfig(parsed);
|
|
29
37
|
* ---
|
|
30
38
|
*
|
|
31
39
|
* <ProductList.Root productsConfig={productsConfig}>
|
|
@@ -44,23 +52,31 @@ export const DEFAULT_QUERY_LIMIT = 100;
|
|
|
44
52
|
* ```tsx
|
|
45
53
|
* // Next.js page example - pages/products.tsx
|
|
46
54
|
* import { GetServerSideProps } from 'next';
|
|
47
|
-
* import { loadProductsListServiceConfig } from '@wix/stores/services';
|
|
55
|
+
* import { loadProductsListServiceConfig, parseUrlToSearchOptions, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
48
56
|
* import { ProductsList } from '@wix/stores/components';
|
|
49
57
|
*
|
|
50
58
|
* interface ProductsPageProps {
|
|
51
59
|
* productsConfig: Awaited<ReturnType<typeof loadProductsListServiceConfig>>;
|
|
52
60
|
* }
|
|
53
61
|
*
|
|
54
|
-
* export const getServerSideProps: GetServerSideProps<ProductsPageProps> = async () => {
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* filter: {
|
|
58
|
-
* 'allCategoriesInfo.categories': { $matchItems: [{ _id: { $in: [category._id] } }] }
|
|
59
|
-
* },
|
|
60
|
-
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
61
|
-
* };
|
|
62
|
+
* export const getServerSideProps: GetServerSideProps<ProductsPageProps> = async ({ req }) => {
|
|
63
|
+
* // Option 1: Parse from URL
|
|
64
|
+
* const productsConfig = await loadProductsListServiceConfig(`${req.url}`);
|
|
62
65
|
*
|
|
63
|
-
*
|
|
66
|
+
* // Option 2: Custom parsing with filters
|
|
67
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
68
|
+
* const parsed = await parseUrlToSearchOptions(
|
|
69
|
+
* `${req.url}`,
|
|
70
|
+
* categories.categories,
|
|
71
|
+
* {
|
|
72
|
+
* cursorPaging: { limit: 12 },
|
|
73
|
+
* filter: {
|
|
74
|
+
* 'allCategoriesInfo.categories': { $matchItems: [{ _id: { $in: [category._id] } }] }
|
|
75
|
+
* },
|
|
76
|
+
* sort: [{ fieldName: 'name' as const, order: 'ASC' as const }]
|
|
77
|
+
* }
|
|
78
|
+
* );
|
|
79
|
+
* const productsConfig = await loadProductsListServiceConfig(parsed);
|
|
64
80
|
*
|
|
65
81
|
* return {
|
|
66
82
|
* props: {
|
|
@@ -84,8 +100,34 @@ export const DEFAULT_QUERY_LIMIT = 100;
|
|
|
84
100
|
* );
|
|
85
101
|
* }
|
|
86
102
|
* ```
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```tsx
|
|
106
|
+
* // Advanced: Performance optimization when using both services
|
|
107
|
+
* import { parseUrlToSearchOptions, loadProductsListServiceConfig, loadProductsListSearchServiceConfig, loadCategoriesListServiceConfig } from '@wix/stores/services';
|
|
108
|
+
*
|
|
109
|
+
* const categories = await loadCategoriesListServiceConfig();
|
|
110
|
+
* const parsed = await parseUrlToSearchOptions(url, categories.categories);
|
|
111
|
+
*
|
|
112
|
+
* // Both services use the same parsed result (no duplicate URL parsing)
|
|
113
|
+
* const [productsConfig, searchConfig] = await Promise.all([
|
|
114
|
+
* loadProductsListServiceConfig(parsed),
|
|
115
|
+
* loadProductsListSearchServiceConfig(parsed)
|
|
116
|
+
* ]);
|
|
117
|
+
* ```
|
|
87
118
|
*/
|
|
88
|
-
export async function loadProductsListServiceConfig(
|
|
119
|
+
export async function loadProductsListServiceConfig(input) {
|
|
120
|
+
let searchOptions;
|
|
121
|
+
if (typeof input === 'string') {
|
|
122
|
+
// URL input - parse it
|
|
123
|
+
const categoriesListConfig = await loadCategoriesListServiceConfig();
|
|
124
|
+
const { searchOptions: parsedOptions } = await parseUrlToSearchOptions(input, categoriesListConfig.categories);
|
|
125
|
+
searchOptions = parsedOptions;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Parsed URL result - use searchOptions directly
|
|
129
|
+
searchOptions = input.searchOptions;
|
|
130
|
+
}
|
|
89
131
|
const searchWithoutFilter = { ...searchOptions, filter: {} };
|
|
90
132
|
const [resultWithoutFilter, resultWithFilter] = await Promise.all([
|
|
91
133
|
fetchProducts(searchWithoutFilter),
|