@wix/headless-stores 0.0.35 → 0.0.36
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 +46 -0
- package/cjs/dist/react/Category.js +69 -3
- package/cjs/dist/react/FilteredCollection.d.ts +83 -0
- package/cjs/dist/react/FilteredCollection.js +100 -4
- package/cjs/dist/services/collection-service.js +1 -1
- package/cjs/dist/services/selected-variant-service.js +0 -1
- package/dist/react/Category.d.ts +46 -0
- package/dist/react/Category.js +69 -3
- package/dist/react/FilteredCollection.d.ts +83 -0
- package/dist/react/FilteredCollection.js +100 -4
- package/dist/services/collection-service.js +1 -1
- package/dist/services/selected-variant-service.js +0 -1
- package/package.json +1 -1
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
import { type Category } from "@wix/auto_sdk_categories_categories";
|
|
2
2
|
import React, { type ReactNode } from "react";
|
|
3
|
+
import { type CategoryServiceConfig } from "../services/category-service.js";
|
|
4
|
+
import type { PropsWithChildren } from "react";
|
|
5
|
+
/**
|
|
6
|
+
* Root component that provides the Category service context to its children.
|
|
7
|
+
* This component sets up the necessary services for managing category functionality.
|
|
8
|
+
*
|
|
9
|
+
* @order 1
|
|
10
|
+
* @component
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* import { Category } from '@wix/stores/components';
|
|
14
|
+
*
|
|
15
|
+
* function CategoryNavigation({ categories }) {
|
|
16
|
+
* return (
|
|
17
|
+
* <Category.Root categoryServiceConfig={{ categories }}>
|
|
18
|
+
* <div>
|
|
19
|
+
* <Category.List>
|
|
20
|
+
* {({ categories, selectedCategory, setSelectedCategory }) => (
|
|
21
|
+
* <nav>
|
|
22
|
+
* <button
|
|
23
|
+
* onClick={() => setSelectedCategory(null)}
|
|
24
|
+
* className={selectedCategory === null ? 'active' : ''}
|
|
25
|
+
* >
|
|
26
|
+
* All Categories
|
|
27
|
+
* </button>
|
|
28
|
+
* {categories.map(category => (
|
|
29
|
+
* <button
|
|
30
|
+
* key={category.id}
|
|
31
|
+
* onClick={() => setSelectedCategory(category.id)}
|
|
32
|
+
* className={selectedCategory === category.id ? 'active' : ''}
|
|
33
|
+
* >
|
|
34
|
+
* {category.name}
|
|
35
|
+
* </button>
|
|
36
|
+
* ))}
|
|
37
|
+
* </nav>
|
|
38
|
+
* )}
|
|
39
|
+
* </Category.List>
|
|
40
|
+
* </div>
|
|
41
|
+
* </Category.Root>
|
|
42
|
+
* );
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function Root(props: PropsWithChildren<{
|
|
47
|
+
categoryServiceConfig?: CategoryServiceConfig;
|
|
48
|
+
}>): import("react/jsx-runtime").JSX.Element;
|
|
3
49
|
export interface CategoryListProps {
|
|
4
50
|
children: (data: {
|
|
5
51
|
categories: Category[];
|
|
@@ -1,6 +1,72 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useService } from "@wix/services-manager-react";
|
|
3
|
-
import { CategoryServiceDefinition } from "../services/category-service.js";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useService, WixServices } from "@wix/services-manager-react";
|
|
3
|
+
import { CategoryServiceDefinition, CategoryService, } from "../services/category-service.js";
|
|
4
|
+
import { createServicesMap } from "@wix/services-manager";
|
|
5
|
+
// Create navigation handler for category URLs
|
|
6
|
+
const handleCategoryChange = (categoryId, category) => {
|
|
7
|
+
if (typeof window !== "undefined") {
|
|
8
|
+
let newPath = "/category";
|
|
9
|
+
if (categoryId !== null) {
|
|
10
|
+
// Use category slug for URL
|
|
11
|
+
if (!category?.slug) {
|
|
12
|
+
console.warn(`Category ${categoryId} has no slug, using category ID as fallback`);
|
|
13
|
+
}
|
|
14
|
+
const categorySlug = category?.slug || categoryId;
|
|
15
|
+
newPath = `/category/${categorySlug}`;
|
|
16
|
+
}
|
|
17
|
+
window.history.pushState(null, "Showing Category " + category?.name, newPath);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Root component that provides the Category service context to its children.
|
|
22
|
+
* This component sets up the necessary services for managing category functionality.
|
|
23
|
+
*
|
|
24
|
+
* @order 1
|
|
25
|
+
* @component
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* import { Category } from '@wix/stores/components';
|
|
29
|
+
*
|
|
30
|
+
* function CategoryNavigation({ categories }) {
|
|
31
|
+
* return (
|
|
32
|
+
* <Category.Root categoryServiceConfig={{ categories }}>
|
|
33
|
+
* <div>
|
|
34
|
+
* <Category.List>
|
|
35
|
+
* {({ categories, selectedCategory, setSelectedCategory }) => (
|
|
36
|
+
* <nav>
|
|
37
|
+
* <button
|
|
38
|
+
* onClick={() => setSelectedCategory(null)}
|
|
39
|
+
* className={selectedCategory === null ? 'active' : ''}
|
|
40
|
+
* >
|
|
41
|
+
* All Categories
|
|
42
|
+
* </button>
|
|
43
|
+
* {categories.map(category => (
|
|
44
|
+
* <button
|
|
45
|
+
* key={category.id}
|
|
46
|
+
* onClick={() => setSelectedCategory(category.id)}
|
|
47
|
+
* className={selectedCategory === category.id ? 'active' : ''}
|
|
48
|
+
* >
|
|
49
|
+
* {category.name}
|
|
50
|
+
* </button>
|
|
51
|
+
* ))}
|
|
52
|
+
* </nav>
|
|
53
|
+
* )}
|
|
54
|
+
* </Category.List>
|
|
55
|
+
* </div>
|
|
56
|
+
* </Category.Root>
|
|
57
|
+
* );
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function Root(props) {
|
|
62
|
+
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(CategoryServiceDefinition, CategoryService, {
|
|
63
|
+
...(props.categoryServiceConfig ?? {
|
|
64
|
+
categories: [],
|
|
65
|
+
initialCategoryId: null,
|
|
66
|
+
}),
|
|
67
|
+
onCategoryChange: handleCategoryChange,
|
|
68
|
+
}), children: props.children }));
|
|
69
|
+
}
|
|
4
70
|
/**
|
|
5
71
|
* Headless component for displaying a list of categories
|
|
6
72
|
*
|
|
@@ -1,7 +1,90 @@
|
|
|
1
1
|
import React, { type ReactNode } from "react";
|
|
2
2
|
import { type AvailableOptions, type FilterServiceAPI, type Filter } from "../services/filter-service.js";
|
|
3
3
|
import { type V3Product } from "@wix/auto_sdk_stores_products-v-3";
|
|
4
|
+
import type { PropsWithChildren } from "react";
|
|
4
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;
|
|
5
88
|
export interface FiltersLoadingProps {
|
|
6
89
|
children: (data: {
|
|
7
90
|
isFullyLoaded: boolean;
|
|
@@ -1,8 +1,104 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useService } from "@wix/services-manager-react";
|
|
3
|
-
import { CollectionServiceDefinition } from "../services/collection-service.js";
|
|
4
|
-
import { FilterServiceDefinition, } from "../services/filter-service.js";
|
|
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";
|
|
5
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
|
+
}
|
|
6
102
|
/**
|
|
7
103
|
* Headless component for displaying a loading state for filters
|
|
8
104
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineService, implementService
|
|
1
|
+
import { defineService, implementService } from "@wix/services-definitions";
|
|
2
2
|
import { SignalsServiceDefinition } from "@wix/services-definitions/core-services/signals";
|
|
3
3
|
import { productsV3, readOnlyVariantsV3 } from "@wix/stores";
|
|
4
4
|
import { FilterServiceDefinition } from "./filter-service.js";
|
|
@@ -9,7 +9,6 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
|
|
|
9
9
|
const signalsService = getService(SignalsServiceDefinition);
|
|
10
10
|
const cartService = getService(CurrentCartServiceDefinition);
|
|
11
11
|
const productService = getService(ProductServiceDefinition);
|
|
12
|
-
// const mediaService = getService(MediaGalleryServiceDefinition);
|
|
13
12
|
const selectedChoices = signalsService.signal({});
|
|
14
13
|
const preOrderMessage = signalsService.signal(null);
|
|
15
14
|
const initialProduct = productService.product.get();
|
package/dist/react/Category.d.ts
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
import { type Category } from "@wix/auto_sdk_categories_categories";
|
|
2
2
|
import React, { type ReactNode } from "react";
|
|
3
|
+
import { type CategoryServiceConfig } from "../services/category-service.js";
|
|
4
|
+
import type { PropsWithChildren } from "react";
|
|
5
|
+
/**
|
|
6
|
+
* Root component that provides the Category service context to its children.
|
|
7
|
+
* This component sets up the necessary services for managing category functionality.
|
|
8
|
+
*
|
|
9
|
+
* @order 1
|
|
10
|
+
* @component
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* import { Category } from '@wix/stores/components';
|
|
14
|
+
*
|
|
15
|
+
* function CategoryNavigation({ categories }) {
|
|
16
|
+
* return (
|
|
17
|
+
* <Category.Root categoryServiceConfig={{ categories }}>
|
|
18
|
+
* <div>
|
|
19
|
+
* <Category.List>
|
|
20
|
+
* {({ categories, selectedCategory, setSelectedCategory }) => (
|
|
21
|
+
* <nav>
|
|
22
|
+
* <button
|
|
23
|
+
* onClick={() => setSelectedCategory(null)}
|
|
24
|
+
* className={selectedCategory === null ? 'active' : ''}
|
|
25
|
+
* >
|
|
26
|
+
* All Categories
|
|
27
|
+
* </button>
|
|
28
|
+
* {categories.map(category => (
|
|
29
|
+
* <button
|
|
30
|
+
* key={category.id}
|
|
31
|
+
* onClick={() => setSelectedCategory(category.id)}
|
|
32
|
+
* className={selectedCategory === category.id ? 'active' : ''}
|
|
33
|
+
* >
|
|
34
|
+
* {category.name}
|
|
35
|
+
* </button>
|
|
36
|
+
* ))}
|
|
37
|
+
* </nav>
|
|
38
|
+
* )}
|
|
39
|
+
* </Category.List>
|
|
40
|
+
* </div>
|
|
41
|
+
* </Category.Root>
|
|
42
|
+
* );
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function Root(props: PropsWithChildren<{
|
|
47
|
+
categoryServiceConfig?: CategoryServiceConfig;
|
|
48
|
+
}>): import("react/jsx-runtime").JSX.Element;
|
|
3
49
|
export interface CategoryListProps {
|
|
4
50
|
children: (data: {
|
|
5
51
|
categories: Category[];
|
package/dist/react/Category.js
CHANGED
|
@@ -1,6 +1,72 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useService } from "@wix/services-manager-react";
|
|
3
|
-
import { CategoryServiceDefinition } from "../services/category-service.js";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useService, WixServices } from "@wix/services-manager-react";
|
|
3
|
+
import { CategoryServiceDefinition, CategoryService, } from "../services/category-service.js";
|
|
4
|
+
import { createServicesMap } from "@wix/services-manager";
|
|
5
|
+
// Create navigation handler for category URLs
|
|
6
|
+
const handleCategoryChange = (categoryId, category) => {
|
|
7
|
+
if (typeof window !== "undefined") {
|
|
8
|
+
let newPath = "/category";
|
|
9
|
+
if (categoryId !== null) {
|
|
10
|
+
// Use category slug for URL
|
|
11
|
+
if (!category?.slug) {
|
|
12
|
+
console.warn(`Category ${categoryId} has no slug, using category ID as fallback`);
|
|
13
|
+
}
|
|
14
|
+
const categorySlug = category?.slug || categoryId;
|
|
15
|
+
newPath = `/category/${categorySlug}`;
|
|
16
|
+
}
|
|
17
|
+
window.history.pushState(null, "Showing Category " + category?.name, newPath);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Root component that provides the Category service context to its children.
|
|
22
|
+
* This component sets up the necessary services for managing category functionality.
|
|
23
|
+
*
|
|
24
|
+
* @order 1
|
|
25
|
+
* @component
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* import { Category } from '@wix/stores/components';
|
|
29
|
+
*
|
|
30
|
+
* function CategoryNavigation({ categories }) {
|
|
31
|
+
* return (
|
|
32
|
+
* <Category.Root categoryServiceConfig={{ categories }}>
|
|
33
|
+
* <div>
|
|
34
|
+
* <Category.List>
|
|
35
|
+
* {({ categories, selectedCategory, setSelectedCategory }) => (
|
|
36
|
+
* <nav>
|
|
37
|
+
* <button
|
|
38
|
+
* onClick={() => setSelectedCategory(null)}
|
|
39
|
+
* className={selectedCategory === null ? 'active' : ''}
|
|
40
|
+
* >
|
|
41
|
+
* All Categories
|
|
42
|
+
* </button>
|
|
43
|
+
* {categories.map(category => (
|
|
44
|
+
* <button
|
|
45
|
+
* key={category.id}
|
|
46
|
+
* onClick={() => setSelectedCategory(category.id)}
|
|
47
|
+
* className={selectedCategory === category.id ? 'active' : ''}
|
|
48
|
+
* >
|
|
49
|
+
* {category.name}
|
|
50
|
+
* </button>
|
|
51
|
+
* ))}
|
|
52
|
+
* </nav>
|
|
53
|
+
* )}
|
|
54
|
+
* </Category.List>
|
|
55
|
+
* </div>
|
|
56
|
+
* </Category.Root>
|
|
57
|
+
* );
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function Root(props) {
|
|
62
|
+
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(CategoryServiceDefinition, CategoryService, {
|
|
63
|
+
...(props.categoryServiceConfig ?? {
|
|
64
|
+
categories: [],
|
|
65
|
+
initialCategoryId: null,
|
|
66
|
+
}),
|
|
67
|
+
onCategoryChange: handleCategoryChange,
|
|
68
|
+
}), children: props.children }));
|
|
69
|
+
}
|
|
4
70
|
/**
|
|
5
71
|
* Headless component for displaying a list of categories
|
|
6
72
|
*
|
|
@@ -1,7 +1,90 @@
|
|
|
1
1
|
import React, { type ReactNode } from "react";
|
|
2
2
|
import { type AvailableOptions, type FilterServiceAPI, type Filter } from "../services/filter-service.js";
|
|
3
3
|
import { type V3Product } from "@wix/auto_sdk_stores_products-v-3";
|
|
4
|
+
import type { PropsWithChildren } from "react";
|
|
4
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;
|
|
5
88
|
export interface FiltersLoadingProps {
|
|
6
89
|
children: (data: {
|
|
7
90
|
isFullyLoaded: boolean;
|
|
@@ -1,8 +1,104 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useService } from "@wix/services-manager-react";
|
|
3
|
-
import { CollectionServiceDefinition } from "../services/collection-service.js";
|
|
4
|
-
import { FilterServiceDefinition, } from "../services/filter-service.js";
|
|
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";
|
|
5
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
|
+
}
|
|
6
102
|
/**
|
|
7
103
|
* Headless component for displaying a loading state for filters
|
|
8
104
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineService, implementService
|
|
1
|
+
import { defineService, implementService } from "@wix/services-definitions";
|
|
2
2
|
import { SignalsServiceDefinition } from "@wix/services-definitions/core-services/signals";
|
|
3
3
|
import { productsV3, readOnlyVariantsV3 } from "@wix/stores";
|
|
4
4
|
import { FilterServiceDefinition } from "./filter-service.js";
|
|
@@ -9,7 +9,6 @@ export const SelectedVariantService = implementService.withConfig()(SelectedVari
|
|
|
9
9
|
const signalsService = getService(SignalsServiceDefinition);
|
|
10
10
|
const cartService = getService(CurrentCartServiceDefinition);
|
|
11
11
|
const productService = getService(ProductServiceDefinition);
|
|
12
|
-
// const mediaService = getService(MediaGalleryServiceDefinition);
|
|
13
12
|
const selectedChoices = signalsService.signal({});
|
|
14
13
|
const preOrderMessage = signalsService.signal(null);
|
|
15
14
|
const initialProduct = productService.product.get();
|