@wix/headless-stores 0.0.25 → 0.0.26
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/ProductsList.d.ts +110 -0
- package/cjs/dist/react/ProductsList.js +129 -0
- package/cjs/dist/services/products-list-service.d.ts +51 -0
- package/cjs/dist/services/products-list-service.js +63 -0
- package/dist/react/ProductsList.d.ts +110 -0
- package/dist/react/ProductsList.js +129 -0
- package/dist/services/products-list-service.d.ts +51 -0
- package/dist/services/products-list-service.js +63 -0
- package/package.json +1 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { type ProductsListServiceConfig } from "../services/products-list-service.js";
|
|
2
|
+
import type { PropsWithChildren, ReactNode } from "react";
|
|
3
|
+
import { productsV3 } from "@wix/stores";
|
|
4
|
+
/**
|
|
5
|
+
* Root component that provides the ProductsList service context to its children.
|
|
6
|
+
* This component sets up the necessary services for managing products list state.
|
|
7
|
+
*
|
|
8
|
+
* @component
|
|
9
|
+
* @param props - Component props
|
|
10
|
+
* @param props.children - Child components that will have access to the ProductsList service
|
|
11
|
+
* @param props.productsListConfig - Configuration for the ProductsList service
|
|
12
|
+
* @returns JSX element wrapping children with ProductsList service context
|
|
13
|
+
*/
|
|
14
|
+
declare function Root(props: PropsWithChildren<{
|
|
15
|
+
productsListConfig: ProductsListServiceConfig;
|
|
16
|
+
}>): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export type EmptyStateProps = {
|
|
18
|
+
children: ((props: EmptyStateRenderProps) => ReactNode) | ReactNode;
|
|
19
|
+
};
|
|
20
|
+
export type EmptyStateRenderProps = {};
|
|
21
|
+
/**
|
|
22
|
+
* Component that renders content when the products list is empty.
|
|
23
|
+
* Only displays its children when there are no products, no loading state, and no errors.
|
|
24
|
+
*
|
|
25
|
+
* @component
|
|
26
|
+
* @param props - Component props
|
|
27
|
+
* @param props.children - Content to display when products list is empty (can be a render function or ReactNode)
|
|
28
|
+
* @returns JSX element or null based on products list state
|
|
29
|
+
*/
|
|
30
|
+
declare function EmptyState(props: EmptyStateProps): ReactNode;
|
|
31
|
+
export type LoadingProps = {
|
|
32
|
+
children: ((props: LoadingRenderProps) => ReactNode) | ReactNode;
|
|
33
|
+
};
|
|
34
|
+
export type LoadingRenderProps = {};
|
|
35
|
+
/**
|
|
36
|
+
* Component that renders content during loading state.
|
|
37
|
+
* Only displays its children when the products list is currently loading.
|
|
38
|
+
*
|
|
39
|
+
* @component
|
|
40
|
+
* @param props - Component props
|
|
41
|
+
* @param props.children - Content to display during loading (can be a render function or ReactNode)
|
|
42
|
+
* @returns JSX element or null based on loading state
|
|
43
|
+
*/
|
|
44
|
+
declare function Loading(props: LoadingProps): ReactNode;
|
|
45
|
+
export type ErrorProps = {
|
|
46
|
+
children: ((props: ErrorRenderProps) => ReactNode) | ReactNode;
|
|
47
|
+
};
|
|
48
|
+
export type ErrorRenderProps = {
|
|
49
|
+
error: string | null;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Component that renders content when there's an error loading products.
|
|
53
|
+
* Only displays its children when an error has occurred.
|
|
54
|
+
*
|
|
55
|
+
* @component
|
|
56
|
+
* @param props - Component props
|
|
57
|
+
* @param props.children - Content to display during error state (can be a render function or ReactNode)
|
|
58
|
+
* @returns JSX element or null based on error state
|
|
59
|
+
*/
|
|
60
|
+
declare function Error(props: ErrorProps): ReactNode;
|
|
61
|
+
export type ItemContentRenderProps = {
|
|
62
|
+
product: productsV3.V3Product;
|
|
63
|
+
};
|
|
64
|
+
export type ItemContentProps = {
|
|
65
|
+
children: ((props: ItemContentRenderProps) => ReactNode) | ReactNode;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Component that renders content for each product in the list.
|
|
69
|
+
* Maps over all products and provides each product through a service context.
|
|
70
|
+
* Only renders when products are successfully loaded (not loading, no error, and has products).
|
|
71
|
+
*
|
|
72
|
+
* @component
|
|
73
|
+
* @param props - Component props
|
|
74
|
+
* @param props.children - Content to display for each product (can be a render function receiving product data or ReactNode)
|
|
75
|
+
* @returns Array of JSX elements for each product or null if no products to display
|
|
76
|
+
*/
|
|
77
|
+
declare function ItemContent(props: ItemContentProps): import("react/jsx-runtime").JSX.Element[] | null;
|
|
78
|
+
/**
|
|
79
|
+
* ProductsList component collection providing a complete solution for displaying products.
|
|
80
|
+
*
|
|
81
|
+
* Includes components for different states:
|
|
82
|
+
* - Root: Service provider component
|
|
83
|
+
* - EmptyState: Displays when no products are available
|
|
84
|
+
* - Loading: Displays during loading state
|
|
85
|
+
* - Error: Displays when an error occurs
|
|
86
|
+
* - ItemContent: Renders individual product items
|
|
87
|
+
*
|
|
88
|
+
* @component
|
|
89
|
+
* @example
|
|
90
|
+
* ```jsx
|
|
91
|
+
* <ProductsList.Root productsListConfig={config}>
|
|
92
|
+
* <ProductsList.Loading>Loading products...</ProductsList.Loading>
|
|
93
|
+
* <ProductsList.Error>
|
|
94
|
+
* {({ error }) => <div>Error: {error}</div>}
|
|
95
|
+
* </ProductsList.Error>
|
|
96
|
+
* <ProductsList.EmptyState>No products found</ProductsList.EmptyState>
|
|
97
|
+
* <ProductsList.ItemContent>
|
|
98
|
+
* {({ product }) => <div>{product.name}</div>}
|
|
99
|
+
* </ProductsList.ItemContent>
|
|
100
|
+
* </ProductsList.Root>
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare const ProductsList: {
|
|
104
|
+
Root: typeof Root;
|
|
105
|
+
EmptyState: typeof EmptyState;
|
|
106
|
+
Loading: typeof Loading;
|
|
107
|
+
Error: typeof Error;
|
|
108
|
+
ItemContent: typeof ItemContent;
|
|
109
|
+
};
|
|
110
|
+
export {};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useService, WixServices } from "@wix/services-manager-react";
|
|
3
|
+
import { createServicesMap } from "@wix/services-manager";
|
|
4
|
+
import { ProductListService, ProductsListServiceDefinition, } from "../services/products-list-service.js";
|
|
5
|
+
import { ProductService, ProductServiceDefinition, } from "@wix/headless-stores/services";
|
|
6
|
+
/**
|
|
7
|
+
* Root component that provides the ProductsList service context to its children.
|
|
8
|
+
* This component sets up the necessary services for managing products list state.
|
|
9
|
+
*
|
|
10
|
+
* @component
|
|
11
|
+
* @param props - Component props
|
|
12
|
+
* @param props.children - Child components that will have access to the ProductsList service
|
|
13
|
+
* @param props.productsListConfig - Configuration for the ProductsList service
|
|
14
|
+
* @returns JSX element wrapping children with ProductsList service context
|
|
15
|
+
*/
|
|
16
|
+
function Root(props) {
|
|
17
|
+
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(ProductsListServiceDefinition, ProductListService, props.productsListConfig), children: props.children }));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Component that renders content when the products list is empty.
|
|
21
|
+
* Only displays its children when there are no products, no loading state, and no errors.
|
|
22
|
+
*
|
|
23
|
+
* @component
|
|
24
|
+
* @param props - Component props
|
|
25
|
+
* @param props.children - Content to display when products list is empty (can be a render function or ReactNode)
|
|
26
|
+
* @returns JSX element or null based on products list state
|
|
27
|
+
*/
|
|
28
|
+
function EmptyState(props) {
|
|
29
|
+
const { isLoading, error, products } = useService(ProductsListServiceDefinition);
|
|
30
|
+
const isLoadingValue = isLoading.get();
|
|
31
|
+
const errorValue = error.get();
|
|
32
|
+
const productsValue = products.get();
|
|
33
|
+
if (!isLoadingValue && !errorValue && productsValue.length === 0) {
|
|
34
|
+
return typeof props.children === "function"
|
|
35
|
+
? props.children({})
|
|
36
|
+
: props.children;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Component that renders content during loading state.
|
|
42
|
+
* Only displays its children when the products list is currently loading.
|
|
43
|
+
*
|
|
44
|
+
* @component
|
|
45
|
+
* @param props - Component props
|
|
46
|
+
* @param props.children - Content to display during loading (can be a render function or ReactNode)
|
|
47
|
+
* @returns JSX element or null based on loading state
|
|
48
|
+
*/
|
|
49
|
+
function Loading(props) {
|
|
50
|
+
const { isLoading } = useService(ProductsListServiceDefinition);
|
|
51
|
+
const isLoadingValue = isLoading.get();
|
|
52
|
+
if (isLoadingValue) {
|
|
53
|
+
return typeof props.children === "function"
|
|
54
|
+
? props.children({})
|
|
55
|
+
: props.children;
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Component that renders content when there's an error loading products.
|
|
61
|
+
* Only displays its children when an error has occurred.
|
|
62
|
+
*
|
|
63
|
+
* @component
|
|
64
|
+
* @param props - Component props
|
|
65
|
+
* @param props.children - Content to display during error state (can be a render function or ReactNode)
|
|
66
|
+
* @returns JSX element or null based on error state
|
|
67
|
+
*/
|
|
68
|
+
function Error(props) {
|
|
69
|
+
const { error } = useService(ProductsListServiceDefinition);
|
|
70
|
+
const errorValue = error.get();
|
|
71
|
+
if (errorValue) {
|
|
72
|
+
return typeof props.children === "function"
|
|
73
|
+
? props.children({ error: errorValue })
|
|
74
|
+
: props.children;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Component that renders content for each product in the list.
|
|
80
|
+
* Maps over all products and provides each product through a service context.
|
|
81
|
+
* Only renders when products are successfully loaded (not loading, no error, and has products).
|
|
82
|
+
*
|
|
83
|
+
* @component
|
|
84
|
+
* @param props - Component props
|
|
85
|
+
* @param props.children - Content to display for each product (can be a render function receiving product data or ReactNode)
|
|
86
|
+
* @returns Array of JSX elements for each product or null if no products to display
|
|
87
|
+
*/
|
|
88
|
+
function ItemContent(props) {
|
|
89
|
+
const { products, isLoading, error } = useService(ProductsListServiceDefinition);
|
|
90
|
+
const productsValue = products.get();
|
|
91
|
+
if (isLoading.get() || error.get() || productsValue.length === 0) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return productsValue.map((product) => (_jsx(WixServices, { servicesMap: createServicesMap().addService(ProductServiceDefinition, ProductService, { product }), children: typeof props.children === "function"
|
|
95
|
+
? props.children({ product })
|
|
96
|
+
: props.children }, product._id)));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* ProductsList component collection providing a complete solution for displaying products.
|
|
100
|
+
*
|
|
101
|
+
* Includes components for different states:
|
|
102
|
+
* - Root: Service provider component
|
|
103
|
+
* - EmptyState: Displays when no products are available
|
|
104
|
+
* - Loading: Displays during loading state
|
|
105
|
+
* - Error: Displays when an error occurs
|
|
106
|
+
* - ItemContent: Renders individual product items
|
|
107
|
+
*
|
|
108
|
+
* @component
|
|
109
|
+
* @example
|
|
110
|
+
* ```jsx
|
|
111
|
+
* <ProductsList.Root productsListConfig={config}>
|
|
112
|
+
* <ProductsList.Loading>Loading products...</ProductsList.Loading>
|
|
113
|
+
* <ProductsList.Error>
|
|
114
|
+
* {({ error }) => <div>Error: {error}</div>}
|
|
115
|
+
* </ProductsList.Error>
|
|
116
|
+
* <ProductsList.EmptyState>No products found</ProductsList.EmptyState>
|
|
117
|
+
* <ProductsList.ItemContent>
|
|
118
|
+
* {({ product }) => <div>{product.name}</div>}
|
|
119
|
+
* </ProductsList.ItemContent>
|
|
120
|
+
* </ProductsList.Root>
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export const ProductsList = {
|
|
124
|
+
Root,
|
|
125
|
+
EmptyState,
|
|
126
|
+
Loading,
|
|
127
|
+
Error,
|
|
128
|
+
ItemContent,
|
|
129
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type Signal } from "@wix/services-definitions/core-services/signals";
|
|
2
|
+
import { productsV3 } from "@wix/stores";
|
|
3
|
+
export type ProductsListServiceConfig = {
|
|
4
|
+
products: productsV3.V3Product[];
|
|
5
|
+
searchOptions: Parameters<typeof productsV3.searchProducts>[0];
|
|
6
|
+
pagingMetadata: productsV3.CommonCursorPagingMetadata;
|
|
7
|
+
aggregations: productsV3.AggregationData;
|
|
8
|
+
};
|
|
9
|
+
export declare function loadProductsListServiceConfig(searchOptions: Parameters<typeof productsV3.searchProducts>[0]): Promise<ProductsListServiceConfig>;
|
|
10
|
+
export declare const ProductsListServiceDefinition: string & {
|
|
11
|
+
__api: {
|
|
12
|
+
products: Signal<productsV3.V3Product[]>;
|
|
13
|
+
aggregations: Signal<productsV3.AggregationData>;
|
|
14
|
+
pagingMetadata: Signal<productsV3.CommonCursorPagingMetadata>;
|
|
15
|
+
searchOptions: Signal<Parameters<typeof productsV3.searchProducts>[0]>;
|
|
16
|
+
isLoading: Signal<boolean>;
|
|
17
|
+
error: Signal<string | null>;
|
|
18
|
+
setSearchOptions: (searchOptions: Parameters<typeof productsV3.searchProducts>[0]) => void;
|
|
19
|
+
};
|
|
20
|
+
__config: ProductsListServiceConfig;
|
|
21
|
+
isServiceDefinition?: boolean;
|
|
22
|
+
} & {
|
|
23
|
+
products: Signal<productsV3.V3Product[]>;
|
|
24
|
+
aggregations: Signal<productsV3.AggregationData>;
|
|
25
|
+
pagingMetadata: Signal<productsV3.CommonCursorPagingMetadata>;
|
|
26
|
+
searchOptions: Signal<Parameters<typeof productsV3.searchProducts>[0]>;
|
|
27
|
+
isLoading: Signal<boolean>;
|
|
28
|
+
error: Signal<string | null>;
|
|
29
|
+
setSearchOptions: (searchOptions: Parameters<typeof productsV3.searchProducts>[0]) => void;
|
|
30
|
+
};
|
|
31
|
+
export declare const ProductListService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
32
|
+
__api: {
|
|
33
|
+
products: Signal<productsV3.V3Product[]>;
|
|
34
|
+
aggregations: Signal<productsV3.AggregationData>;
|
|
35
|
+
pagingMetadata: Signal<productsV3.CommonCursorPagingMetadata>;
|
|
36
|
+
searchOptions: Signal<Parameters<typeof productsV3.searchProducts>[0]>;
|
|
37
|
+
isLoading: Signal<boolean>;
|
|
38
|
+
error: Signal<string | null>;
|
|
39
|
+
setSearchOptions: (searchOptions: Parameters<typeof productsV3.searchProducts>[0]) => void;
|
|
40
|
+
};
|
|
41
|
+
__config: ProductsListServiceConfig;
|
|
42
|
+
isServiceDefinition?: boolean;
|
|
43
|
+
} & {
|
|
44
|
+
products: Signal<productsV3.V3Product[]>;
|
|
45
|
+
aggregations: Signal<productsV3.AggregationData>;
|
|
46
|
+
pagingMetadata: Signal<productsV3.CommonCursorPagingMetadata>;
|
|
47
|
+
searchOptions: Signal<Parameters<typeof productsV3.searchProducts>[0]>;
|
|
48
|
+
isLoading: Signal<boolean>;
|
|
49
|
+
error: Signal<string | null>;
|
|
50
|
+
setSearchOptions: (searchOptions: Parameters<typeof productsV3.searchProducts>[0]) => void;
|
|
51
|
+
}, ProductsListServiceConfig>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { defineService, implementService } from "@wix/services-definitions";
|
|
2
|
+
import { SignalsServiceDefinition, } from "@wix/services-definitions/core-services/signals";
|
|
3
|
+
import { productsV3 } from "@wix/stores";
|
|
4
|
+
export async function loadProductsListServiceConfig(searchOptions) {
|
|
5
|
+
const result = await productsV3.searchProducts(searchOptions);
|
|
6
|
+
return {
|
|
7
|
+
products: result.products ?? [],
|
|
8
|
+
searchOptions,
|
|
9
|
+
pagingMetadata: result.pagingMetadata,
|
|
10
|
+
aggregations: result.aggregationData,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export const ProductsListServiceDefinition = defineService("products-list");
|
|
14
|
+
export const ProductListService = implementService.withConfig()(ProductsListServiceDefinition, ({ getService, config }) => {
|
|
15
|
+
let firstRun = true;
|
|
16
|
+
const signalsService = getService(SignalsServiceDefinition);
|
|
17
|
+
const productsSignal = signalsService.signal(config.products);
|
|
18
|
+
const searchOptionsSignal = signalsService.signal(config.searchOptions);
|
|
19
|
+
const pagingMetadataSignal = signalsService.signal(config.pagingMetadata);
|
|
20
|
+
const aggregationsSignal = signalsService.signal(config.aggregations);
|
|
21
|
+
const isLoadingSignal = signalsService.signal(false);
|
|
22
|
+
const errorSignal = signalsService.signal(null);
|
|
23
|
+
if (typeof window !== "undefined") {
|
|
24
|
+
signalsService.effect(async () => {
|
|
25
|
+
// CRITICAL: Read the signals FIRST to establish dependencies, even on first run
|
|
26
|
+
const searchOptions = searchOptionsSignal.get();
|
|
27
|
+
if (firstRun) {
|
|
28
|
+
firstRun = false;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
isLoadingSignal.set(true);
|
|
33
|
+
const affectiveSearchOptions = searchOptions.cursorPaging?.cursor
|
|
34
|
+
? {
|
|
35
|
+
cursorPaging: {
|
|
36
|
+
cursor: searchOptions.cursorPaging.cursor,
|
|
37
|
+
limit: searchOptions.cursorPaging.limit,
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
: searchOptions;
|
|
41
|
+
const result = await productsV3.searchProducts(affectiveSearchOptions);
|
|
42
|
+
productsSignal.set(result.products ?? []);
|
|
43
|
+
pagingMetadataSignal.set(result.pagingMetadata);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
errorSignal.set(error instanceof Error ? error.message : "Unknown error");
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
isLoadingSignal.set(false);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
firstRun = false;
|
|
54
|
+
return {
|
|
55
|
+
products: productsSignal,
|
|
56
|
+
searchOptions: searchOptionsSignal,
|
|
57
|
+
pagingMetadata: pagingMetadataSignal,
|
|
58
|
+
aggregations: aggregationsSignal,
|
|
59
|
+
setSearchOptions: (searchOptions) => searchOptionsSignal.set(searchOptions),
|
|
60
|
+
isLoading: isLoadingSignal,
|
|
61
|
+
error: errorSignal,
|
|
62
|
+
};
|
|
63
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { type ProductsListServiceConfig } from "../services/products-list-service.js";
|
|
2
|
+
import type { PropsWithChildren, ReactNode } from "react";
|
|
3
|
+
import { productsV3 } from "@wix/stores";
|
|
4
|
+
/**
|
|
5
|
+
* Root component that provides the ProductsList service context to its children.
|
|
6
|
+
* This component sets up the necessary services for managing products list state.
|
|
7
|
+
*
|
|
8
|
+
* @component
|
|
9
|
+
* @param props - Component props
|
|
10
|
+
* @param props.children - Child components that will have access to the ProductsList service
|
|
11
|
+
* @param props.productsListConfig - Configuration for the ProductsList service
|
|
12
|
+
* @returns JSX element wrapping children with ProductsList service context
|
|
13
|
+
*/
|
|
14
|
+
declare function Root(props: PropsWithChildren<{
|
|
15
|
+
productsListConfig: ProductsListServiceConfig;
|
|
16
|
+
}>): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export type EmptyStateProps = {
|
|
18
|
+
children: ((props: EmptyStateRenderProps) => ReactNode) | ReactNode;
|
|
19
|
+
};
|
|
20
|
+
export type EmptyStateRenderProps = {};
|
|
21
|
+
/**
|
|
22
|
+
* Component that renders content when the products list is empty.
|
|
23
|
+
* Only displays its children when there are no products, no loading state, and no errors.
|
|
24
|
+
*
|
|
25
|
+
* @component
|
|
26
|
+
* @param props - Component props
|
|
27
|
+
* @param props.children - Content to display when products list is empty (can be a render function or ReactNode)
|
|
28
|
+
* @returns JSX element or null based on products list state
|
|
29
|
+
*/
|
|
30
|
+
declare function EmptyState(props: EmptyStateProps): ReactNode;
|
|
31
|
+
export type LoadingProps = {
|
|
32
|
+
children: ((props: LoadingRenderProps) => ReactNode) | ReactNode;
|
|
33
|
+
};
|
|
34
|
+
export type LoadingRenderProps = {};
|
|
35
|
+
/**
|
|
36
|
+
* Component that renders content during loading state.
|
|
37
|
+
* Only displays its children when the products list is currently loading.
|
|
38
|
+
*
|
|
39
|
+
* @component
|
|
40
|
+
* @param props - Component props
|
|
41
|
+
* @param props.children - Content to display during loading (can be a render function or ReactNode)
|
|
42
|
+
* @returns JSX element or null based on loading state
|
|
43
|
+
*/
|
|
44
|
+
declare function Loading(props: LoadingProps): ReactNode;
|
|
45
|
+
export type ErrorProps = {
|
|
46
|
+
children: ((props: ErrorRenderProps) => ReactNode) | ReactNode;
|
|
47
|
+
};
|
|
48
|
+
export type ErrorRenderProps = {
|
|
49
|
+
error: string | null;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Component that renders content when there's an error loading products.
|
|
53
|
+
* Only displays its children when an error has occurred.
|
|
54
|
+
*
|
|
55
|
+
* @component
|
|
56
|
+
* @param props - Component props
|
|
57
|
+
* @param props.children - Content to display during error state (can be a render function or ReactNode)
|
|
58
|
+
* @returns JSX element or null based on error state
|
|
59
|
+
*/
|
|
60
|
+
declare function Error(props: ErrorProps): ReactNode;
|
|
61
|
+
export type ItemContentRenderProps = {
|
|
62
|
+
product: productsV3.V3Product;
|
|
63
|
+
};
|
|
64
|
+
export type ItemContentProps = {
|
|
65
|
+
children: ((props: ItemContentRenderProps) => ReactNode) | ReactNode;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Component that renders content for each product in the list.
|
|
69
|
+
* Maps over all products and provides each product through a service context.
|
|
70
|
+
* Only renders when products are successfully loaded (not loading, no error, and has products).
|
|
71
|
+
*
|
|
72
|
+
* @component
|
|
73
|
+
* @param props - Component props
|
|
74
|
+
* @param props.children - Content to display for each product (can be a render function receiving product data or ReactNode)
|
|
75
|
+
* @returns Array of JSX elements for each product or null if no products to display
|
|
76
|
+
*/
|
|
77
|
+
declare function ItemContent(props: ItemContentProps): import("react/jsx-runtime").JSX.Element[] | null;
|
|
78
|
+
/**
|
|
79
|
+
* ProductsList component collection providing a complete solution for displaying products.
|
|
80
|
+
*
|
|
81
|
+
* Includes components for different states:
|
|
82
|
+
* - Root: Service provider component
|
|
83
|
+
* - EmptyState: Displays when no products are available
|
|
84
|
+
* - Loading: Displays during loading state
|
|
85
|
+
* - Error: Displays when an error occurs
|
|
86
|
+
* - ItemContent: Renders individual product items
|
|
87
|
+
*
|
|
88
|
+
* @component
|
|
89
|
+
* @example
|
|
90
|
+
* ```jsx
|
|
91
|
+
* <ProductsList.Root productsListConfig={config}>
|
|
92
|
+
* <ProductsList.Loading>Loading products...</ProductsList.Loading>
|
|
93
|
+
* <ProductsList.Error>
|
|
94
|
+
* {({ error }) => <div>Error: {error}</div>}
|
|
95
|
+
* </ProductsList.Error>
|
|
96
|
+
* <ProductsList.EmptyState>No products found</ProductsList.EmptyState>
|
|
97
|
+
* <ProductsList.ItemContent>
|
|
98
|
+
* {({ product }) => <div>{product.name}</div>}
|
|
99
|
+
* </ProductsList.ItemContent>
|
|
100
|
+
* </ProductsList.Root>
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare const ProductsList: {
|
|
104
|
+
Root: typeof Root;
|
|
105
|
+
EmptyState: typeof EmptyState;
|
|
106
|
+
Loading: typeof Loading;
|
|
107
|
+
Error: typeof Error;
|
|
108
|
+
ItemContent: typeof ItemContent;
|
|
109
|
+
};
|
|
110
|
+
export {};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useService, WixServices } from "@wix/services-manager-react";
|
|
3
|
+
import { createServicesMap } from "@wix/services-manager";
|
|
4
|
+
import { ProductListService, ProductsListServiceDefinition, } from "../services/products-list-service.js";
|
|
5
|
+
import { ProductService, ProductServiceDefinition, } from "@wix/headless-stores/services";
|
|
6
|
+
/**
|
|
7
|
+
* Root component that provides the ProductsList service context to its children.
|
|
8
|
+
* This component sets up the necessary services for managing products list state.
|
|
9
|
+
*
|
|
10
|
+
* @component
|
|
11
|
+
* @param props - Component props
|
|
12
|
+
* @param props.children - Child components that will have access to the ProductsList service
|
|
13
|
+
* @param props.productsListConfig - Configuration for the ProductsList service
|
|
14
|
+
* @returns JSX element wrapping children with ProductsList service context
|
|
15
|
+
*/
|
|
16
|
+
function Root(props) {
|
|
17
|
+
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(ProductsListServiceDefinition, ProductListService, props.productsListConfig), children: props.children }));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Component that renders content when the products list is empty.
|
|
21
|
+
* Only displays its children when there are no products, no loading state, and no errors.
|
|
22
|
+
*
|
|
23
|
+
* @component
|
|
24
|
+
* @param props - Component props
|
|
25
|
+
* @param props.children - Content to display when products list is empty (can be a render function or ReactNode)
|
|
26
|
+
* @returns JSX element or null based on products list state
|
|
27
|
+
*/
|
|
28
|
+
function EmptyState(props) {
|
|
29
|
+
const { isLoading, error, products } = useService(ProductsListServiceDefinition);
|
|
30
|
+
const isLoadingValue = isLoading.get();
|
|
31
|
+
const errorValue = error.get();
|
|
32
|
+
const productsValue = products.get();
|
|
33
|
+
if (!isLoadingValue && !errorValue && productsValue.length === 0) {
|
|
34
|
+
return typeof props.children === "function"
|
|
35
|
+
? props.children({})
|
|
36
|
+
: props.children;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Component that renders content during loading state.
|
|
42
|
+
* Only displays its children when the products list is currently loading.
|
|
43
|
+
*
|
|
44
|
+
* @component
|
|
45
|
+
* @param props - Component props
|
|
46
|
+
* @param props.children - Content to display during loading (can be a render function or ReactNode)
|
|
47
|
+
* @returns JSX element or null based on loading state
|
|
48
|
+
*/
|
|
49
|
+
function Loading(props) {
|
|
50
|
+
const { isLoading } = useService(ProductsListServiceDefinition);
|
|
51
|
+
const isLoadingValue = isLoading.get();
|
|
52
|
+
if (isLoadingValue) {
|
|
53
|
+
return typeof props.children === "function"
|
|
54
|
+
? props.children({})
|
|
55
|
+
: props.children;
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Component that renders content when there's an error loading products.
|
|
61
|
+
* Only displays its children when an error has occurred.
|
|
62
|
+
*
|
|
63
|
+
* @component
|
|
64
|
+
* @param props - Component props
|
|
65
|
+
* @param props.children - Content to display during error state (can be a render function or ReactNode)
|
|
66
|
+
* @returns JSX element or null based on error state
|
|
67
|
+
*/
|
|
68
|
+
function Error(props) {
|
|
69
|
+
const { error } = useService(ProductsListServiceDefinition);
|
|
70
|
+
const errorValue = error.get();
|
|
71
|
+
if (errorValue) {
|
|
72
|
+
return typeof props.children === "function"
|
|
73
|
+
? props.children({ error: errorValue })
|
|
74
|
+
: props.children;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Component that renders content for each product in the list.
|
|
80
|
+
* Maps over all products and provides each product through a service context.
|
|
81
|
+
* Only renders when products are successfully loaded (not loading, no error, and has products).
|
|
82
|
+
*
|
|
83
|
+
* @component
|
|
84
|
+
* @param props - Component props
|
|
85
|
+
* @param props.children - Content to display for each product (can be a render function receiving product data or ReactNode)
|
|
86
|
+
* @returns Array of JSX elements for each product or null if no products to display
|
|
87
|
+
*/
|
|
88
|
+
function ItemContent(props) {
|
|
89
|
+
const { products, isLoading, error } = useService(ProductsListServiceDefinition);
|
|
90
|
+
const productsValue = products.get();
|
|
91
|
+
if (isLoading.get() || error.get() || productsValue.length === 0) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return productsValue.map((product) => (_jsx(WixServices, { servicesMap: createServicesMap().addService(ProductServiceDefinition, ProductService, { product }), children: typeof props.children === "function"
|
|
95
|
+
? props.children({ product })
|
|
96
|
+
: props.children }, product._id)));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* ProductsList component collection providing a complete solution for displaying products.
|
|
100
|
+
*
|
|
101
|
+
* Includes components for different states:
|
|
102
|
+
* - Root: Service provider component
|
|
103
|
+
* - EmptyState: Displays when no products are available
|
|
104
|
+
* - Loading: Displays during loading state
|
|
105
|
+
* - Error: Displays when an error occurs
|
|
106
|
+
* - ItemContent: Renders individual product items
|
|
107
|
+
*
|
|
108
|
+
* @component
|
|
109
|
+
* @example
|
|
110
|
+
* ```jsx
|
|
111
|
+
* <ProductsList.Root productsListConfig={config}>
|
|
112
|
+
* <ProductsList.Loading>Loading products...</ProductsList.Loading>
|
|
113
|
+
* <ProductsList.Error>
|
|
114
|
+
* {({ error }) => <div>Error: {error}</div>}
|
|
115
|
+
* </ProductsList.Error>
|
|
116
|
+
* <ProductsList.EmptyState>No products found</ProductsList.EmptyState>
|
|
117
|
+
* <ProductsList.ItemContent>
|
|
118
|
+
* {({ product }) => <div>{product.name}</div>}
|
|
119
|
+
* </ProductsList.ItemContent>
|
|
120
|
+
* </ProductsList.Root>
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export const ProductsList = {
|
|
124
|
+
Root,
|
|
125
|
+
EmptyState,
|
|
126
|
+
Loading,
|
|
127
|
+
Error,
|
|
128
|
+
ItemContent,
|
|
129
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type Signal } from "@wix/services-definitions/core-services/signals";
|
|
2
|
+
import { productsV3 } from "@wix/stores";
|
|
3
|
+
export type ProductsListServiceConfig = {
|
|
4
|
+
products: productsV3.V3Product[];
|
|
5
|
+
searchOptions: Parameters<typeof productsV3.searchProducts>[0];
|
|
6
|
+
pagingMetadata: productsV3.CommonCursorPagingMetadata;
|
|
7
|
+
aggregations: productsV3.AggregationData;
|
|
8
|
+
};
|
|
9
|
+
export declare function loadProductsListServiceConfig(searchOptions: Parameters<typeof productsV3.searchProducts>[0]): Promise<ProductsListServiceConfig>;
|
|
10
|
+
export declare const ProductsListServiceDefinition: string & {
|
|
11
|
+
__api: {
|
|
12
|
+
products: Signal<productsV3.V3Product[]>;
|
|
13
|
+
aggregations: Signal<productsV3.AggregationData>;
|
|
14
|
+
pagingMetadata: Signal<productsV3.CommonCursorPagingMetadata>;
|
|
15
|
+
searchOptions: Signal<Parameters<typeof productsV3.searchProducts>[0]>;
|
|
16
|
+
isLoading: Signal<boolean>;
|
|
17
|
+
error: Signal<string | null>;
|
|
18
|
+
setSearchOptions: (searchOptions: Parameters<typeof productsV3.searchProducts>[0]) => void;
|
|
19
|
+
};
|
|
20
|
+
__config: ProductsListServiceConfig;
|
|
21
|
+
isServiceDefinition?: boolean;
|
|
22
|
+
} & {
|
|
23
|
+
products: Signal<productsV3.V3Product[]>;
|
|
24
|
+
aggregations: Signal<productsV3.AggregationData>;
|
|
25
|
+
pagingMetadata: Signal<productsV3.CommonCursorPagingMetadata>;
|
|
26
|
+
searchOptions: Signal<Parameters<typeof productsV3.searchProducts>[0]>;
|
|
27
|
+
isLoading: Signal<boolean>;
|
|
28
|
+
error: Signal<string | null>;
|
|
29
|
+
setSearchOptions: (searchOptions: Parameters<typeof productsV3.searchProducts>[0]) => void;
|
|
30
|
+
};
|
|
31
|
+
export declare const ProductListService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
32
|
+
__api: {
|
|
33
|
+
products: Signal<productsV3.V3Product[]>;
|
|
34
|
+
aggregations: Signal<productsV3.AggregationData>;
|
|
35
|
+
pagingMetadata: Signal<productsV3.CommonCursorPagingMetadata>;
|
|
36
|
+
searchOptions: Signal<Parameters<typeof productsV3.searchProducts>[0]>;
|
|
37
|
+
isLoading: Signal<boolean>;
|
|
38
|
+
error: Signal<string | null>;
|
|
39
|
+
setSearchOptions: (searchOptions: Parameters<typeof productsV3.searchProducts>[0]) => void;
|
|
40
|
+
};
|
|
41
|
+
__config: ProductsListServiceConfig;
|
|
42
|
+
isServiceDefinition?: boolean;
|
|
43
|
+
} & {
|
|
44
|
+
products: Signal<productsV3.V3Product[]>;
|
|
45
|
+
aggregations: Signal<productsV3.AggregationData>;
|
|
46
|
+
pagingMetadata: Signal<productsV3.CommonCursorPagingMetadata>;
|
|
47
|
+
searchOptions: Signal<Parameters<typeof productsV3.searchProducts>[0]>;
|
|
48
|
+
isLoading: Signal<boolean>;
|
|
49
|
+
error: Signal<string | null>;
|
|
50
|
+
setSearchOptions: (searchOptions: Parameters<typeof productsV3.searchProducts>[0]) => void;
|
|
51
|
+
}, ProductsListServiceConfig>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { defineService, implementService } from "@wix/services-definitions";
|
|
2
|
+
import { SignalsServiceDefinition, } from "@wix/services-definitions/core-services/signals";
|
|
3
|
+
import { productsV3 } from "@wix/stores";
|
|
4
|
+
export async function loadProductsListServiceConfig(searchOptions) {
|
|
5
|
+
const result = await productsV3.searchProducts(searchOptions);
|
|
6
|
+
return {
|
|
7
|
+
products: result.products ?? [],
|
|
8
|
+
searchOptions,
|
|
9
|
+
pagingMetadata: result.pagingMetadata,
|
|
10
|
+
aggregations: result.aggregationData,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export const ProductsListServiceDefinition = defineService("products-list");
|
|
14
|
+
export const ProductListService = implementService.withConfig()(ProductsListServiceDefinition, ({ getService, config }) => {
|
|
15
|
+
let firstRun = true;
|
|
16
|
+
const signalsService = getService(SignalsServiceDefinition);
|
|
17
|
+
const productsSignal = signalsService.signal(config.products);
|
|
18
|
+
const searchOptionsSignal = signalsService.signal(config.searchOptions);
|
|
19
|
+
const pagingMetadataSignal = signalsService.signal(config.pagingMetadata);
|
|
20
|
+
const aggregationsSignal = signalsService.signal(config.aggregations);
|
|
21
|
+
const isLoadingSignal = signalsService.signal(false);
|
|
22
|
+
const errorSignal = signalsService.signal(null);
|
|
23
|
+
if (typeof window !== "undefined") {
|
|
24
|
+
signalsService.effect(async () => {
|
|
25
|
+
// CRITICAL: Read the signals FIRST to establish dependencies, even on first run
|
|
26
|
+
const searchOptions = searchOptionsSignal.get();
|
|
27
|
+
if (firstRun) {
|
|
28
|
+
firstRun = false;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
isLoadingSignal.set(true);
|
|
33
|
+
const affectiveSearchOptions = searchOptions.cursorPaging?.cursor
|
|
34
|
+
? {
|
|
35
|
+
cursorPaging: {
|
|
36
|
+
cursor: searchOptions.cursorPaging.cursor,
|
|
37
|
+
limit: searchOptions.cursorPaging.limit,
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
: searchOptions;
|
|
41
|
+
const result = await productsV3.searchProducts(affectiveSearchOptions);
|
|
42
|
+
productsSignal.set(result.products ?? []);
|
|
43
|
+
pagingMetadataSignal.set(result.pagingMetadata);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
errorSignal.set(error instanceof Error ? error.message : "Unknown error");
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
isLoadingSignal.set(false);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
firstRun = false;
|
|
54
|
+
return {
|
|
55
|
+
products: productsSignal,
|
|
56
|
+
searchOptions: searchOptionsSignal,
|
|
57
|
+
pagingMetadata: pagingMetadataSignal,
|
|
58
|
+
aggregations: aggregationsSignal,
|
|
59
|
+
setSearchOptions: (searchOptions) => searchOptionsSignal.set(searchOptions),
|
|
60
|
+
isLoading: isLoadingSignal,
|
|
61
|
+
error: errorSignal,
|
|
62
|
+
};
|
|
63
|
+
});
|