@wix/headless-stores 0.0.0
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/astro/actions/package.json +4 -0
- package/cjs/dist/astro/actions/custom-checkout.d.ts +50 -0
- package/cjs/dist/astro/actions/custom-checkout.js +53 -0
- package/cjs/dist/astro/actions/index.d.ts +1 -0
- package/cjs/dist/astro/actions/index.js +1 -0
- package/cjs/dist/data-component-tags.d.ts +8 -0
- package/cjs/dist/data-component-tags.js +9 -0
- package/cjs/dist/enums/index.d.ts +2 -0
- package/cjs/dist/enums/index.js +2 -0
- package/cjs/dist/enums/social-platform-enums.d.ts +25 -0
- package/cjs/dist/enums/social-platform-enums.js +27 -0
- package/cjs/dist/enums/sort-enums.d.ts +17 -0
- package/cjs/dist/enums/sort-enums.js +18 -0
- package/cjs/dist/react/Category.d.ts +242 -0
- package/cjs/dist/react/Category.js +235 -0
- package/cjs/dist/react/CategoryList.d.ts +107 -0
- package/cjs/dist/react/CategoryList.js +91 -0
- package/cjs/dist/react/Choice.d.ts +211 -0
- package/cjs/dist/react/Choice.js +213 -0
- package/cjs/dist/react/Option.d.ts +242 -0
- package/cjs/dist/react/Option.js +346 -0
- package/cjs/dist/react/Product.d.ts +1065 -0
- package/cjs/dist/react/Product.js +1157 -0
- package/cjs/dist/react/ProductList.d.ts +400 -0
- package/cjs/dist/react/ProductList.js +368 -0
- package/cjs/dist/react/core/CategoryList.d.ts +194 -0
- package/cjs/dist/react/core/CategoryList.js +180 -0
- package/cjs/dist/react/core/Product.d.ts +225 -0
- package/cjs/dist/react/core/Product.js +190 -0
- package/cjs/dist/react/core/ProductList.d.ts +235 -0
- package/cjs/dist/react/core/ProductList.js +217 -0
- package/cjs/dist/react/core/ProductListFilters.d.ts +138 -0
- package/cjs/dist/react/core/ProductListFilters.js +242 -0
- package/cjs/dist/react/core/ProductListPagination.d.ts +49 -0
- package/cjs/dist/react/core/ProductListPagination.js +41 -0
- package/cjs/dist/react/core/ProductListSort.d.ts +19 -0
- package/cjs/dist/react/core/ProductListSort.js +52 -0
- package/cjs/dist/react/core/ProductModifiers.d.ts +416 -0
- package/cjs/dist/react/core/ProductModifiers.js +413 -0
- package/cjs/dist/react/core/ProductVariantSelector.d.ts +313 -0
- package/cjs/dist/react/core/ProductVariantSelector.js +291 -0
- package/cjs/dist/react/core/SelectedVariant.d.ts +230 -0
- package/cjs/dist/react/core/SelectedVariant.js +269 -0
- package/cjs/dist/react/index.d.ts +6 -0
- package/cjs/dist/react/index.js +6 -0
- package/cjs/dist/react/types.d.ts +8 -0
- package/cjs/dist/react/types.js +9 -0
- package/cjs/dist/server-actions/custom-checkout-action.d.ts +49 -0
- package/cjs/dist/server-actions/custom-checkout-action.js +64 -0
- package/cjs/dist/server-actions/index.d.ts +1 -0
- package/cjs/dist/server-actions/index.js +1 -0
- package/cjs/dist/services/buy-now-service.d.ts +346 -0
- package/cjs/dist/services/buy-now-service.js +197 -0
- package/cjs/dist/services/categories-list-service.d.ts +164 -0
- package/cjs/dist/services/categories-list-service.js +148 -0
- package/cjs/dist/services/index.d.ts +5 -0
- package/cjs/dist/services/index.js +5 -0
- package/cjs/dist/services/pay-now-service.d.ts +214 -0
- package/cjs/dist/services/pay-now-service.js +156 -0
- package/cjs/dist/services/product-modifiers-service.d.ts +34 -0
- package/cjs/dist/services/product-modifiers-service.js +107 -0
- package/cjs/dist/services/product-service.d.ts +177 -0
- package/cjs/dist/services/product-service.js +190 -0
- package/cjs/dist/services/products-list-search-service.d.ts +1 -0
- package/cjs/dist/services/products-list-search-service.js +1 -0
- package/cjs/dist/services/products-list-service.d.ts +429 -0
- package/cjs/dist/services/products-list-service.js +893 -0
- package/cjs/dist/services/selected-variant-service.d.ts +66 -0
- package/cjs/dist/services/selected-variant-service.js +527 -0
- package/cjs/dist/utils/index.d.ts +1 -0
- package/cjs/dist/utils/index.js +30 -0
- package/cjs/dist/utils/url-params.d.ts +73 -0
- package/cjs/dist/utils/url-params.js +114 -0
- package/cjs/package.json +3 -0
- package/dist/astro/actions/custom-checkout.d.ts +50 -0
- package/dist/astro/actions/custom-checkout.js +53 -0
- package/dist/astro/actions/index.d.ts +1 -0
- package/dist/astro/actions/index.js +1 -0
- package/dist/data-component-tags.d.ts +8 -0
- package/dist/data-component-tags.js +9 -0
- package/dist/enums/index.d.ts +2 -0
- package/dist/enums/index.js +2 -0
- package/dist/enums/social-platform-enums.d.ts +25 -0
- package/dist/enums/social-platform-enums.js +27 -0
- package/dist/enums/sort-enums.d.ts +17 -0
- package/dist/enums/sort-enums.js +18 -0
- package/dist/react/Category.d.ts +242 -0
- package/dist/react/Category.js +235 -0
- package/dist/react/CategoryList.d.ts +107 -0
- package/dist/react/CategoryList.js +91 -0
- package/dist/react/Choice.d.ts +211 -0
- package/dist/react/Choice.js +213 -0
- package/dist/react/Option.d.ts +242 -0
- package/dist/react/Option.js +346 -0
- package/dist/react/Product.d.ts +1065 -0
- package/dist/react/Product.js +1157 -0
- package/dist/react/ProductList.d.ts +400 -0
- package/dist/react/ProductList.js +368 -0
- package/dist/react/core/CategoryList.d.ts +194 -0
- package/dist/react/core/CategoryList.js +180 -0
- package/dist/react/core/Product.d.ts +225 -0
- package/dist/react/core/Product.js +190 -0
- package/dist/react/core/ProductList.d.ts +235 -0
- package/dist/react/core/ProductList.js +217 -0
- package/dist/react/core/ProductListFilters.d.ts +138 -0
- package/dist/react/core/ProductListFilters.js +242 -0
- package/dist/react/core/ProductListPagination.d.ts +49 -0
- package/dist/react/core/ProductListPagination.js +41 -0
- package/dist/react/core/ProductListSort.d.ts +19 -0
- package/dist/react/core/ProductListSort.js +52 -0
- package/dist/react/core/ProductModifiers.d.ts +416 -0
- package/dist/react/core/ProductModifiers.js +413 -0
- package/dist/react/core/ProductVariantSelector.d.ts +313 -0
- package/dist/react/core/ProductVariantSelector.js +291 -0
- package/dist/react/core/SelectedVariant.d.ts +230 -0
- package/dist/react/core/SelectedVariant.js +269 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.js +6 -0
- package/dist/react/types.d.ts +8 -0
- package/dist/react/types.js +9 -0
- package/dist/server-actions/custom-checkout-action.d.ts +49 -0
- package/dist/server-actions/custom-checkout-action.js +64 -0
- package/dist/server-actions/index.d.ts +1 -0
- package/dist/server-actions/index.js +1 -0
- package/dist/services/buy-now-service.d.ts +346 -0
- package/dist/services/buy-now-service.js +197 -0
- package/dist/services/categories-list-service.d.ts +164 -0
- package/dist/services/categories-list-service.js +148 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.js +5 -0
- package/dist/services/pay-now-service.d.ts +214 -0
- package/dist/services/pay-now-service.js +156 -0
- package/dist/services/product-modifiers-service.d.ts +34 -0
- package/dist/services/product-modifiers-service.js +107 -0
- package/dist/services/product-service.d.ts +177 -0
- package/dist/services/product-service.js +190 -0
- package/dist/services/products-list-search-service.d.ts +0 -0
- package/dist/services/products-list-search-service.js +1 -0
- package/dist/services/products-list-service.d.ts +429 -0
- package/dist/services/products-list-service.js +893 -0
- package/dist/services/selected-variant-service.d.ts +66 -0
- package/dist/services/selected-variant-service.js +527 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +30 -0
- package/dist/utils/url-params.d.ts +73 -0
- package/dist/utils/url-params.js +114 -0
- package/package.json +89 -0
- package/react/package.json +4 -0
- package/server-actions/package.json +4 -0
- package/services/package.json +4 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useService } from '@wix/services-manager-react';
|
|
3
|
+
import { ProductsListServiceDefinition, InventoryStatusType, CategoriesListServiceDefinition, } from '../../services/index.js';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
import { Filter as FilterPrimitive, } from '@wix/headless-components/react';
|
|
6
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
7
|
+
import React from 'react';
|
|
8
|
+
// Conversion utilities for platform compatibility
|
|
9
|
+
function getInventoryStatusLabel(status) {
|
|
10
|
+
switch (status) {
|
|
11
|
+
case InventoryStatusType.IN_STOCK:
|
|
12
|
+
return 'In Stock';
|
|
13
|
+
case InventoryStatusType.OUT_OF_STOCK:
|
|
14
|
+
return 'Out of Stock';
|
|
15
|
+
case InventoryStatusType.PARTIALLY_OUT_OF_STOCK:
|
|
16
|
+
return 'Limited Stock';
|
|
17
|
+
default:
|
|
18
|
+
return String(status);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function buildSearchFilterData(availableOptions, availableInventoryStatuses, availableMinPrice, availableMaxPrice) {
|
|
22
|
+
// Build consolidated filter options using search field names
|
|
23
|
+
const filterOptions = [
|
|
24
|
+
// Price range - use a logical key that maps to both min/max fields
|
|
25
|
+
{
|
|
26
|
+
key: 'priceRange',
|
|
27
|
+
label: 'Price Range',
|
|
28
|
+
type: 'range',
|
|
29
|
+
displayType: 'range',
|
|
30
|
+
validValues: [availableMinPrice, availableMaxPrice],
|
|
31
|
+
valueFormatter: (value) => `$${value}`,
|
|
32
|
+
fieldName: [
|
|
33
|
+
'actualPriceRange.minValue.amount',
|
|
34
|
+
'actualPriceRange.maxValue.amount',
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
// Product options (colors, sizes, etc.) - individual filters for each option type
|
|
38
|
+
...availableOptions.map((option) => ({
|
|
39
|
+
key: option.id,
|
|
40
|
+
label: String(option.name),
|
|
41
|
+
type: 'multi',
|
|
42
|
+
displayType: option.optionRenderType === 'SWATCH_CHOICES'
|
|
43
|
+
? 'color'
|
|
44
|
+
: 'text',
|
|
45
|
+
fieldName: 'options.choicesSettings.choices.choiceId',
|
|
46
|
+
fieldType: 'array',
|
|
47
|
+
validValues: option.choices.map((choice) => choice.id),
|
|
48
|
+
valueFormatter: (value) => {
|
|
49
|
+
const choice = option.choices.find((c) => c.id === value);
|
|
50
|
+
const name = choice?.name || String(value);
|
|
51
|
+
return option.optionRenderType === 'SWATCH_CHOICES'
|
|
52
|
+
? name.toLowerCase()
|
|
53
|
+
: name;
|
|
54
|
+
},
|
|
55
|
+
valueBgColorFormatter: (value) => {
|
|
56
|
+
const choice = option.choices.find((c) => c.id === value);
|
|
57
|
+
return choice?.colorCode || null;
|
|
58
|
+
},
|
|
59
|
+
})),
|
|
60
|
+
// Inventory status - use actual search field name
|
|
61
|
+
{
|
|
62
|
+
key: 'inventory.availabilityStatus',
|
|
63
|
+
label: 'Availability',
|
|
64
|
+
type: 'multi',
|
|
65
|
+
displayType: 'text',
|
|
66
|
+
fieldName: 'inventory.availabilityStatus',
|
|
67
|
+
fieldType: 'singular',
|
|
68
|
+
validValues: availableInventoryStatuses,
|
|
69
|
+
valueFormatter: (value) => getInventoryStatusLabel(value),
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
return { filterOptions };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Headless component for resetting all filters
|
|
76
|
+
*
|
|
77
|
+
* @component
|
|
78
|
+
* @example
|
|
79
|
+
* ```tsx
|
|
80
|
+
* import { ProductList, ProductListFilters } from '@wix/stores/components';
|
|
81
|
+
*
|
|
82
|
+
* function ResetFiltersButton() {
|
|
83
|
+
* return (
|
|
84
|
+
* <ProductList.Root
|
|
85
|
+
* productsListConfig={{ products: [], searchOptions: {}, pagingMetadata: {}, aggregations: {} }}
|
|
86
|
+
* productsListSearchConfig={{ customizations: [] }}
|
|
87
|
+
* >
|
|
88
|
+
* <ProductListFilters.ResetTrigger>
|
|
89
|
+
* {({ resetFilters, isFiltered }) => (
|
|
90
|
+
* <button
|
|
91
|
+
* onClick={resetFilters}
|
|
92
|
+
* disabled={!isFiltered}
|
|
93
|
+
* className={isFiltered ? 'active' : 'disabled'}
|
|
94
|
+
* >
|
|
95
|
+
* {isFiltered ? 'Clear Filters' : 'No Filters Applied'}
|
|
96
|
+
* </button>
|
|
97
|
+
* )}
|
|
98
|
+
* </ProductListFilters.ResetTrigger>
|
|
99
|
+
* </ProductList.Root>
|
|
100
|
+
* );
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export function ResetTrigger(props) {
|
|
105
|
+
const service = useService(ProductsListServiceDefinition);
|
|
106
|
+
const resetFilters = service.resetFilter;
|
|
107
|
+
const isFiltered = service.isFiltered().get();
|
|
108
|
+
return typeof props.children === 'function'
|
|
109
|
+
? props.children({ resetFilters, isFiltered })
|
|
110
|
+
: props.children;
|
|
111
|
+
}
|
|
112
|
+
export function CategoryFilter(props) {
|
|
113
|
+
const categoriesService = useService(CategoriesListServiceDefinition);
|
|
114
|
+
const productListService = useService(ProductsListServiceDefinition);
|
|
115
|
+
const categories = categoriesService.categories.get();
|
|
116
|
+
const setSelectedCategory = (category) => {
|
|
117
|
+
const currentFilter = productListService.searchOptions.get().filter || {};
|
|
118
|
+
if (!category) {
|
|
119
|
+
delete currentFilter['allCategoriesInfo.categories'];
|
|
120
|
+
productListService.setFilter(currentFilter);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
productListService.setFilter({
|
|
124
|
+
...currentFilter,
|
|
125
|
+
'allCategoriesInfo.categories': {
|
|
126
|
+
$matchItems: [{ id: { $in: [category._id] } }],
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
const selectedCategoryId = productListService.searchOptions.get().filter['allCategoriesInfo.categories']?.$matchItems?.[0]?.id
|
|
131
|
+
?.$in?.[0];
|
|
132
|
+
const selectedCategory = categories?.find((c) => c._id === selectedCategoryId) || null;
|
|
133
|
+
return typeof props.children === 'function'
|
|
134
|
+
? props.children({ selectedCategory, setSelectedCategory })
|
|
135
|
+
: props.children;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Internal component that provides filter data for the Filter component.
|
|
139
|
+
* Consolidates data from both search and list services.
|
|
140
|
+
*/
|
|
141
|
+
function AllFilters(props) {
|
|
142
|
+
const listService = useService(ProductsListServiceDefinition);
|
|
143
|
+
// Get current filter state
|
|
144
|
+
const currentSearchOptions = listService.searchOptions.get();
|
|
145
|
+
const currentFilter = currentSearchOptions.filter;
|
|
146
|
+
// Get available filter data
|
|
147
|
+
const availableOptions = listService.availableProductOptions.get();
|
|
148
|
+
const availableInventoryStatuses = listService.availableInventoryStatuses.get();
|
|
149
|
+
const availableMinPrice = listService.minPrice.get();
|
|
150
|
+
const availableMaxPrice = listService.maxPrice.get();
|
|
151
|
+
// Get filter state
|
|
152
|
+
const resetFilters = listService.resetFilter;
|
|
153
|
+
const isFiltered = listService.isFiltered().get();
|
|
154
|
+
// Build filter options and handlers
|
|
155
|
+
const searchFilterData = useMemo(() => {
|
|
156
|
+
const { filterOptions } = buildSearchFilterData(availableOptions, availableInventoryStatuses, availableMinPrice, availableMaxPrice);
|
|
157
|
+
const updateFilter = (newFilter) => {
|
|
158
|
+
listService.setFilter(newFilter);
|
|
159
|
+
};
|
|
160
|
+
return {
|
|
161
|
+
filterValue: currentFilter,
|
|
162
|
+
filterOptions,
|
|
163
|
+
updateFilter,
|
|
164
|
+
clearFilters: resetFilters,
|
|
165
|
+
hasFilters: isFiltered,
|
|
166
|
+
};
|
|
167
|
+
}, [
|
|
168
|
+
availableOptions,
|
|
169
|
+
availableInventoryStatuses,
|
|
170
|
+
availableMinPrice,
|
|
171
|
+
availableMaxPrice,
|
|
172
|
+
currentFilter,
|
|
173
|
+
resetFilters,
|
|
174
|
+
isFiltered,
|
|
175
|
+
listService,
|
|
176
|
+
]);
|
|
177
|
+
return typeof props.children === 'function'
|
|
178
|
+
? props.children({ searchFilter: searchFilterData })
|
|
179
|
+
: props.children;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Filter component that provides comprehensive filtering functionality for product lists.
|
|
183
|
+
*
|
|
184
|
+
* This component acts as a provider that integrates with the ProductList service to offer
|
|
185
|
+
* predefined filter options including:
|
|
186
|
+
* - **Price Range**: Min/max price filtering with currency formatting
|
|
187
|
+
* - **Product Options**: Dynamic filters for colors, sizes, and other product variants
|
|
188
|
+
* - **Inventory Status**: Filter by availability (In Stock, Out of Stock, Limited Stock)
|
|
189
|
+
*
|
|
190
|
+
* The component automatically extracts available filter options from the current product set
|
|
191
|
+
* and provides them to child Filter primitive components for rendering.
|
|
192
|
+
*
|
|
193
|
+
* @component
|
|
194
|
+
* @example
|
|
195
|
+
* ```tsx
|
|
196
|
+
* // Basic usage with styled filter components
|
|
197
|
+
* <ProductList.Filter>
|
|
198
|
+
* <Filter.FilterOptions>
|
|
199
|
+
* <Filter.FilterOptionRepeater>
|
|
200
|
+
* <Filter.FilterOption.Label />
|
|
201
|
+
* <Filter.FilterOption.MultiFilter />
|
|
202
|
+
* <Filter.FilterOption.RangeFilter />
|
|
203
|
+
* </Filter.FilterOptionRepeater>
|
|
204
|
+
* </Filter.FilterOptions>
|
|
205
|
+
* </ProductList.Filter>
|
|
206
|
+
*
|
|
207
|
+
* // With custom container using asChild
|
|
208
|
+
* <ProductList.Filter asChild>
|
|
209
|
+
* <aside className="filter-sidebar">
|
|
210
|
+
* <Filter.FilterOptions>
|
|
211
|
+
* <Filter.FilterOptionRepeater>
|
|
212
|
+
* <Filter.FilterOption.Label />
|
|
213
|
+
* <Filter.FilterOption.MultiFilter />
|
|
214
|
+
* </Filter.FilterOptionRepeater>
|
|
215
|
+
* </Filter.FilterOptions>
|
|
216
|
+
* </aside>
|
|
217
|
+
* </ProductList.Filter>
|
|
218
|
+
*
|
|
219
|
+
* // With reset functionality
|
|
220
|
+
* <ProductList.Filter className="filters-container">
|
|
221
|
+
* <Filter.Action.Clear label="Clear All" />
|
|
222
|
+
* <Filter.FilterOptions>
|
|
223
|
+
* <Filter.FilterOptionRepeater>
|
|
224
|
+
* <Filter.FilterOption.Label />
|
|
225
|
+
* <Filter.FilterOption.MultiFilter />
|
|
226
|
+
* <Filter.FilterOption.RangeFilter />
|
|
227
|
+
* </Filter.FilterOptionRepeater>
|
|
228
|
+
* </Filter.FilterOptions>
|
|
229
|
+
* </ProductList.Filter>
|
|
230
|
+
* ```
|
|
231
|
+
*
|
|
232
|
+
* @see {@link AllFilters} for the underlying filter data logic
|
|
233
|
+
* @see {@link FilterPrimitive.Root} for the primitive filter component
|
|
234
|
+
* @see {@link ResetTrigger} for filter reset functionality
|
|
235
|
+
*/
|
|
236
|
+
export const FilterRoot = React.forwardRef(({ children, className, asChild }, ref) => {
|
|
237
|
+
const Comp = asChild ? Slot : 'div';
|
|
238
|
+
return (_jsx(AllFilters, { children: ({ searchFilter }) => {
|
|
239
|
+
return (_jsx(FilterPrimitive.Root, { value: searchFilter.filterValue, onChange: searchFilter.updateFilter, filterOptions: searchFilter.filterOptions, children: _jsx(Comp, { className: className, ref: ref, children: children }) }));
|
|
240
|
+
} }));
|
|
241
|
+
});
|
|
242
|
+
FilterRoot.displayName = 'ProductList.Filter';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Props for LoadMoreTrigger headless component
|
|
3
|
+
*/
|
|
4
|
+
export interface LoadMoreTriggerProps {
|
|
5
|
+
/** Content to display (can be a render function receiving load more controls or ReactNode) */
|
|
6
|
+
children: ((props: LoadMoreTriggerRenderProps) => React.ReactNode) | React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Render props for LoadMoreTrigger component
|
|
10
|
+
*/
|
|
11
|
+
export interface LoadMoreTriggerRenderProps {
|
|
12
|
+
/** Function to load more products */
|
|
13
|
+
loadMore: (count: number) => void;
|
|
14
|
+
/** Whether there are more products to load */
|
|
15
|
+
hasMoreProducts: boolean;
|
|
16
|
+
/** Whether products are currently loading */
|
|
17
|
+
isLoading: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Headless component for loading more products (infinite scroll pattern)
|
|
21
|
+
*
|
|
22
|
+
* @component
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { ProductList, ProductListPagination } from '@wix/stores/components';
|
|
26
|
+
*
|
|
27
|
+
* function LoadMoreButton() {
|
|
28
|
+
* return (
|
|
29
|
+
* <ProductList.Root
|
|
30
|
+
* productsListConfig={{ products: [], searchOptions: {}, pagingMetadata: {}, aggregations: {} }}
|
|
31
|
+
* productsListSearchConfig={{ customizations: [] }}
|
|
32
|
+
* >
|
|
33
|
+
* <ProductListPagination.LoadMoreTrigger>
|
|
34
|
+
* {({ loadMore, hasMoreProducts, isLoading }) => (
|
|
35
|
+
* <button
|
|
36
|
+
* onClick={() => loadMore(10)}
|
|
37
|
+
* disabled={!hasMoreProducts || isLoading}
|
|
38
|
+
* className="load-more-btn"
|
|
39
|
+
* >
|
|
40
|
+
* {isLoading ? 'Loading...' : hasMoreProducts ? 'Load More' : 'No More Products'}
|
|
41
|
+
* </button>
|
|
42
|
+
* )}
|
|
43
|
+
* </ProductListPagination.LoadMoreTrigger>
|
|
44
|
+
* </ProductList.Root>
|
|
45
|
+
* );
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function LoadMoreTrigger(props: LoadMoreTriggerProps): import("react").ReactNode;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useService } from '@wix/services-manager-react';
|
|
2
|
+
import { ProductsListServiceDefinition } from '../../services/products-list-service.js';
|
|
3
|
+
/**
|
|
4
|
+
* Headless component for loading more products (infinite scroll pattern)
|
|
5
|
+
*
|
|
6
|
+
* @component
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { ProductList, ProductListPagination } from '@wix/stores/components';
|
|
10
|
+
*
|
|
11
|
+
* function LoadMoreButton() {
|
|
12
|
+
* return (
|
|
13
|
+
* <ProductList.Root
|
|
14
|
+
* productsListConfig={{ products: [], searchOptions: {}, pagingMetadata: {}, aggregations: {} }}
|
|
15
|
+
* productsListSearchConfig={{ customizations: [] }}
|
|
16
|
+
* >
|
|
17
|
+
* <ProductListPagination.LoadMoreTrigger>
|
|
18
|
+
* {({ loadMore, hasMoreProducts, isLoading }) => (
|
|
19
|
+
* <button
|
|
20
|
+
* onClick={() => loadMore(10)}
|
|
21
|
+
* disabled={!hasMoreProducts || isLoading}
|
|
22
|
+
* className="load-more-btn"
|
|
23
|
+
* >
|
|
24
|
+
* {isLoading ? 'Loading...' : hasMoreProducts ? 'Load More' : 'No More Products'}
|
|
25
|
+
* </button>
|
|
26
|
+
* )}
|
|
27
|
+
* </ProductListPagination.LoadMoreTrigger>
|
|
28
|
+
* </ProductList.Root>
|
|
29
|
+
* );
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function LoadMoreTrigger(props) {
|
|
34
|
+
const productsListService = useService(ProductsListServiceDefinition);
|
|
35
|
+
const loadMore = productsListService.loadMore;
|
|
36
|
+
const hasMoreProducts = productsListService.hasMoreProducts.get();
|
|
37
|
+
const isLoading = productsListService.isLoading.get();
|
|
38
|
+
return typeof props.children === 'function'
|
|
39
|
+
? props.children({ loadMore, hasMoreProducts, isLoading })
|
|
40
|
+
: props.children;
|
|
41
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Sort as SortPrimitive } from '@wix/headless-components/react';
|
|
2
|
+
import { productsV3 } from '@wix/stores';
|
|
3
|
+
export interface ProductListSortProps {
|
|
4
|
+
children: (props: {
|
|
5
|
+
currentSort: productsV3.V3ProductSearch['sort'];
|
|
6
|
+
sortOptions: SortPrimitive.SortOption[];
|
|
7
|
+
setSort: (sort: productsV3.V3ProductSearch['sort']) => void;
|
|
8
|
+
}) => React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export declare const ProductListSort: (props: ProductListSortProps) => import("react").ReactNode;
|
|
11
|
+
export interface ProductListSeperateSortProps {
|
|
12
|
+
children: (props: {
|
|
13
|
+
currentSort: productsV3.V3ProductSearch['sort'];
|
|
14
|
+
sortFieldOptions: SortPrimitive.SortOption[];
|
|
15
|
+
sortOrderOptions: SortPrimitive.SortOption[];
|
|
16
|
+
setSort: (sort: productsV3.V3ProductSearch['sort']) => void;
|
|
17
|
+
}) => React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
export declare function ProductListSeperateSort(props: ProductListSeperateSortProps): import("react").ReactNode;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useService } from '@wix/services-manager-react';
|
|
2
|
+
import { ProductsListServiceDefinition } from '../../services/products-list-service.js';
|
|
3
|
+
export const ProductListSort = (props) => {
|
|
4
|
+
const productListService = useService(ProductsListServiceDefinition);
|
|
5
|
+
const currentSort = productListService.searchOptions.get().sort;
|
|
6
|
+
// Define sort options - primitive handles all conversion logic
|
|
7
|
+
const sortOptions = [
|
|
8
|
+
{ fieldName: 'name', order: 'ASC', label: 'Name (A-Z)' },
|
|
9
|
+
{ fieldName: 'name', order: 'DESC', label: 'Name (Z-A)' },
|
|
10
|
+
{
|
|
11
|
+
fieldName: 'actualPriceRange.minValue.amount',
|
|
12
|
+
order: 'ASC',
|
|
13
|
+
label: 'Price: Low to High',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
fieldName: 'actualPriceRange.minValue.amount',
|
|
17
|
+
order: 'DESC',
|
|
18
|
+
label: 'Price: High to Low',
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
return props.children({
|
|
22
|
+
currentSort,
|
|
23
|
+
sortOptions,
|
|
24
|
+
setSort: (sort) => {
|
|
25
|
+
productListService.setSort(sort);
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
export function ProductListSeperateSort(props) {
|
|
30
|
+
const productListService = useService(ProductsListServiceDefinition);
|
|
31
|
+
const currentSort = productListService.searchOptions.get().sort;
|
|
32
|
+
// Define sort options - primitive handles all conversion logic
|
|
33
|
+
const sortFieldOptions = [
|
|
34
|
+
{ fieldName: 'name', label: 'Name' },
|
|
35
|
+
{
|
|
36
|
+
fieldName: 'actualPriceRange.minValue.amount',
|
|
37
|
+
label: 'Price',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
const sortOrderOptions = [
|
|
41
|
+
{ order: 'ASC', label: 'Ascending' },
|
|
42
|
+
{ order: 'DESC', label: 'Descending' },
|
|
43
|
+
];
|
|
44
|
+
return props.children({
|
|
45
|
+
currentSort,
|
|
46
|
+
sortFieldOptions,
|
|
47
|
+
sortOrderOptions,
|
|
48
|
+
setSort: (sort) => {
|
|
49
|
+
productListService.setSort(sort);
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|