@wix/headless-stores 0.0.36 → 0.0.38
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/react/Category.d.ts +65 -59
- package/cjs/dist/react/Category.js +50 -83
- package/cjs/dist/react/CategoryList.d.ts +184 -0
- package/cjs/dist/react/CategoryList.js +174 -0
- package/cjs/dist/react/Product.d.ts +3 -3
- package/cjs/dist/react/Product.js +6 -6
- package/{dist/react/ProductsList.d.ts → cjs/dist/react/ProductList.d.ts} +71 -38
- package/cjs/dist/react/{ProductsList.js → ProductList.js} +30 -26
- package/cjs/dist/react/ProductListFilters.d.ts +244 -0
- package/cjs/dist/react/ProductListFilters.js +216 -0
- package/cjs/dist/react/ProductListPagination.d.ts +246 -0
- package/cjs/dist/react/ProductListPagination.js +207 -0
- package/cjs/dist/react/ProductListSort.d.ts +87 -0
- package/cjs/dist/react/ProductListSort.js +85 -0
- package/cjs/dist/react/ProductModifiers.d.ts +5 -5
- package/cjs/dist/react/ProductModifiers.js +10 -10
- package/cjs/dist/react/ProductVariantSelector.d.ts +5 -5
- package/cjs/dist/react/ProductVariantSelector.js +13 -10
- package/cjs/dist/react/SelectedVariant.d.ts +66 -3
- package/cjs/dist/react/SelectedVariant.js +106 -7
- package/cjs/dist/react/index.d.ts +6 -9
- package/cjs/dist/react/index.js +6 -9
- package/cjs/dist/services/buy-now-service.d.ts +208 -0
- package/cjs/dist/services/buy-now-service.js +132 -1
- package/cjs/dist/services/categories-list-service.d.ts +163 -0
- package/cjs/dist/services/categories-list-service.js +148 -0
- package/cjs/dist/services/category-service.d.ts +115 -70
- package/cjs/dist/services/category-service.js +101 -110
- package/cjs/dist/services/index.d.ts +6 -7
- package/cjs/dist/services/index.js +5 -16
- package/cjs/dist/services/pay-now-service.d.ts +146 -0
- package/cjs/dist/services/pay-now-service.js +112 -1
- package/cjs/dist/services/product-service.d.ts +71 -0
- package/cjs/dist/services/product-service.js +47 -0
- package/cjs/dist/services/products-list-filters-service.d.ts +292 -0
- package/cjs/dist/services/products-list-filters-service.js +446 -0
- package/cjs/dist/services/products-list-pagination-service.d.ts +186 -0
- package/cjs/dist/services/products-list-pagination-service.js +179 -0
- package/cjs/dist/services/products-list-service.d.ts +138 -52
- package/cjs/dist/services/products-list-service.js +185 -54
- package/cjs/dist/services/products-list-sort-service.d.ts +117 -0
- package/cjs/dist/services/products-list-sort-service.js +144 -0
- package/cjs/dist/utils/url-params.d.ts +68 -0
- package/cjs/dist/utils/url-params.js +72 -4
- package/dist/react/Category.d.ts +65 -59
- package/dist/react/Category.js +50 -83
- package/dist/react/CategoryList.d.ts +184 -0
- package/dist/react/CategoryList.js +174 -0
- package/dist/react/Product.d.ts +3 -3
- package/dist/react/Product.js +6 -6
- package/{cjs/dist/react/ProductsList.d.ts → dist/react/ProductList.d.ts} +71 -38
- package/dist/react/{ProductsList.js → ProductList.js} +30 -26
- package/dist/react/ProductListFilters.d.ts +244 -0
- package/dist/react/ProductListFilters.js +216 -0
- package/dist/react/ProductListPagination.d.ts +246 -0
- package/dist/react/ProductListPagination.js +207 -0
- package/dist/react/ProductListSort.d.ts +87 -0
- package/dist/react/ProductListSort.js +85 -0
- package/dist/react/ProductModifiers.d.ts +5 -5
- package/dist/react/ProductModifiers.js +10 -10
- package/dist/react/ProductVariantSelector.d.ts +5 -5
- package/dist/react/ProductVariantSelector.js +13 -10
- package/dist/react/SelectedVariant.d.ts +66 -3
- package/dist/react/SelectedVariant.js +106 -7
- package/dist/react/index.d.ts +6 -9
- package/dist/react/index.js +6 -9
- package/dist/services/buy-now-service.d.ts +208 -0
- package/dist/services/buy-now-service.js +132 -1
- package/dist/services/categories-list-service.d.ts +163 -0
- package/dist/services/categories-list-service.js +148 -0
- package/dist/services/category-service.d.ts +115 -70
- package/dist/services/category-service.js +101 -110
- package/dist/services/index.d.ts +6 -7
- package/dist/services/index.js +5 -16
- package/dist/services/pay-now-service.d.ts +146 -0
- package/dist/services/pay-now-service.js +112 -1
- package/dist/services/product-service.d.ts +71 -0
- package/dist/services/product-service.js +47 -0
- package/dist/services/products-list-filters-service.d.ts +292 -0
- package/dist/services/products-list-filters-service.js +446 -0
- package/dist/services/products-list-pagination-service.d.ts +186 -0
- package/dist/services/products-list-pagination-service.js +179 -0
- package/dist/services/products-list-service.d.ts +138 -52
- package/dist/services/products-list-service.js +185 -54
- package/dist/services/products-list-sort-service.d.ts +117 -0
- package/dist/services/products-list-sort-service.js +144 -0
- package/dist/utils/url-params.d.ts +68 -0
- package/dist/utils/url-params.js +72 -4
- package/package.json +3 -3
- package/cjs/dist/react/Collection.d.ts +0 -294
- package/cjs/dist/react/Collection.js +0 -345
- package/cjs/dist/react/FilteredCollection.d.ts +0 -299
- package/cjs/dist/react/FilteredCollection.js +0 -352
- package/cjs/dist/react/ProductActions.d.ts +0 -70
- package/cjs/dist/react/ProductActions.js +0 -104
- package/cjs/dist/react/RelatedProducts.d.ts +0 -169
- package/cjs/dist/react/RelatedProducts.js +0 -180
- package/cjs/dist/react/Sort.d.ts +0 -37
- package/cjs/dist/react/Sort.js +0 -36
- package/cjs/dist/services/catalog-service.d.ts +0 -36
- package/cjs/dist/services/catalog-service.js +0 -193
- package/cjs/dist/services/collection-service.d.ts +0 -124
- package/cjs/dist/services/collection-service.js +0 -628
- package/cjs/dist/services/filter-service.d.ts +0 -35
- package/cjs/dist/services/filter-service.js +0 -119
- package/cjs/dist/services/related-products-service.d.ts +0 -100
- package/cjs/dist/services/related-products-service.js +0 -127
- package/cjs/dist/services/sort-service.d.ts +0 -20
- package/cjs/dist/services/sort-service.js +0 -27
- package/dist/react/Collection.d.ts +0 -294
- package/dist/react/Collection.js +0 -345
- package/dist/react/FilteredCollection.d.ts +0 -299
- package/dist/react/FilteredCollection.js +0 -352
- package/dist/react/ProductActions.d.ts +0 -70
- package/dist/react/ProductActions.js +0 -104
- package/dist/react/RelatedProducts.d.ts +0 -169
- package/dist/react/RelatedProducts.js +0 -180
- package/dist/react/Sort.d.ts +0 -37
- package/dist/react/Sort.js +0 -36
- package/dist/services/catalog-service.d.ts +0 -36
- package/dist/services/catalog-service.js +0 -193
- package/dist/services/collection-service.d.ts +0 -124
- package/dist/services/collection-service.js +0 -628
- package/dist/services/filter-service.d.ts +0 -35
- package/dist/services/filter-service.js +0 -119
- package/dist/services/related-products-service.d.ts +0 -100
- package/dist/services/related-products-service.js +0 -127
- package/dist/services/sort-service.d.ts +0 -20
- package/dist/services/sort-service.js +0 -27
|
@@ -1,102 +1,89 @@
|
|
|
1
1
|
import { defineService, implementService } from "@wix/services-definitions";
|
|
2
2
|
import { SignalsServiceDefinition, } from "@wix/services-definitions/core-services/signals";
|
|
3
|
-
import { productsV3 } from "@wix/stores";
|
|
4
|
-
;
|
|
3
|
+
import { productsV3, readOnlyVariantsV3 } from "@wix/stores";
|
|
5
4
|
/**
|
|
6
|
-
* Loads products list service configuration from the Wix
|
|
5
|
+
* Loads products list service configuration from the Wix Stores API for SSR initialization.
|
|
7
6
|
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
8
|
-
* products based on search criteria
|
|
7
|
+
* a list of products based on search criteria.
|
|
9
8
|
*
|
|
10
|
-
* @param searchOptions
|
|
11
|
-
* @returns Promise that resolves to
|
|
9
|
+
* @param {Parameters<typeof productsV3.searchProducts>[0]} searchOptions - The search options for querying products
|
|
10
|
+
* @returns {Promise<ProductsListServiceConfig>} Promise that resolves to the products list configuration
|
|
12
11
|
*
|
|
13
12
|
* @example
|
|
14
13
|
* ```astro
|
|
15
14
|
* ---
|
|
16
|
-
* // Astro page example - pages/
|
|
15
|
+
* // Astro page example - pages/products.astro
|
|
17
16
|
* import { loadProductsListServiceConfig } from '@wix/stores/services';
|
|
18
|
-
* import {
|
|
19
|
-
*
|
|
20
|
-
* // Get search query from URL params
|
|
21
|
-
* const searchQuery = Astro.url.searchParams.get('q') || '';
|
|
22
|
-
* const category = Astro.url.searchParams.get('category');
|
|
17
|
+
* import { ProductList } from '@wix/stores/components';
|
|
23
18
|
*
|
|
24
|
-
* //
|
|
19
|
+
* // Define search options
|
|
25
20
|
* const searchOptions = {
|
|
26
|
-
*
|
|
27
|
-
* filter:
|
|
28
|
-
*
|
|
21
|
+
* cursorPaging: { limit: 12 },
|
|
22
|
+
* filter: {},
|
|
23
|
+
* sort: [{ fieldName: 'name', order: 'ASC' }]
|
|
29
24
|
* };
|
|
30
25
|
*
|
|
31
|
-
* // Load products during SSR
|
|
32
|
-
* const
|
|
26
|
+
* // Load products data during SSR
|
|
27
|
+
* const productsConfig = await loadProductsListServiceConfig(searchOptions);
|
|
33
28
|
* ---
|
|
34
29
|
*
|
|
35
|
-
* <
|
|
36
|
-
* <
|
|
30
|
+
* <ProductList.Root productsConfig={productsConfig}>
|
|
31
|
+
* <ProductList.ItemContent>
|
|
37
32
|
* {({ product }) => (
|
|
38
|
-
* <div
|
|
33
|
+
* <div>
|
|
39
34
|
* <h3>{product.name}</h3>
|
|
35
|
+
* <p>{product.description}</p>
|
|
40
36
|
* </div>
|
|
41
37
|
* )}
|
|
42
|
-
* </
|
|
43
|
-
* </
|
|
38
|
+
* </ProductList.ItemContent>
|
|
39
|
+
* </ProductList.Root>
|
|
44
40
|
* ```
|
|
45
41
|
*
|
|
46
42
|
* @example
|
|
47
43
|
* ```tsx
|
|
48
|
-
* // Next.js page example - pages/
|
|
44
|
+
* // Next.js page example - pages/products.tsx
|
|
49
45
|
* import { GetServerSideProps } from 'next';
|
|
50
46
|
* import { loadProductsListServiceConfig } from '@wix/stores/services';
|
|
51
47
|
* import { ProductsList } from '@wix/stores/components';
|
|
52
48
|
*
|
|
53
|
-
* interface
|
|
54
|
-
*
|
|
55
|
-
* searchQuery: string;
|
|
49
|
+
* interface ProductsPageProps {
|
|
50
|
+
* productsConfig: Awaited<ReturnType<typeof loadProductsListServiceConfig>>;
|
|
56
51
|
* }
|
|
57
52
|
*
|
|
58
|
-
* export const getServerSideProps: GetServerSideProps<
|
|
59
|
-
* const searchQuery = (query.q as string) || '';
|
|
60
|
-
* const category = query.category as string;
|
|
61
|
-
*
|
|
62
|
-
* // Build search options
|
|
53
|
+
* export const getServerSideProps: GetServerSideProps<ProductsPageProps> = async () => {
|
|
63
54
|
* const searchOptions = {
|
|
64
|
-
*
|
|
65
|
-
* filter:
|
|
66
|
-
*
|
|
55
|
+
* cursorPaging: { limit: 12 },
|
|
56
|
+
* filter: {},
|
|
57
|
+
* sort: [{ fieldName: 'name', order: 'ASC' }]
|
|
67
58
|
* };
|
|
68
59
|
*
|
|
69
|
-
*
|
|
70
|
-
* const productsListConfig = await loadProductsListServiceConfig(searchOptions);
|
|
60
|
+
* const productsConfig = await loadProductsListServiceConfig(searchOptions);
|
|
71
61
|
*
|
|
72
62
|
* return {
|
|
73
63
|
* props: {
|
|
74
|
-
*
|
|
75
|
-
* searchQuery,
|
|
64
|
+
* productsConfig,
|
|
76
65
|
* },
|
|
77
66
|
* };
|
|
78
67
|
* };
|
|
79
68
|
*
|
|
80
|
-
* export default function
|
|
69
|
+
* export default function ProductsPage({ productsConfig }: ProductsPageProps) {
|
|
81
70
|
* return (
|
|
82
|
-
* <
|
|
83
|
-
* <
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* <
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* </ProductsList.Root>
|
|
93
|
-
* </div>
|
|
71
|
+
* <ProductList.Root productsConfig={productsConfig}>
|
|
72
|
+
* <ProductList.ItemContent>
|
|
73
|
+
* {({ product }) => (
|
|
74
|
+
* <div>
|
|
75
|
+
* <h3>{product.name}</h3>
|
|
76
|
+
* <p>{product.description}</p>
|
|
77
|
+
* </div>
|
|
78
|
+
* )}
|
|
79
|
+
* </ProductList.ItemContent>
|
|
80
|
+
* </ProductList.Root>
|
|
94
81
|
* );
|
|
95
82
|
* }
|
|
96
83
|
* ```
|
|
97
84
|
*/
|
|
98
85
|
export async function loadProductsListServiceConfig(searchOptions) {
|
|
99
|
-
const result = await
|
|
86
|
+
const result = await fetchProducts(searchOptions);
|
|
100
87
|
return {
|
|
101
88
|
products: result.products ?? [],
|
|
102
89
|
searchOptions,
|
|
@@ -104,7 +91,151 @@ export async function loadProductsListServiceConfig(searchOptions) {
|
|
|
104
91
|
aggregations: result.aggregationData,
|
|
105
92
|
};
|
|
106
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Fetches products and their missing variants in one optimized request.
|
|
96
|
+
* This function wraps the standard searchProducts call and automatically
|
|
97
|
+
* fetches missing variant data for all products that need it.
|
|
98
|
+
*
|
|
99
|
+
* @param searchOptions - The search options for querying products
|
|
100
|
+
* @returns Promise that resolves to the search result with complete variant data
|
|
101
|
+
*/
|
|
102
|
+
const fetchProducts = async (searchOptions) => {
|
|
103
|
+
const result = await productsV3.searchProducts(searchOptions);
|
|
104
|
+
// Fetch missing variants for all products in one batch request
|
|
105
|
+
if (result.products) {
|
|
106
|
+
result.products = await fetchMissingVariants(result.products);
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Fetches missing variants for all products in one batch request.
|
|
112
|
+
* This function identifies products that need variant data and fetches
|
|
113
|
+
* all variants efficiently using the readOnlyVariantsV3 API.
|
|
114
|
+
*
|
|
115
|
+
* @param products - Array of products that may need variant data
|
|
116
|
+
* @returns Promise that resolves to products with complete variant information
|
|
117
|
+
*/
|
|
118
|
+
const fetchMissingVariants = async (products) => {
|
|
119
|
+
// Find products that need variants (both single and multi-variant products)
|
|
120
|
+
const productsNeedingVariants = products.filter((product) => !product.variantsInfo?.variants &&
|
|
121
|
+
product.variantSummary?.variantCount &&
|
|
122
|
+
product.variantSummary.variantCount > 0);
|
|
123
|
+
if (productsNeedingVariants.length === 0) {
|
|
124
|
+
return products;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const productIds = productsNeedingVariants
|
|
128
|
+
.map((p) => p._id)
|
|
129
|
+
.filter(Boolean);
|
|
130
|
+
if (productIds.length === 0) {
|
|
131
|
+
return products;
|
|
132
|
+
}
|
|
133
|
+
const items = [];
|
|
134
|
+
const res = await readOnlyVariantsV3
|
|
135
|
+
.queryVariants({})
|
|
136
|
+
.in("productData.productId", productIds)
|
|
137
|
+
.limit(100)
|
|
138
|
+
.find();
|
|
139
|
+
items.push(...res.items);
|
|
140
|
+
let nextRes = res;
|
|
141
|
+
while (nextRes.hasNext()) {
|
|
142
|
+
nextRes = await nextRes.next();
|
|
143
|
+
items.push(...nextRes.items);
|
|
144
|
+
}
|
|
145
|
+
const variantsByProductId = new Map();
|
|
146
|
+
items.forEach((item) => {
|
|
147
|
+
const productId = item.productData?.productId;
|
|
148
|
+
if (productId) {
|
|
149
|
+
if (!variantsByProductId.has(productId)) {
|
|
150
|
+
variantsByProductId.set(productId, []);
|
|
151
|
+
}
|
|
152
|
+
variantsByProductId.get(productId).push({
|
|
153
|
+
...item,
|
|
154
|
+
choices: item.optionChoices,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
// Update products with their variants
|
|
159
|
+
return products.map((product) => {
|
|
160
|
+
const variants = variantsByProductId.get(product._id || "");
|
|
161
|
+
if (variants && variants.length > 0) {
|
|
162
|
+
return {
|
|
163
|
+
...product,
|
|
164
|
+
variantsInfo: {
|
|
165
|
+
...product.variantsInfo,
|
|
166
|
+
variants,
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return product;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
console.error("Failed to fetch missing variants:", error);
|
|
175
|
+
return products;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
/**
|
|
179
|
+
* Service definition for the Products List service.
|
|
180
|
+
* This defines the reactive API contract for managing a list of products with search, pagination, and filtering capabilities.
|
|
181
|
+
*
|
|
182
|
+
* @constant
|
|
183
|
+
*/
|
|
107
184
|
export const ProductsListServiceDefinition = defineService("products-list");
|
|
185
|
+
/**
|
|
186
|
+
* Implementation of the Products List service that manages reactive products data.
|
|
187
|
+
* This service provides signals for products data, search options, pagination, aggregations,
|
|
188
|
+
* loading state, and error handling. It automatically re-fetches products when search options change.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```tsx
|
|
192
|
+
* import { ProductListService, ProductsListServiceDefinition } from '@wix/stores/services';
|
|
193
|
+
* import { useService } from '@wix/services-manager-react';
|
|
194
|
+
*
|
|
195
|
+
* function ProductsComponent({ productsConfig }) {
|
|
196
|
+
* return (
|
|
197
|
+
* <ServiceProvider services={createServicesMap([
|
|
198
|
+
* [ProductsListServiceDefinition, ProductListService.withConfig(productsConfig)]
|
|
199
|
+
* ])}>
|
|
200
|
+
* <ProductsDisplay />
|
|
201
|
+
* </ServiceProvider>
|
|
202
|
+
* );
|
|
203
|
+
* }
|
|
204
|
+
*
|
|
205
|
+
* function ProductsDisplay() {
|
|
206
|
+
* const productsService = useService(ProductsListServiceDefinition);
|
|
207
|
+
* const products = productsService.products.get();
|
|
208
|
+
* const isLoading = productsService.isLoading.get();
|
|
209
|
+
* const error = productsService.error.get();
|
|
210
|
+
*
|
|
211
|
+
* // Update search options to filter by category
|
|
212
|
+
* const filterByCategory = (categoryId: string) => {
|
|
213
|
+
* const currentOptions = productsService.searchOptions.get();
|
|
214
|
+
* productsService.setSearchOptions({
|
|
215
|
+
* ...currentOptions,
|
|
216
|
+
* filter: {
|
|
217
|
+
* ...currentOptions.filter,
|
|
218
|
+
* categoryIds: [categoryId]
|
|
219
|
+
* }
|
|
220
|
+
* });
|
|
221
|
+
* };
|
|
222
|
+
*
|
|
223
|
+
* if (isLoading) return <div>Loading products...</div>;
|
|
224
|
+
* if (error) return <div>Error: {error}</div>;
|
|
225
|
+
*
|
|
226
|
+
* return (
|
|
227
|
+
* <div>
|
|
228
|
+
* {products.map(product => (
|
|
229
|
+
* <div key={product._id}>
|
|
230
|
+
* <h3>{product.name}</h3>
|
|
231
|
+
* <p>{product.description}</p>
|
|
232
|
+
* </div>
|
|
233
|
+
* ))}
|
|
234
|
+
* </div>
|
|
235
|
+
* );
|
|
236
|
+
* }
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
108
239
|
export const ProductListService = implementService.withConfig()(ProductsListServiceDefinition, ({ getService, config }) => {
|
|
109
240
|
let firstRun = true;
|
|
110
241
|
const signalsService = getService(SignalsServiceDefinition);
|
|
@@ -132,7 +263,7 @@ export const ProductListService = implementService.withConfig()(ProductsListServ
|
|
|
132
263
|
},
|
|
133
264
|
}
|
|
134
265
|
: searchOptions;
|
|
135
|
-
const result = await
|
|
266
|
+
const result = await fetchProducts(affectiveSearchOptions);
|
|
136
267
|
productsSignal.set(result.products ?? []);
|
|
137
268
|
pagingMetadataSignal.set(result.pagingMetadata);
|
|
138
269
|
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { Signal } from "@wix/services-definitions/core-services/signals";
|
|
2
|
+
/**
|
|
3
|
+
* Service definition for the Products List Sort service.
|
|
4
|
+
* This defines the reactive API contract for managing product list sorting options.
|
|
5
|
+
*
|
|
6
|
+
* @constant
|
|
7
|
+
*/
|
|
8
|
+
export declare const ProductsListSortServiceDefinition: string & {
|
|
9
|
+
__api: {
|
|
10
|
+
/** Reactive signal containing the currently selected sort option */
|
|
11
|
+
selectedSortOption: Signal<string>;
|
|
12
|
+
/** Function to update the selected sort option */
|
|
13
|
+
setSelectedSortOption: (sort: string) => void;
|
|
14
|
+
/** Array of available sort types */
|
|
15
|
+
sortOptions: SortType[];
|
|
16
|
+
};
|
|
17
|
+
__config: {};
|
|
18
|
+
isServiceDefinition?: boolean;
|
|
19
|
+
} & {
|
|
20
|
+
/** Reactive signal containing the currently selected sort option */
|
|
21
|
+
selectedSortOption: Signal<string>;
|
|
22
|
+
/** Function to update the selected sort option */
|
|
23
|
+
setSelectedSortOption: (sort: string) => void;
|
|
24
|
+
/** Array of available sort types */
|
|
25
|
+
sortOptions: SortType[];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Configuration interface for the Products List Sort service.
|
|
29
|
+
* Currently empty as this service doesn't require initial configuration.
|
|
30
|
+
*
|
|
31
|
+
* @interface ProductsListSortServiceConfig
|
|
32
|
+
*/
|
|
33
|
+
export type ProductsListSortServiceConfig = {};
|
|
34
|
+
/**
|
|
35
|
+
* Enumeration of available product sort types.
|
|
36
|
+
* These values correspond to how products can be sorted in the product list.
|
|
37
|
+
*
|
|
38
|
+
* @enum {string}
|
|
39
|
+
*/
|
|
40
|
+
export declare enum SortType {
|
|
41
|
+
/** Sort by newest products first */
|
|
42
|
+
NEWEST = "newest",
|
|
43
|
+
/** Sort by product name in ascending order (A-Z) */
|
|
44
|
+
NAME_ASC = "name_asc",
|
|
45
|
+
/** Sort by product name in descending order (Z-A) */
|
|
46
|
+
NAME_DESC = "name_desc",
|
|
47
|
+
/** Sort by price in ascending order (lowest first) */
|
|
48
|
+
PRICE_ASC = "price_asc",
|
|
49
|
+
/** Sort by price in descending order (highest first) */
|
|
50
|
+
PRICE_DESC = "price_desc",
|
|
51
|
+
/** Sort by recommended products (algorithm-based) */
|
|
52
|
+
RECOMMENDED = "recommended"
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Implementation of the Products List Sort service that manages reactive sorting state.
|
|
56
|
+
* This service provides signals for the current sort option and automatically updates
|
|
57
|
+
* the products list search options when the sort selection changes.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import { ProductsListSortService, ProductsListSortServiceDefinition, SortType } from '@wix/stores/services';
|
|
62
|
+
* import { useService } from '@wix/services-manager-react';
|
|
63
|
+
*
|
|
64
|
+
* function SortComponent() {
|
|
65
|
+
* return (
|
|
66
|
+
* <ServiceProvider services={createServicesMap([
|
|
67
|
+
* [ProductsListSortServiceDefinition, ProductsListSortService.withConfig({})]
|
|
68
|
+
* ])}>
|
|
69
|
+
* <SortSelector />
|
|
70
|
+
* </ServiceProvider>
|
|
71
|
+
* );
|
|
72
|
+
* }
|
|
73
|
+
*
|
|
74
|
+
* function SortSelector() {
|
|
75
|
+
* const sortService = useService(ProductsListSortServiceDefinition);
|
|
76
|
+
* const selectedSort = sortService.selectedSortOption.get();
|
|
77
|
+
* const sortOptions = sortService.sortOptions;
|
|
78
|
+
*
|
|
79
|
+
* return (
|
|
80
|
+
* <select
|
|
81
|
+
* value={selectedSort}
|
|
82
|
+
* onChange={(e) => sortService.setSelectedSortOption(e.target.value)}
|
|
83
|
+
* >
|
|
84
|
+
* {sortOptions.map(option => (
|
|
85
|
+
* <option key={option} value={option}>
|
|
86
|
+
* {option === SortType.NAME_ASC ? 'Name A-Z' :
|
|
87
|
+
* option === SortType.NAME_DESC ? 'Name Z-A' :
|
|
88
|
+
* option === SortType.PRICE_ASC ? 'Price Low to High' :
|
|
89
|
+
* option === SortType.PRICE_DESC ? 'Price High to Low' :
|
|
90
|
+
* option === SortType.NEWEST ? 'Newest First' :
|
|
91
|
+
* 'Recommended'}
|
|
92
|
+
* </option>
|
|
93
|
+
* ))}
|
|
94
|
+
* </select>
|
|
95
|
+
* );
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export declare const ProductsListSortService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
100
|
+
__api: {
|
|
101
|
+
/** Reactive signal containing the currently selected sort option */
|
|
102
|
+
selectedSortOption: Signal<string>;
|
|
103
|
+
/** Function to update the selected sort option */
|
|
104
|
+
setSelectedSortOption: (sort: string) => void;
|
|
105
|
+
/** Array of available sort types */
|
|
106
|
+
sortOptions: SortType[];
|
|
107
|
+
};
|
|
108
|
+
__config: {};
|
|
109
|
+
isServiceDefinition?: boolean;
|
|
110
|
+
} & {
|
|
111
|
+
/** Reactive signal containing the currently selected sort option */
|
|
112
|
+
selectedSortOption: Signal<string>;
|
|
113
|
+
/** Function to update the selected sort option */
|
|
114
|
+
setSelectedSortOption: (sort: string) => void;
|
|
115
|
+
/** Array of available sort types */
|
|
116
|
+
sortOptions: SortType[];
|
|
117
|
+
}, ProductsListSortServiceConfig>;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { defineService, implementService } from "@wix/services-definitions";
|
|
2
|
+
import { SignalsServiceDefinition } from "@wix/services-definitions/core-services/signals";
|
|
3
|
+
import { ProductsListServiceDefinition } from "./products-list-service.js";
|
|
4
|
+
import { productsV3 } from "@wix/stores";
|
|
5
|
+
/**
|
|
6
|
+
* Service definition for the Products List Sort service.
|
|
7
|
+
* This defines the reactive API contract for managing product list sorting options.
|
|
8
|
+
*
|
|
9
|
+
* @constant
|
|
10
|
+
*/
|
|
11
|
+
export const ProductsListSortServiceDefinition = defineService("products-list-sort");
|
|
12
|
+
/**
|
|
13
|
+
* Enumeration of available product sort types.
|
|
14
|
+
* These values correspond to how products can be sorted in the product list.
|
|
15
|
+
*
|
|
16
|
+
* @enum {string}
|
|
17
|
+
*/
|
|
18
|
+
export var SortType;
|
|
19
|
+
(function (SortType) {
|
|
20
|
+
/** Sort by newest products first */
|
|
21
|
+
SortType["NEWEST"] = "newest";
|
|
22
|
+
/** Sort by product name in ascending order (A-Z) */
|
|
23
|
+
SortType["NAME_ASC"] = "name_asc";
|
|
24
|
+
/** Sort by product name in descending order (Z-A) */
|
|
25
|
+
SortType["NAME_DESC"] = "name_desc";
|
|
26
|
+
/** Sort by price in ascending order (lowest first) */
|
|
27
|
+
SortType["PRICE_ASC"] = "price_asc";
|
|
28
|
+
/** Sort by price in descending order (highest first) */
|
|
29
|
+
SortType["PRICE_DESC"] = "price_desc";
|
|
30
|
+
/** Sort by recommended products (algorithm-based) */
|
|
31
|
+
SortType["RECOMMENDED"] = "recommended";
|
|
32
|
+
})(SortType || (SortType = {}));
|
|
33
|
+
/**
|
|
34
|
+
* Implementation of the Products List Sort service that manages reactive sorting state.
|
|
35
|
+
* This service provides signals for the current sort option and automatically updates
|
|
36
|
+
* the products list search options when the sort selection changes.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* import { ProductsListSortService, ProductsListSortServiceDefinition, SortType } from '@wix/stores/services';
|
|
41
|
+
* import { useService } from '@wix/services-manager-react';
|
|
42
|
+
*
|
|
43
|
+
* function SortComponent() {
|
|
44
|
+
* return (
|
|
45
|
+
* <ServiceProvider services={createServicesMap([
|
|
46
|
+
* [ProductsListSortServiceDefinition, ProductsListSortService.withConfig({})]
|
|
47
|
+
* ])}>
|
|
48
|
+
* <SortSelector />
|
|
49
|
+
* </ServiceProvider>
|
|
50
|
+
* );
|
|
51
|
+
* }
|
|
52
|
+
*
|
|
53
|
+
* function SortSelector() {
|
|
54
|
+
* const sortService = useService(ProductsListSortServiceDefinition);
|
|
55
|
+
* const selectedSort = sortService.selectedSortOption.get();
|
|
56
|
+
* const sortOptions = sortService.sortOptions;
|
|
57
|
+
*
|
|
58
|
+
* return (
|
|
59
|
+
* <select
|
|
60
|
+
* value={selectedSort}
|
|
61
|
+
* onChange={(e) => sortService.setSelectedSortOption(e.target.value)}
|
|
62
|
+
* >
|
|
63
|
+
* {sortOptions.map(option => (
|
|
64
|
+
* <option key={option} value={option}>
|
|
65
|
+
* {option === SortType.NAME_ASC ? 'Name A-Z' :
|
|
66
|
+
* option === SortType.NAME_DESC ? 'Name Z-A' :
|
|
67
|
+
* option === SortType.PRICE_ASC ? 'Price Low to High' :
|
|
68
|
+
* option === SortType.PRICE_DESC ? 'Price High to Low' :
|
|
69
|
+
* option === SortType.NEWEST ? 'Newest First' :
|
|
70
|
+
* 'Recommended'}
|
|
71
|
+
* </option>
|
|
72
|
+
* ))}
|
|
73
|
+
* </select>
|
|
74
|
+
* );
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export const ProductsListSortService = implementService.withConfig()(ProductsListSortServiceDefinition, ({ getService }) => {
|
|
79
|
+
let firstRun = true;
|
|
80
|
+
const signalsService = getService(SignalsServiceDefinition);
|
|
81
|
+
const productsListService = getService(ProductsListServiceDefinition);
|
|
82
|
+
const selectedSortOptionSignal = signalsService.signal("name");
|
|
83
|
+
if (typeof window !== "undefined") {
|
|
84
|
+
signalsService.effect(() => {
|
|
85
|
+
const sort = selectedSortOptionSignal.get();
|
|
86
|
+
if (firstRun) {
|
|
87
|
+
firstRun = false;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const newSearchOptions = {
|
|
91
|
+
...productsListService.searchOptions.peek(),
|
|
92
|
+
};
|
|
93
|
+
if (!newSearchOptions.sort) {
|
|
94
|
+
newSearchOptions.sort = [];
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// Copy existing filter to avoid mutation
|
|
98
|
+
newSearchOptions.sort = [...newSearchOptions.sort];
|
|
99
|
+
}
|
|
100
|
+
switch (sort) {
|
|
101
|
+
case SortType.NAME_ASC:
|
|
102
|
+
newSearchOptions.sort = [
|
|
103
|
+
{ fieldName: "name", order: productsV3.SortDirection.ASC },
|
|
104
|
+
];
|
|
105
|
+
break;
|
|
106
|
+
case SortType.NAME_DESC:
|
|
107
|
+
newSearchOptions.sort = [
|
|
108
|
+
{ fieldName: "name", order: productsV3.SortDirection.DESC },
|
|
109
|
+
];
|
|
110
|
+
break;
|
|
111
|
+
case SortType.PRICE_ASC:
|
|
112
|
+
newSearchOptions.sort = [
|
|
113
|
+
{
|
|
114
|
+
fieldName: "actualPriceRange.minValue.amount",
|
|
115
|
+
order: productsV3.SortDirection.ASC,
|
|
116
|
+
},
|
|
117
|
+
];
|
|
118
|
+
break;
|
|
119
|
+
case SortType.PRICE_DESC:
|
|
120
|
+
newSearchOptions.sort = [
|
|
121
|
+
{
|
|
122
|
+
fieldName: "actualPriceRange.minValue.amount",
|
|
123
|
+
order: productsV3.SortDirection.DESC,
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
break;
|
|
127
|
+
case SortType.RECOMMENDED:
|
|
128
|
+
newSearchOptions.sort = [
|
|
129
|
+
{
|
|
130
|
+
fieldName: "name",
|
|
131
|
+
order: productsV3.SortDirection.DESC,
|
|
132
|
+
},
|
|
133
|
+
];
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
productsListService.setSearchOptions(newSearchOptions);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
selectedSortOption: selectedSortOptionSignal,
|
|
141
|
+
sortOptions: Object.values(SortType),
|
|
142
|
+
setSelectedSortOption: (sort) => selectedSortOptionSignal.set(sort),
|
|
143
|
+
};
|
|
144
|
+
});
|
|
@@ -1,5 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility class for managing URL parameters in web applications.
|
|
3
|
+
* Provides methods to parse, update, and retrieve URL search parameters with support for multiple values.
|
|
4
|
+
*
|
|
5
|
+
* @class URLParamsUtils
|
|
6
|
+
*/
|
|
1
7
|
export declare class URLParamsUtils {
|
|
8
|
+
/**
|
|
9
|
+
* Parses URLSearchParams into a more convenient format that supports multiple values for the same key.
|
|
10
|
+
* Converts multiple parameters with the same key into an array.
|
|
11
|
+
*
|
|
12
|
+
* @static
|
|
13
|
+
* @param {URLSearchParams} searchParams - The URLSearchParams object to parse
|
|
14
|
+
* @returns {Record<string, string | string[]>} Object with parameter names as keys and values as strings or arrays
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // URL: ?color=red&color=blue&size=large
|
|
19
|
+
* const params = new URLSearchParams('color=red&color=blue&size=large');
|
|
20
|
+
* const parsed = URLParamsUtils.parseSearchParams(params);
|
|
21
|
+
* // Result: { color: ['red', 'blue'], size: 'large' }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
2
24
|
static parseSearchParams(searchParams: URLSearchParams): Record<string, string | string[]>;
|
|
25
|
+
/**
|
|
26
|
+
* Updates the current page URL with new parameters without causing a page reload.
|
|
27
|
+
* Supports multiple values for the same parameter key.
|
|
28
|
+
*
|
|
29
|
+
* @static
|
|
30
|
+
* @param {Record<string, string | string[]>} params - Object with parameter names and values to set
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* // Update URL with single and multiple values
|
|
35
|
+
* URLParamsUtils.updateURL({
|
|
36
|
+
* category: 'electronics',
|
|
37
|
+
* color: ['red', 'blue'],
|
|
38
|
+
* price: '100'
|
|
39
|
+
* });
|
|
40
|
+
* // URL becomes: ?category=electronics&color=red&color=blue&price=100
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* // Clear all parameters by passing empty object
|
|
46
|
+
* URLParamsUtils.updateURL({});
|
|
47
|
+
* // URL becomes: current-path (no query string)
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
3
50
|
static updateURL(params: Record<string, string | string[]>): void;
|
|
51
|
+
/**
|
|
52
|
+
* Gets the current URL parameters parsed into a convenient format.
|
|
53
|
+
* Returns an empty object when running in server-side environment.
|
|
54
|
+
*
|
|
55
|
+
* @static
|
|
56
|
+
* @returns {Record<string, string | string[]>} Object with current URL parameters
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* // Current URL: ?category=electronics&color=red&color=blue
|
|
61
|
+
* const params = URLParamsUtils.getURLParams();
|
|
62
|
+
* // Result: { category: 'electronics', color: ['red', 'blue'] }
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* // Server-side usage
|
|
68
|
+
* const params = URLParamsUtils.getURLParams();
|
|
69
|
+
* // Result: {} (empty object)
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
4
72
|
static getURLParams(): Record<string, string | string[]>;
|
|
5
73
|
}
|