@wix/headless-stores 0.0.36 → 0.0.37
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/cjs/dist/react/ProductActions.d.ts +1 -1
- package/cjs/dist/react/ProductActions.js +2 -2
- 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 +3 -3
- package/cjs/dist/react/SelectedVariant.js +6 -6
- package/cjs/dist/react/index.d.ts +7 -9
- package/cjs/dist/react/index.js +7 -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 +98 -51
- 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/dist/react/ProductActions.d.ts +1 -1
- package/dist/react/ProductActions.js +2 -2
- 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 +3 -3
- package/dist/react/SelectedVariant.js +6 -6
- package/dist/react/index.d.ts +7 -9
- package/dist/react/index.js +7 -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 +98 -51
- 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/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/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,299 +0,0 @@
|
|
|
1
|
-
import React, { type ReactNode } from "react";
|
|
2
|
-
import { type AvailableOptions, type FilterServiceAPI, type Filter } from "../services/filter-service.js";
|
|
3
|
-
import { type V3Product } from "@wix/auto_sdk_stores_products-v-3";
|
|
4
|
-
import type { PropsWithChildren } from "react";
|
|
5
|
-
export type { AvailableOptions, Filter, FilterServiceAPI };
|
|
6
|
-
/**
|
|
7
|
-
* Root component that provides the FilteredCollection service context to its children.
|
|
8
|
-
* This component sets up the necessary services for managing filtered collection functionality.
|
|
9
|
-
*
|
|
10
|
-
* @order 1
|
|
11
|
-
* @component
|
|
12
|
-
* @example
|
|
13
|
-
* ```tsx
|
|
14
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
15
|
-
*
|
|
16
|
-
* function FilteredProductsPage() {
|
|
17
|
-
* return (
|
|
18
|
-
* <FilteredCollection.Root>
|
|
19
|
-
* <div>
|
|
20
|
-
* <FilteredCollection.Filters>
|
|
21
|
-
* {({ applyFilters, clearFilters, currentFilters, availableOptions, isFiltered }) => (
|
|
22
|
-
* <div className="filters">
|
|
23
|
-
* <h3>Filters</h3>
|
|
24
|
-
* <div className="price-filter">
|
|
25
|
-
* <label>Price Range</label>
|
|
26
|
-
* <input
|
|
27
|
-
* type="range"
|
|
28
|
-
* min={availableOptions.priceRange.min}
|
|
29
|
-
* max={availableOptions.priceRange.max}
|
|
30
|
-
* value={currentFilters.priceRange.min}
|
|
31
|
-
* onChange={(e) => applyFilters({
|
|
32
|
-
* ...currentFilters,
|
|
33
|
-
* priceRange: { ...currentFilters.priceRange, min: Number(e.target.value) }
|
|
34
|
-
* })}
|
|
35
|
-
* />
|
|
36
|
-
* </div>
|
|
37
|
-
* {isFiltered && (
|
|
38
|
-
* <button onClick={clearFilters}>Clear All Filters</button>
|
|
39
|
-
* )}
|
|
40
|
-
* </div>
|
|
41
|
-
* )}
|
|
42
|
-
* </FilteredCollection.Filters>
|
|
43
|
-
*
|
|
44
|
-
* <FilteredCollection.Grid>
|
|
45
|
-
* {({ products, isLoading, error, isEmpty, totalProducts, hasMoreProducts }) => (
|
|
46
|
-
* <div>
|
|
47
|
-
* {isLoading && <div>Loading filtered products...</div>}
|
|
48
|
-
* {error && <div>Error: {error}</div>}
|
|
49
|
-
* {isEmpty && <div>No products match your filters</div>}
|
|
50
|
-
* {products.length > 0 && (
|
|
51
|
-
* <div>
|
|
52
|
-
* <p>Showing {products.length} of {totalProducts} products</p>
|
|
53
|
-
* <div className="filtered-grid">
|
|
54
|
-
* {products.map(product => (
|
|
55
|
-
* <FilteredCollection.Item key={product.id} product={product}>
|
|
56
|
-
* {({ title, image, price, available, slug }) => (
|
|
57
|
-
* <div className={`product-item ${!available ? 'unavailable' : ''}`}>
|
|
58
|
-
* {image && <img src={image} alt={title} />}
|
|
59
|
-
* <h3>{title}</h3>
|
|
60
|
-
* <div className="price">{price}</div>
|
|
61
|
-
* <a href={`/product/${slug}`}>View Details</a>
|
|
62
|
-
* </div>
|
|
63
|
-
* )}
|
|
64
|
-
* </FilteredCollection.Item>
|
|
65
|
-
* ))}
|
|
66
|
-
* </div>
|
|
67
|
-
* {hasMoreProducts && (
|
|
68
|
-
* <FilteredCollection.LoadMore>
|
|
69
|
-
* {({ loadMore, isLoading }) => (
|
|
70
|
-
* <button onClick={loadMore} disabled={isLoading}>
|
|
71
|
-
* {isLoading ? 'Loading...' : 'Load More'}
|
|
72
|
-
* </button>
|
|
73
|
-
* )}
|
|
74
|
-
* </FilteredCollection.LoadMore>
|
|
75
|
-
* )}
|
|
76
|
-
* </div>
|
|
77
|
-
* )}
|
|
78
|
-
* </div>
|
|
79
|
-
* )}
|
|
80
|
-
* </FilteredCollection.Grid>
|
|
81
|
-
* </div>
|
|
82
|
-
* </FilteredCollection.Root>
|
|
83
|
-
* );
|
|
84
|
-
* }
|
|
85
|
-
* ```
|
|
86
|
-
*/
|
|
87
|
-
export declare function Root(props: PropsWithChildren<{}>): import("react/jsx-runtime").JSX.Element;
|
|
88
|
-
export interface FiltersLoadingProps {
|
|
89
|
-
children: (data: {
|
|
90
|
-
isFullyLoaded: boolean;
|
|
91
|
-
}) => ReactNode;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Headless component for displaying a loading state for filters
|
|
95
|
-
*
|
|
96
|
-
* @component
|
|
97
|
-
* @example
|
|
98
|
-
* ```tsx
|
|
99
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
100
|
-
*
|
|
101
|
-
* function FiltersLoadingIndicator() {
|
|
102
|
-
* return (
|
|
103
|
-
* <FilteredCollection.FiltersLoading>
|
|
104
|
-
* {({ isFullyLoaded }) => (
|
|
105
|
-
* <div>
|
|
106
|
-
* {!isFullyLoaded && (
|
|
107
|
-
* <div className="loading-pulse">
|
|
108
|
-
* Loading filters...
|
|
109
|
-
* </div>
|
|
110
|
-
* )}
|
|
111
|
-
* </div>
|
|
112
|
-
* )}
|
|
113
|
-
* </FilteredCollection.FiltersLoading>
|
|
114
|
-
* );
|
|
115
|
-
* }
|
|
116
|
-
* ```
|
|
117
|
-
*/
|
|
118
|
-
export declare const FiltersLoading: React.FC<FiltersLoadingProps>;
|
|
119
|
-
export interface FilteredGridProps {
|
|
120
|
-
children: (data: {
|
|
121
|
-
products: V3Product[];
|
|
122
|
-
totalProducts: number;
|
|
123
|
-
isLoading: boolean;
|
|
124
|
-
error: string | null;
|
|
125
|
-
isEmpty: boolean;
|
|
126
|
-
hasMoreProducts: boolean;
|
|
127
|
-
}) => ReactNode;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Headless component for displaying a grid of filtered products
|
|
131
|
-
*
|
|
132
|
-
* @component
|
|
133
|
-
* @example
|
|
134
|
-
* ```tsx
|
|
135
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
136
|
-
*
|
|
137
|
-
* function FilteredProductsGrid() {
|
|
138
|
-
* return (
|
|
139
|
-
* <FilteredCollection.Grid>
|
|
140
|
-
* {({ products, isLoading, error, isEmpty, totalProducts, hasMoreProducts }) => (
|
|
141
|
-
* <div>
|
|
142
|
-
* {isLoading && <div>Loading filtered products...</div>}
|
|
143
|
-
* {error && <div>Error: {error}</div>}
|
|
144
|
-
* {isEmpty && <div>No products match your filters</div>}
|
|
145
|
-
* {products.length > 0 && (
|
|
146
|
-
* <div>
|
|
147
|
-
* <p>Showing {products.length} of {totalProducts} products</p>
|
|
148
|
-
* <div className="filtered-grid">
|
|
149
|
-
* {products.map(product => (
|
|
150
|
-
* <div key={product.id}>{product.name}</div>
|
|
151
|
-
* ))}
|
|
152
|
-
* </div>
|
|
153
|
-
* {hasMoreProducts && <button>Load More</button>}
|
|
154
|
-
* </div>
|
|
155
|
-
* )}
|
|
156
|
-
* </div>
|
|
157
|
-
* )}
|
|
158
|
-
* </FilteredCollection.Grid>
|
|
159
|
-
* );
|
|
160
|
-
* }
|
|
161
|
-
* ```
|
|
162
|
-
*/
|
|
163
|
-
export declare const Grid: React.FC<FilteredGridProps>;
|
|
164
|
-
export interface FilteredItemProps {
|
|
165
|
-
product: V3Product;
|
|
166
|
-
children: (data: {
|
|
167
|
-
title: string;
|
|
168
|
-
image: string | null;
|
|
169
|
-
imageAltText: string | null;
|
|
170
|
-
price: string;
|
|
171
|
-
compareAtPrice: string | null;
|
|
172
|
-
available: boolean;
|
|
173
|
-
slug: string;
|
|
174
|
-
description?: string;
|
|
175
|
-
}) => ReactNode;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Headless component for displaying a filtered product item
|
|
179
|
-
*
|
|
180
|
-
* @component
|
|
181
|
-
* @example
|
|
182
|
-
* ```tsx
|
|
183
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
184
|
-
*
|
|
185
|
-
* function FilteredProductItem({ product }) {
|
|
186
|
-
* return (
|
|
187
|
-
* <FilteredCollection.Item product={product}>
|
|
188
|
-
* {({ title, image, price, compareAtPrice, available, slug, description }) => (
|
|
189
|
-
* <div className={`product-item ${!available ? 'unavailable' : ''}`}>
|
|
190
|
-
* {image && <img src={image} alt={title} />}
|
|
191
|
-
* <h3>{title}</h3>
|
|
192
|
-
* {description && <p>{description}</p>}
|
|
193
|
-
* <div className="price">
|
|
194
|
-
* <span className="current">{price}</span>
|
|
195
|
-
* {compareAtPrice && <span className="compare"><s>{compareAtPrice}</s></span>}
|
|
196
|
-
* </div>
|
|
197
|
-
* {!available && <div className="out-of-stock">Out of Stock</div>}
|
|
198
|
-
* <a href={`/product/${slug}`}>View Details</a>
|
|
199
|
-
* </div>
|
|
200
|
-
* )}
|
|
201
|
-
* </FilteredCollection.Item>
|
|
202
|
-
* );
|
|
203
|
-
* }
|
|
204
|
-
* ```
|
|
205
|
-
*/
|
|
206
|
-
export declare const Item: React.FC<FilteredItemProps>;
|
|
207
|
-
export interface FilteredLoadMoreProps {
|
|
208
|
-
children: (data: {
|
|
209
|
-
loadMore: () => Promise<void>;
|
|
210
|
-
refresh: () => Promise<void>;
|
|
211
|
-
isLoading: boolean;
|
|
212
|
-
hasProducts: boolean;
|
|
213
|
-
totalProducts: number;
|
|
214
|
-
hasMoreProducts: boolean;
|
|
215
|
-
}) => ReactNode;
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Headless component for load more filtered products functionality
|
|
219
|
-
*
|
|
220
|
-
* @component
|
|
221
|
-
* @example
|
|
222
|
-
* ```tsx
|
|
223
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
224
|
-
*
|
|
225
|
-
* function LoadMoreProducts() {
|
|
226
|
-
* return (
|
|
227
|
-
* <FilteredCollection.LoadMore>
|
|
228
|
-
* {({ loadMore, refresh, isLoading, hasProducts, totalProducts, hasMoreProducts }) => (
|
|
229
|
-
* <div>
|
|
230
|
-
* {hasProducts && (
|
|
231
|
-
* <div>
|
|
232
|
-
* <p>Showing products ({totalProducts} total)</p>
|
|
233
|
-
* {hasMoreProducts && (
|
|
234
|
-
* <button
|
|
235
|
-
* onClick={loadMore}
|
|
236
|
-
* disabled={isLoading}
|
|
237
|
-
* >
|
|
238
|
-
* {isLoading ? 'Loading...' : 'Load More'}
|
|
239
|
-
* </button>
|
|
240
|
-
* )}
|
|
241
|
-
* <button onClick={refresh}>Refresh</button>
|
|
242
|
-
* </div>
|
|
243
|
-
* )}
|
|
244
|
-
* </div>
|
|
245
|
-
* )}
|
|
246
|
-
* </FilteredCollection.LoadMore>
|
|
247
|
-
* );
|
|
248
|
-
* }
|
|
249
|
-
* ```
|
|
250
|
-
*/
|
|
251
|
-
export declare const LoadMore: React.FC<FilteredLoadMoreProps>;
|
|
252
|
-
export interface FilteredFiltersProps {
|
|
253
|
-
children: (data: {
|
|
254
|
-
applyFilters: (filters: Filter) => void;
|
|
255
|
-
clearFilters: () => void;
|
|
256
|
-
currentFilters: Filter;
|
|
257
|
-
allProducts: V3Product[];
|
|
258
|
-
availableOptions: AvailableOptions;
|
|
259
|
-
isFiltered: boolean;
|
|
260
|
-
}) => ReactNode;
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Headless component for product filters with available options
|
|
264
|
-
*
|
|
265
|
-
* @component
|
|
266
|
-
* @example
|
|
267
|
-
* ```tsx
|
|
268
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
269
|
-
*
|
|
270
|
-
* function ProductFilters() {
|
|
271
|
-
* return (
|
|
272
|
-
* <FilteredCollection.Filters>
|
|
273
|
-
* {({ applyFilters, clearFilters, currentFilters, availableOptions, isFiltered }) => (
|
|
274
|
-
* <div className="filters">
|
|
275
|
-
* <h3>Filters</h3>
|
|
276
|
-
* <div className="price-filter">
|
|
277
|
-
* <label>Price Range</label>
|
|
278
|
-
* <input
|
|
279
|
-
* type="range"
|
|
280
|
-
* min={availableOptions.priceRange.min}
|
|
281
|
-
* max={availableOptions.priceRange.max}
|
|
282
|
-
* value={currentFilters.priceRange.min}
|
|
283
|
-
* onChange={(e) => applyFilters({
|
|
284
|
-
* ...currentFilters,
|
|
285
|
-
* priceRange: { ...currentFilters.priceRange, min: Number(e.target.value) }
|
|
286
|
-
* })}
|
|
287
|
-
* />
|
|
288
|
-
* </div>
|
|
289
|
-
* {isFiltered && (
|
|
290
|
-
* <button onClick={clearFilters}>Clear All Filters</button>
|
|
291
|
-
* )}
|
|
292
|
-
* </div>
|
|
293
|
-
* )}
|
|
294
|
-
* </FilteredCollection.Filters>
|
|
295
|
-
* );
|
|
296
|
-
* }
|
|
297
|
-
* ```
|
|
298
|
-
*/
|
|
299
|
-
export declare const Filters: React.FC<FilteredFiltersProps>;
|
|
@@ -1,352 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useService, WixServices } from "@wix/services-manager-react";
|
|
3
|
-
import { CollectionServiceDefinition, CollectionService, } from "../services/collection-service.js";
|
|
4
|
-
import { FilterServiceDefinition, FilterService, } from "../services/filter-service.js";
|
|
5
|
-
import { CategoryServiceDefinition, CategoryService, } from "../services/category-service.js";
|
|
6
|
-
import { SortServiceDefinition, SortService, } from "../services/sort-service.js";
|
|
7
|
-
import { CatalogServiceDefinition, CatalogService, } from "../services/catalog-service.js";
|
|
8
|
-
import { InventoryAvailabilityStatus, } from "@wix/auto_sdk_stores_products-v-3";
|
|
9
|
-
import { createServicesMap } from "@wix/services-manager";
|
|
10
|
-
/**
|
|
11
|
-
* Root component that provides the FilteredCollection service context to its children.
|
|
12
|
-
* This component sets up the necessary services for managing filtered collection functionality.
|
|
13
|
-
*
|
|
14
|
-
* @order 1
|
|
15
|
-
* @component
|
|
16
|
-
* @example
|
|
17
|
-
* ```tsx
|
|
18
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
19
|
-
*
|
|
20
|
-
* function FilteredProductsPage() {
|
|
21
|
-
* return (
|
|
22
|
-
* <FilteredCollection.Root>
|
|
23
|
-
* <div>
|
|
24
|
-
* <FilteredCollection.Filters>
|
|
25
|
-
* {({ applyFilters, clearFilters, currentFilters, availableOptions, isFiltered }) => (
|
|
26
|
-
* <div className="filters">
|
|
27
|
-
* <h3>Filters</h3>
|
|
28
|
-
* <div className="price-filter">
|
|
29
|
-
* <label>Price Range</label>
|
|
30
|
-
* <input
|
|
31
|
-
* type="range"
|
|
32
|
-
* min={availableOptions.priceRange.min}
|
|
33
|
-
* max={availableOptions.priceRange.max}
|
|
34
|
-
* value={currentFilters.priceRange.min}
|
|
35
|
-
* onChange={(e) => applyFilters({
|
|
36
|
-
* ...currentFilters,
|
|
37
|
-
* priceRange: { ...currentFilters.priceRange, min: Number(e.target.value) }
|
|
38
|
-
* })}
|
|
39
|
-
* />
|
|
40
|
-
* </div>
|
|
41
|
-
* {isFiltered && (
|
|
42
|
-
* <button onClick={clearFilters}>Clear All Filters</button>
|
|
43
|
-
* )}
|
|
44
|
-
* </div>
|
|
45
|
-
* )}
|
|
46
|
-
* </FilteredCollection.Filters>
|
|
47
|
-
*
|
|
48
|
-
* <FilteredCollection.Grid>
|
|
49
|
-
* {({ products, isLoading, error, isEmpty, totalProducts, hasMoreProducts }) => (
|
|
50
|
-
* <div>
|
|
51
|
-
* {isLoading && <div>Loading filtered products...</div>}
|
|
52
|
-
* {error && <div>Error: {error}</div>}
|
|
53
|
-
* {isEmpty && <div>No products match your filters</div>}
|
|
54
|
-
* {products.length > 0 && (
|
|
55
|
-
* <div>
|
|
56
|
-
* <p>Showing {products.length} of {totalProducts} products</p>
|
|
57
|
-
* <div className="filtered-grid">
|
|
58
|
-
* {products.map(product => (
|
|
59
|
-
* <FilteredCollection.Item key={product.id} product={product}>
|
|
60
|
-
* {({ title, image, price, available, slug }) => (
|
|
61
|
-
* <div className={`product-item ${!available ? 'unavailable' : ''}`}>
|
|
62
|
-
* {image && <img src={image} alt={title} />}
|
|
63
|
-
* <h3>{title}</h3>
|
|
64
|
-
* <div className="price">{price}</div>
|
|
65
|
-
* <a href={`/product/${slug}`}>View Details</a>
|
|
66
|
-
* </div>
|
|
67
|
-
* )}
|
|
68
|
-
* </FilteredCollection.Item>
|
|
69
|
-
* ))}
|
|
70
|
-
* </div>
|
|
71
|
-
* {hasMoreProducts && (
|
|
72
|
-
* <FilteredCollection.LoadMore>
|
|
73
|
-
* {({ loadMore, isLoading }) => (
|
|
74
|
-
* <button onClick={loadMore} disabled={isLoading}>
|
|
75
|
-
* {isLoading ? 'Loading...' : 'Load More'}
|
|
76
|
-
* </button>
|
|
77
|
-
* )}
|
|
78
|
-
* </FilteredCollection.LoadMore>
|
|
79
|
-
* )}
|
|
80
|
-
* </div>
|
|
81
|
-
* )}
|
|
82
|
-
* </div>
|
|
83
|
-
* )}
|
|
84
|
-
* </FilteredCollection.Grid>
|
|
85
|
-
* </div>
|
|
86
|
-
* </FilteredCollection.Root>
|
|
87
|
-
* );
|
|
88
|
-
* }
|
|
89
|
-
* ```
|
|
90
|
-
*/
|
|
91
|
-
export function Root(props) {
|
|
92
|
-
return (_jsx(WixServices, { servicesMap: createServicesMap()
|
|
93
|
-
.addService(CatalogServiceDefinition, CatalogService, {})
|
|
94
|
-
.addService(CategoryServiceDefinition, CategoryService, {
|
|
95
|
-
categories: [],
|
|
96
|
-
initialCategoryId: null,
|
|
97
|
-
})
|
|
98
|
-
.addService(SortServiceDefinition, SortService, {})
|
|
99
|
-
.addService(FilterServiceDefinition, FilterService, {})
|
|
100
|
-
.addService(CollectionServiceDefinition, CollectionService, {}), children: props.children }));
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Headless component for displaying a loading state for filters
|
|
104
|
-
*
|
|
105
|
-
* @component
|
|
106
|
-
* @example
|
|
107
|
-
* ```tsx
|
|
108
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
109
|
-
*
|
|
110
|
-
* function FiltersLoadingIndicator() {
|
|
111
|
-
* return (
|
|
112
|
-
* <FilteredCollection.FiltersLoading>
|
|
113
|
-
* {({ isFullyLoaded }) => (
|
|
114
|
-
* <div>
|
|
115
|
-
* {!isFullyLoaded && (
|
|
116
|
-
* <div className="loading-pulse">
|
|
117
|
-
* Loading filters...
|
|
118
|
-
* </div>
|
|
119
|
-
* )}
|
|
120
|
-
* </div>
|
|
121
|
-
* )}
|
|
122
|
-
* </FilteredCollection.FiltersLoading>
|
|
123
|
-
* );
|
|
124
|
-
* }
|
|
125
|
-
* ```
|
|
126
|
-
*/
|
|
127
|
-
export const FiltersLoading = ({ children }) => {
|
|
128
|
-
const filter = useService(FilterServiceDefinition);
|
|
129
|
-
const isFullyLoaded = filter.isFullyLoaded.get();
|
|
130
|
-
return _jsx(_Fragment, { children: children({ isFullyLoaded }) });
|
|
131
|
-
};
|
|
132
|
-
/**
|
|
133
|
-
* Headless component for displaying a grid of filtered products
|
|
134
|
-
*
|
|
135
|
-
* @component
|
|
136
|
-
* @example
|
|
137
|
-
* ```tsx
|
|
138
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
139
|
-
*
|
|
140
|
-
* function FilteredProductsGrid() {
|
|
141
|
-
* return (
|
|
142
|
-
* <FilteredCollection.Grid>
|
|
143
|
-
* {({ products, isLoading, error, isEmpty, totalProducts, hasMoreProducts }) => (
|
|
144
|
-
* <div>
|
|
145
|
-
* {isLoading && <div>Loading filtered products...</div>}
|
|
146
|
-
* {error && <div>Error: {error}</div>}
|
|
147
|
-
* {isEmpty && <div>No products match your filters</div>}
|
|
148
|
-
* {products.length > 0 && (
|
|
149
|
-
* <div>
|
|
150
|
-
* <p>Showing {products.length} of {totalProducts} products</p>
|
|
151
|
-
* <div className="filtered-grid">
|
|
152
|
-
* {products.map(product => (
|
|
153
|
-
* <div key={product.id}>{product.name}</div>
|
|
154
|
-
* ))}
|
|
155
|
-
* </div>
|
|
156
|
-
* {hasMoreProducts && <button>Load More</button>}
|
|
157
|
-
* </div>
|
|
158
|
-
* )}
|
|
159
|
-
* </div>
|
|
160
|
-
* )}
|
|
161
|
-
* </FilteredCollection.Grid>
|
|
162
|
-
* );
|
|
163
|
-
* }
|
|
164
|
-
* ```
|
|
165
|
-
*/
|
|
166
|
-
export const Grid = ({ children }) => {
|
|
167
|
-
const collection = useService(CollectionServiceDefinition);
|
|
168
|
-
const products = collection.products.get() || [];
|
|
169
|
-
const totalProducts = collection.totalProducts.get();
|
|
170
|
-
const isLoading = collection.isLoading.get();
|
|
171
|
-
const error = collection.error.get();
|
|
172
|
-
const hasProducts = collection.hasProducts.get();
|
|
173
|
-
const hasMoreProducts = collection.hasMoreProducts.get();
|
|
174
|
-
return (_jsx(_Fragment, { children: children({
|
|
175
|
-
products,
|
|
176
|
-
isLoading,
|
|
177
|
-
error,
|
|
178
|
-
isEmpty: !hasProducts,
|
|
179
|
-
totalProducts,
|
|
180
|
-
hasMoreProducts,
|
|
181
|
-
}) }));
|
|
182
|
-
};
|
|
183
|
-
/**
|
|
184
|
-
* Headless component for displaying a filtered product item
|
|
185
|
-
*
|
|
186
|
-
* @component
|
|
187
|
-
* @example
|
|
188
|
-
* ```tsx
|
|
189
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
190
|
-
*
|
|
191
|
-
* function FilteredProductItem({ product }) {
|
|
192
|
-
* return (
|
|
193
|
-
* <FilteredCollection.Item product={product}>
|
|
194
|
-
* {({ title, image, price, compareAtPrice, available, slug, description }) => (
|
|
195
|
-
* <div className={`product-item ${!available ? 'unavailable' : ''}`}>
|
|
196
|
-
* {image && <img src={image} alt={title} />}
|
|
197
|
-
* <h3>{title}</h3>
|
|
198
|
-
* {description && <p>{description}</p>}
|
|
199
|
-
* <div className="price">
|
|
200
|
-
* <span className="current">{price}</span>
|
|
201
|
-
* {compareAtPrice && <span className="compare"><s>{compareAtPrice}</s></span>}
|
|
202
|
-
* </div>
|
|
203
|
-
* {!available && <div className="out-of-stock">Out of Stock</div>}
|
|
204
|
-
* <a href={`/product/${slug}`}>View Details</a>
|
|
205
|
-
* </div>
|
|
206
|
-
* )}
|
|
207
|
-
* </FilteredCollection.Item>
|
|
208
|
-
* );
|
|
209
|
-
* }
|
|
210
|
-
* ```
|
|
211
|
-
*/
|
|
212
|
-
export const Item = ({ product, children }) => {
|
|
213
|
-
// Safe conversion of product data with type safety guards
|
|
214
|
-
const title = String(product.name || "");
|
|
215
|
-
const image = product.media?.main?.image || null;
|
|
216
|
-
const imageAltText = product.media?.main?.altText || "";
|
|
217
|
-
const price = product.actualPriceRange?.minValue?.formattedAmount ||
|
|
218
|
-
product.actualPriceRange?.maxValue?.formattedAmount ||
|
|
219
|
-
(product.actualPriceRange?.minValue?.amount
|
|
220
|
-
? `$${product.actualPriceRange.minValue.amount}`
|
|
221
|
-
: "$0.00");
|
|
222
|
-
// Add compare at price
|
|
223
|
-
const compareAtPrice = product.compareAtPriceRange?.minValue?.formattedAmount ||
|
|
224
|
-
(product.compareAtPriceRange?.minValue?.amount
|
|
225
|
-
? `$${product.compareAtPriceRange.minValue.amount}`
|
|
226
|
-
: null);
|
|
227
|
-
const availabilityStatus = product.inventory?.availabilityStatus;
|
|
228
|
-
const available = availabilityStatus === InventoryAvailabilityStatus.IN_STOCK ||
|
|
229
|
-
availabilityStatus === InventoryAvailabilityStatus.PARTIALLY_OUT_OF_STOCK;
|
|
230
|
-
const slug = String(product.slug || product._id || "");
|
|
231
|
-
const description = product.plainDescription
|
|
232
|
-
? String(product.plainDescription)
|
|
233
|
-
: undefined;
|
|
234
|
-
return (_jsx(_Fragment, { children: children({
|
|
235
|
-
title,
|
|
236
|
-
image,
|
|
237
|
-
imageAltText,
|
|
238
|
-
price: String(price),
|
|
239
|
-
compareAtPrice,
|
|
240
|
-
available,
|
|
241
|
-
slug,
|
|
242
|
-
description,
|
|
243
|
-
}) }));
|
|
244
|
-
};
|
|
245
|
-
/**
|
|
246
|
-
* Headless component for load more filtered products functionality
|
|
247
|
-
*
|
|
248
|
-
* @component
|
|
249
|
-
* @example
|
|
250
|
-
* ```tsx
|
|
251
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
252
|
-
*
|
|
253
|
-
* function LoadMoreProducts() {
|
|
254
|
-
* return (
|
|
255
|
-
* <FilteredCollection.LoadMore>
|
|
256
|
-
* {({ loadMore, refresh, isLoading, hasProducts, totalProducts, hasMoreProducts }) => (
|
|
257
|
-
* <div>
|
|
258
|
-
* {hasProducts && (
|
|
259
|
-
* <div>
|
|
260
|
-
* <p>Showing products ({totalProducts} total)</p>
|
|
261
|
-
* {hasMoreProducts && (
|
|
262
|
-
* <button
|
|
263
|
-
* onClick={loadMore}
|
|
264
|
-
* disabled={isLoading}
|
|
265
|
-
* >
|
|
266
|
-
* {isLoading ? 'Loading...' : 'Load More'}
|
|
267
|
-
* </button>
|
|
268
|
-
* )}
|
|
269
|
-
* <button onClick={refresh}>Refresh</button>
|
|
270
|
-
* </div>
|
|
271
|
-
* )}
|
|
272
|
-
* </div>
|
|
273
|
-
* )}
|
|
274
|
-
* </FilteredCollection.LoadMore>
|
|
275
|
-
* );
|
|
276
|
-
* }
|
|
277
|
-
* ```
|
|
278
|
-
*/
|
|
279
|
-
export const LoadMore = ({ children }) => {
|
|
280
|
-
const collection = useService(CollectionServiceDefinition);
|
|
281
|
-
const loadMore = collection.loadMore;
|
|
282
|
-
const refresh = collection.refresh;
|
|
283
|
-
const isLoading = collection.isLoading.get();
|
|
284
|
-
const hasProducts = collection.hasProducts.get();
|
|
285
|
-
const totalProducts = collection.totalProducts.get();
|
|
286
|
-
const hasMoreProducts = collection.hasMoreProducts.get();
|
|
287
|
-
return (_jsx(_Fragment, { children: children({
|
|
288
|
-
loadMore,
|
|
289
|
-
refresh,
|
|
290
|
-
isLoading,
|
|
291
|
-
hasProducts,
|
|
292
|
-
totalProducts,
|
|
293
|
-
hasMoreProducts,
|
|
294
|
-
}) }));
|
|
295
|
-
};
|
|
296
|
-
/**
|
|
297
|
-
* Headless component for product filters with available options
|
|
298
|
-
*
|
|
299
|
-
* @component
|
|
300
|
-
* @example
|
|
301
|
-
* ```tsx
|
|
302
|
-
* import { FilteredCollection } from '@wix/stores/components';
|
|
303
|
-
*
|
|
304
|
-
* function ProductFilters() {
|
|
305
|
-
* return (
|
|
306
|
-
* <FilteredCollection.Filters>
|
|
307
|
-
* {({ applyFilters, clearFilters, currentFilters, availableOptions, isFiltered }) => (
|
|
308
|
-
* <div className="filters">
|
|
309
|
-
* <h3>Filters</h3>
|
|
310
|
-
* <div className="price-filter">
|
|
311
|
-
* <label>Price Range</label>
|
|
312
|
-
* <input
|
|
313
|
-
* type="range"
|
|
314
|
-
* min={availableOptions.priceRange.min}
|
|
315
|
-
* max={availableOptions.priceRange.max}
|
|
316
|
-
* value={currentFilters.priceRange.min}
|
|
317
|
-
* onChange={(e) => applyFilters({
|
|
318
|
-
* ...currentFilters,
|
|
319
|
-
* priceRange: { ...currentFilters.priceRange, min: Number(e.target.value) }
|
|
320
|
-
* })}
|
|
321
|
-
* />
|
|
322
|
-
* </div>
|
|
323
|
-
* {isFiltered && (
|
|
324
|
-
* <button onClick={clearFilters}>Clear All Filters</button>
|
|
325
|
-
* )}
|
|
326
|
-
* </div>
|
|
327
|
-
* )}
|
|
328
|
-
* </FilteredCollection.Filters>
|
|
329
|
-
* );
|
|
330
|
-
* }
|
|
331
|
-
* ```
|
|
332
|
-
*/
|
|
333
|
-
export const Filters = ({ children }) => {
|
|
334
|
-
const collection = useService(CollectionServiceDefinition);
|
|
335
|
-
const filter = useService(FilterServiceDefinition);
|
|
336
|
-
const applyFilters = filter.applyFilters;
|
|
337
|
-
const clearFilters = filter.clearFilters;
|
|
338
|
-
const currentFilters = filter.currentFilters.get();
|
|
339
|
-
const allProducts = collection.products.get();
|
|
340
|
-
const availableOptions = filter.availableOptions.get();
|
|
341
|
-
const isFiltered = currentFilters.priceRange.min !== availableOptions.priceRange.min ||
|
|
342
|
-
currentFilters.priceRange.max !== availableOptions.priceRange.max ||
|
|
343
|
-
Object.keys(currentFilters.selectedOptions).length > 0;
|
|
344
|
-
return (_jsx(_Fragment, { children: children({
|
|
345
|
-
applyFilters,
|
|
346
|
-
clearFilters,
|
|
347
|
-
currentFilters,
|
|
348
|
-
allProducts,
|
|
349
|
-
availableOptions,
|
|
350
|
-
isFiltered,
|
|
351
|
-
}) }));
|
|
352
|
-
};
|