@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.
Files changed (129) hide show
  1. package/cjs/dist/react/Category.d.ts +65 -59
  2. package/cjs/dist/react/Category.js +50 -83
  3. package/cjs/dist/react/CategoryList.d.ts +184 -0
  4. package/cjs/dist/react/CategoryList.js +174 -0
  5. package/cjs/dist/react/Product.d.ts +3 -3
  6. package/cjs/dist/react/Product.js +6 -6
  7. package/cjs/dist/react/ProductActions.d.ts +1 -1
  8. package/cjs/dist/react/ProductActions.js +2 -2
  9. package/{dist/react/ProductsList.d.ts → cjs/dist/react/ProductList.d.ts} +71 -38
  10. package/cjs/dist/react/{ProductsList.js → ProductList.js} +30 -26
  11. package/cjs/dist/react/ProductListFilters.d.ts +244 -0
  12. package/cjs/dist/react/ProductListFilters.js +216 -0
  13. package/cjs/dist/react/ProductListPagination.d.ts +246 -0
  14. package/cjs/dist/react/ProductListPagination.js +207 -0
  15. package/cjs/dist/react/ProductListSort.d.ts +87 -0
  16. package/cjs/dist/react/ProductListSort.js +85 -0
  17. package/cjs/dist/react/ProductModifiers.d.ts +5 -5
  18. package/cjs/dist/react/ProductModifiers.js +10 -10
  19. package/cjs/dist/react/ProductVariantSelector.d.ts +5 -5
  20. package/cjs/dist/react/ProductVariantSelector.js +13 -10
  21. package/cjs/dist/react/SelectedVariant.d.ts +3 -3
  22. package/cjs/dist/react/SelectedVariant.js +6 -6
  23. package/cjs/dist/react/index.d.ts +7 -9
  24. package/cjs/dist/react/index.js +7 -9
  25. package/cjs/dist/services/buy-now-service.d.ts +208 -0
  26. package/cjs/dist/services/buy-now-service.js +132 -1
  27. package/cjs/dist/services/categories-list-service.d.ts +163 -0
  28. package/cjs/dist/services/categories-list-service.js +148 -0
  29. package/cjs/dist/services/category-service.d.ts +115 -70
  30. package/cjs/dist/services/category-service.js +101 -110
  31. package/cjs/dist/services/index.d.ts +6 -7
  32. package/cjs/dist/services/index.js +5 -16
  33. package/cjs/dist/services/pay-now-service.d.ts +146 -0
  34. package/cjs/dist/services/pay-now-service.js +112 -1
  35. package/cjs/dist/services/product-service.d.ts +71 -0
  36. package/cjs/dist/services/product-service.js +47 -0
  37. package/cjs/dist/services/products-list-filters-service.d.ts +292 -0
  38. package/cjs/dist/services/products-list-filters-service.js +446 -0
  39. package/cjs/dist/services/products-list-pagination-service.d.ts +186 -0
  40. package/cjs/dist/services/products-list-pagination-service.js +179 -0
  41. package/cjs/dist/services/products-list-service.d.ts +138 -52
  42. package/cjs/dist/services/products-list-service.js +98 -51
  43. package/cjs/dist/services/products-list-sort-service.d.ts +117 -0
  44. package/cjs/dist/services/products-list-sort-service.js +144 -0
  45. package/cjs/dist/utils/url-params.d.ts +68 -0
  46. package/cjs/dist/utils/url-params.js +72 -4
  47. package/dist/react/Category.d.ts +65 -59
  48. package/dist/react/Category.js +50 -83
  49. package/dist/react/CategoryList.d.ts +184 -0
  50. package/dist/react/CategoryList.js +174 -0
  51. package/dist/react/Product.d.ts +3 -3
  52. package/dist/react/Product.js +6 -6
  53. package/dist/react/ProductActions.d.ts +1 -1
  54. package/dist/react/ProductActions.js +2 -2
  55. package/{cjs/dist/react/ProductsList.d.ts → dist/react/ProductList.d.ts} +71 -38
  56. package/dist/react/{ProductsList.js → ProductList.js} +30 -26
  57. package/dist/react/ProductListFilters.d.ts +244 -0
  58. package/dist/react/ProductListFilters.js +216 -0
  59. package/dist/react/ProductListPagination.d.ts +246 -0
  60. package/dist/react/ProductListPagination.js +207 -0
  61. package/dist/react/ProductListSort.d.ts +87 -0
  62. package/dist/react/ProductListSort.js +85 -0
  63. package/dist/react/ProductModifiers.d.ts +5 -5
  64. package/dist/react/ProductModifiers.js +10 -10
  65. package/dist/react/ProductVariantSelector.d.ts +5 -5
  66. package/dist/react/ProductVariantSelector.js +13 -10
  67. package/dist/react/SelectedVariant.d.ts +3 -3
  68. package/dist/react/SelectedVariant.js +6 -6
  69. package/dist/react/index.d.ts +7 -9
  70. package/dist/react/index.js +7 -9
  71. package/dist/services/buy-now-service.d.ts +208 -0
  72. package/dist/services/buy-now-service.js +132 -1
  73. package/dist/services/categories-list-service.d.ts +163 -0
  74. package/dist/services/categories-list-service.js +148 -0
  75. package/dist/services/category-service.d.ts +115 -70
  76. package/dist/services/category-service.js +101 -110
  77. package/dist/services/index.d.ts +6 -7
  78. package/dist/services/index.js +5 -16
  79. package/dist/services/pay-now-service.d.ts +146 -0
  80. package/dist/services/pay-now-service.js +112 -1
  81. package/dist/services/product-service.d.ts +71 -0
  82. package/dist/services/product-service.js +47 -0
  83. package/dist/services/products-list-filters-service.d.ts +292 -0
  84. package/dist/services/products-list-filters-service.js +446 -0
  85. package/dist/services/products-list-pagination-service.d.ts +186 -0
  86. package/dist/services/products-list-pagination-service.js +179 -0
  87. package/dist/services/products-list-service.d.ts +138 -52
  88. package/dist/services/products-list-service.js +98 -51
  89. package/dist/services/products-list-sort-service.d.ts +117 -0
  90. package/dist/services/products-list-sort-service.js +144 -0
  91. package/dist/utils/url-params.d.ts +68 -0
  92. package/dist/utils/url-params.js +72 -4
  93. package/package.json +3 -3
  94. package/cjs/dist/react/Collection.d.ts +0 -294
  95. package/cjs/dist/react/Collection.js +0 -345
  96. package/cjs/dist/react/FilteredCollection.d.ts +0 -299
  97. package/cjs/dist/react/FilteredCollection.js +0 -352
  98. package/cjs/dist/react/RelatedProducts.d.ts +0 -169
  99. package/cjs/dist/react/RelatedProducts.js +0 -180
  100. package/cjs/dist/react/Sort.d.ts +0 -37
  101. package/cjs/dist/react/Sort.js +0 -36
  102. package/cjs/dist/services/catalog-service.d.ts +0 -36
  103. package/cjs/dist/services/catalog-service.js +0 -193
  104. package/cjs/dist/services/collection-service.d.ts +0 -124
  105. package/cjs/dist/services/collection-service.js +0 -628
  106. package/cjs/dist/services/filter-service.d.ts +0 -35
  107. package/cjs/dist/services/filter-service.js +0 -119
  108. package/cjs/dist/services/related-products-service.d.ts +0 -100
  109. package/cjs/dist/services/related-products-service.js +0 -127
  110. package/cjs/dist/services/sort-service.d.ts +0 -20
  111. package/cjs/dist/services/sort-service.js +0 -27
  112. package/dist/react/Collection.d.ts +0 -294
  113. package/dist/react/Collection.js +0 -345
  114. package/dist/react/FilteredCollection.d.ts +0 -299
  115. package/dist/react/FilteredCollection.js +0 -352
  116. package/dist/react/RelatedProducts.d.ts +0 -169
  117. package/dist/react/RelatedProducts.js +0 -180
  118. package/dist/react/Sort.d.ts +0 -37
  119. package/dist/react/Sort.js +0 -36
  120. package/dist/services/catalog-service.d.ts +0 -36
  121. package/dist/services/catalog-service.js +0 -193
  122. package/dist/services/collection-service.d.ts +0 -124
  123. package/dist/services/collection-service.js +0 -628
  124. package/dist/services/filter-service.d.ts +0 -35
  125. package/dist/services/filter-service.js +0 -119
  126. package/dist/services/related-products-service.d.ts +0 -100
  127. package/dist/services/related-products-service.js +0 -127
  128. package/dist/services/sort-service.d.ts +0 -20
  129. 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
- };