@wix/headless-stores 0.0.9 → 0.0.11
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/enums/index.d.ts +2 -0
- package/cjs/dist/enums/index.js +18 -0
- package/cjs/dist/enums/social-platform-enums.d.ts +25 -0
- package/cjs/dist/enums/social-platform-enums.js +30 -0
- package/cjs/dist/enums/sort-enums.d.ts +17 -0
- package/cjs/dist/enums/sort-enums.js +21 -0
- package/cjs/dist/react/BuyNow.d.ts +2 -4
- package/cjs/dist/react/Category.d.ts +15 -0
- package/cjs/dist/react/Category.js +22 -0
- package/cjs/dist/react/Collection.d.ts +151 -0
- package/cjs/dist/react/Collection.js +209 -0
- package/cjs/dist/react/FilteredCollection.d.ts +95 -0
- package/cjs/dist/react/FilteredCollection.js +150 -0
- package/cjs/dist/react/PayNow.d.ts +2 -4
- package/cjs/dist/react/Product.d.ts +43 -0
- package/cjs/dist/react/Product.js +35 -0
- package/cjs/dist/react/ProductActions.d.ts +42 -0
- package/cjs/dist/react/ProductActions.js +83 -0
- package/cjs/dist/react/ProductModifiers.d.ts +164 -0
- package/cjs/dist/react/ProductModifiers.js +168 -0
- package/cjs/dist/react/ProductVariantSelector.d.ts +153 -0
- package/cjs/dist/react/ProductVariantSelector.js +138 -0
- package/cjs/dist/react/RelatedProducts.d.ts +64 -0
- package/cjs/dist/react/RelatedProducts.js +73 -0
- package/cjs/dist/react/SelectedVariant.d.ts +66 -0
- package/cjs/dist/react/SelectedVariant.js +52 -0
- package/cjs/dist/react/SocialSharing.d.ts +112 -0
- package/cjs/dist/react/SocialSharing.js +86 -0
- package/cjs/dist/react/Sort.d.ts +14 -0
- package/cjs/dist/react/Sort.js +17 -0
- package/cjs/dist/react/index.d.ts +11 -0
- package/cjs/dist/react/index.js +34 -0
- package/cjs/dist/services/buy-now-service.js +2 -2
- package/cjs/dist/services/catalog-options-service.d.ts +30 -0
- package/cjs/dist/services/catalog-options-service.js +156 -0
- package/cjs/dist/services/catalog-price-range-service.d.ts +23 -0
- package/cjs/dist/services/catalog-price-range-service.js +97 -0
- package/cjs/dist/services/category-service.d.ts +26 -0
- package/cjs/dist/services/category-service.js +71 -0
- package/cjs/dist/services/collection-service.d.ts +37 -0
- package/cjs/dist/services/collection-service.js +569 -0
- package/cjs/dist/services/filter-service.d.ts +56 -0
- package/cjs/dist/services/filter-service.js +147 -0
- package/cjs/dist/services/product-media-gallery-service.d.ts +25 -0
- package/cjs/dist/services/product-media-gallery-service.js +105 -0
- package/cjs/dist/services/product-modifiers-service.d.ts +34 -0
- package/cjs/dist/services/product-modifiers-service.js +111 -0
- package/cjs/dist/services/product-service.d.ts +28 -0
- package/cjs/dist/services/product-service.js +68 -0
- package/cjs/dist/services/related-products-service.d.ts +25 -0
- package/cjs/dist/services/related-products-service.js +54 -0
- package/cjs/dist/services/selected-variant-service.d.ts +59 -0
- package/cjs/dist/services/selected-variant-service.js +541 -0
- package/cjs/dist/services/social-sharing-service.d.ts +41 -0
- package/cjs/dist/services/social-sharing-service.js +141 -0
- package/cjs/dist/services/sort-service.d.ts +20 -0
- package/cjs/dist/services/sort-service.js +32 -0
- package/cjs/dist/utils/url-params.d.ts +5 -0
- package/cjs/dist/utils/url-params.js +50 -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/BuyNow.d.ts +2 -4
- package/dist/react/Category.d.ts +15 -0
- package/dist/react/Category.js +18 -0
- package/dist/react/Collection.d.ts +151 -0
- package/dist/react/Collection.js +201 -0
- package/dist/react/FilteredCollection.d.ts +95 -0
- package/dist/react/FilteredCollection.js +140 -0
- package/dist/react/PayNow.d.ts +2 -4
- package/dist/react/Product.d.ts +43 -0
- package/dist/react/Product.js +30 -0
- package/dist/react/ProductActions.d.ts +42 -0
- package/dist/react/ProductActions.js +79 -0
- package/dist/react/ProductModifiers.d.ts +164 -0
- package/dist/react/ProductModifiers.js +160 -0
- package/dist/react/ProductVariantSelector.d.ts +153 -0
- package/dist/react/ProductVariantSelector.js +130 -0
- package/dist/react/RelatedProducts.d.ts +64 -0
- package/dist/react/RelatedProducts.js +65 -0
- package/dist/react/SelectedVariant.d.ts +66 -0
- package/dist/react/SelectedVariant.js +46 -0
- package/dist/react/SocialSharing.d.ts +112 -0
- package/dist/react/SocialSharing.js +77 -0
- package/dist/react/Sort.d.ts +14 -0
- package/dist/react/Sort.js +14 -0
- package/dist/react/index.d.ts +11 -0
- package/dist/react/index.js +11 -0
- package/dist/services/buy-now-service.js +2 -2
- package/dist/services/catalog-options-service.d.ts +30 -0
- package/dist/services/catalog-options-service.js +152 -0
- package/dist/services/catalog-price-range-service.d.ts +23 -0
- package/dist/services/catalog-price-range-service.js +93 -0
- package/dist/services/category-service.d.ts +26 -0
- package/dist/services/category-service.js +67 -0
- package/dist/services/collection-service.d.ts +37 -0
- package/dist/services/collection-service.js +532 -0
- package/dist/services/filter-service.d.ts +56 -0
- package/dist/services/filter-service.js +144 -0
- package/dist/services/product-media-gallery-service.d.ts +25 -0
- package/dist/services/product-media-gallery-service.js +101 -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 +28 -0
- package/dist/services/product-service.js +64 -0
- package/dist/services/related-products-service.d.ts +25 -0
- package/dist/services/related-products-service.js +50 -0
- package/dist/services/selected-variant-service.d.ts +59 -0
- package/dist/services/selected-variant-service.js +538 -0
- package/dist/services/social-sharing-service.d.ts +41 -0
- package/dist/services/social-sharing-service.js +137 -0
- package/dist/services/sort-service.d.ts +20 -0
- package/dist/services/sort-service.js +29 -0
- package/dist/utils/url-params.d.ts +5 -0
- package/dist/utils/url-params.js +46 -0
- package/package.json +8 -1
- package/dist/astro/BuyNowServiceContext.d.ts +0 -2
- package/dist/astro/BuyNowServiceContext.js +0 -6
- package/dist/astro/ManagerProviderContext.d.ts +0 -2
- package/dist/astro/ManagerProviderContext.js +0 -7
- package/dist/astro/withBuyButtonService.d.ts +0 -2
- package/dist/astro/withBuyButtonService.js +0 -16
- package/dist/react/CurrentCartServiceProvider.d.ts +0 -5
- package/dist/react/CurrentCartServiceProvider.js +0 -12
- package/dist/react/VariantSelectorServiceProvider.d.ts +0 -7
- package/dist/react/VariantSelectorServiceProvider.js +0 -22
- package/dist/react/hookim/index.d.ts +0 -5
- package/dist/react/hookim/index.js +0 -22
- package/dist/services/CurrentCartService.d.ts +0 -18
- package/dist/services/CurrentCartService.js +0 -9
- package/dist/services/VariantSelectorServices.d.ts +0 -8
- package/dist/services/VariantSelectorServices.js +0 -20
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { useService } from '@wix/services-manager-react';
|
|
2
|
+
import { CollectionServiceDefinition } from '../services/collection-service';
|
|
3
|
+
import { InventoryAvailabilityStatus, } from '@wix/auto_sdk_stores_products-v-3';
|
|
4
|
+
/**
|
|
5
|
+
* Headless component for product grid
|
|
6
|
+
*
|
|
7
|
+
* @component
|
|
8
|
+
*/
|
|
9
|
+
export const Grid = (props) => {
|
|
10
|
+
const service = useService(CollectionServiceDefinition);
|
|
11
|
+
// Debug logging to help identify service issues
|
|
12
|
+
if (!service) {
|
|
13
|
+
console.error('CollectionService is undefined');
|
|
14
|
+
return props.children({
|
|
15
|
+
products: [],
|
|
16
|
+
isLoading: false,
|
|
17
|
+
error: 'Service not available',
|
|
18
|
+
isEmpty: true,
|
|
19
|
+
totalProducts: 0,
|
|
20
|
+
hasProducts: false,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
// Safely access service properties with error handling
|
|
24
|
+
try {
|
|
25
|
+
const productList = service.products?.get() || [];
|
|
26
|
+
const isLoading = service.isLoading?.get() || false;
|
|
27
|
+
const error = service.error?.get() || null;
|
|
28
|
+
const totalProducts = service.totalProducts?.get() || 0;
|
|
29
|
+
const hasProducts = service.hasProducts?.get() || false;
|
|
30
|
+
return props.children({
|
|
31
|
+
products: productList,
|
|
32
|
+
isLoading,
|
|
33
|
+
error,
|
|
34
|
+
isEmpty: !hasProducts && !isLoading,
|
|
35
|
+
totalProducts,
|
|
36
|
+
hasProducts,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
console.error('Error accessing service properties:', err);
|
|
41
|
+
return props.children({
|
|
42
|
+
products: [],
|
|
43
|
+
isLoading: false,
|
|
44
|
+
error: 'Failed to load products',
|
|
45
|
+
isEmpty: true,
|
|
46
|
+
totalProducts: 0,
|
|
47
|
+
hasProducts: false,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Headless component for individual product item
|
|
53
|
+
*
|
|
54
|
+
* @component
|
|
55
|
+
*/
|
|
56
|
+
export const Item = (props) => {
|
|
57
|
+
const { product } = props;
|
|
58
|
+
// Use actual v3 API structure based on real data
|
|
59
|
+
// Images are in media.main.image, not media.itemsInfo.items
|
|
60
|
+
const image = product?.media?.main?.image || null;
|
|
61
|
+
// Create formatted price since formattedAmount is not available
|
|
62
|
+
const rawAmount = product.actualPriceRange?.minValue?.amount;
|
|
63
|
+
const price = rawAmount ? `$${rawAmount}` : '$0.00';
|
|
64
|
+
// Create formatted compare-at price
|
|
65
|
+
const rawCompareAmount = product.compareAtPriceRange?.minValue?.amount;
|
|
66
|
+
const compareAtPrice = rawCompareAmount ? `$${rawCompareAmount}` : null;
|
|
67
|
+
const availabilityStatus = product.inventory?.availabilityStatus;
|
|
68
|
+
const available = availabilityStatus === InventoryAvailabilityStatus.IN_STOCK ||
|
|
69
|
+
availabilityStatus === InventoryAvailabilityStatus.PARTIALLY_OUT_OF_STOCK;
|
|
70
|
+
const description = typeof product.description === 'string' ? product.description : '';
|
|
71
|
+
return props.children({
|
|
72
|
+
id: product._id || '',
|
|
73
|
+
title: product.name || '',
|
|
74
|
+
slug: product.slug || '',
|
|
75
|
+
image,
|
|
76
|
+
price,
|
|
77
|
+
compareAtPrice,
|
|
78
|
+
description,
|
|
79
|
+
available,
|
|
80
|
+
href: `/store/products/${product.slug}`,
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Headless component for load more products functionality
|
|
85
|
+
* Note: V3 API uses simplified loading without traditional pagination
|
|
86
|
+
*
|
|
87
|
+
* @component
|
|
88
|
+
*/
|
|
89
|
+
export const LoadMore = (props) => {
|
|
90
|
+
const service = useService(CollectionServiceDefinition);
|
|
91
|
+
// Error handling for undefined service
|
|
92
|
+
if (!service) {
|
|
93
|
+
console.error('CollectionService is undefined in LoadMore');
|
|
94
|
+
return props.children({
|
|
95
|
+
loadMore: async () => { },
|
|
96
|
+
refresh: async () => { },
|
|
97
|
+
isLoading: false,
|
|
98
|
+
hasProducts: false,
|
|
99
|
+
totalProducts: 0,
|
|
100
|
+
hasMoreProducts: false,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const isLoading = service.isLoading?.get() || false;
|
|
105
|
+
const hasProducts = service.hasProducts?.get() || false;
|
|
106
|
+
const totalProducts = service.totalProducts?.get() || 0;
|
|
107
|
+
const hasMoreProducts = service.hasMoreProducts?.get() || false;
|
|
108
|
+
return props.children({
|
|
109
|
+
loadMore: service.loadMore || (async () => { }),
|
|
110
|
+
refresh: service.refresh || (async () => { }),
|
|
111
|
+
isLoading,
|
|
112
|
+
hasProducts,
|
|
113
|
+
totalProducts,
|
|
114
|
+
hasMoreProducts,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
console.error('Error in LoadMore:', err);
|
|
119
|
+
return props.children({
|
|
120
|
+
loadMore: async () => { },
|
|
121
|
+
refresh: async () => { },
|
|
122
|
+
isLoading: false,
|
|
123
|
+
hasProducts: false,
|
|
124
|
+
totalProducts: 0,
|
|
125
|
+
hasMoreProducts: false,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Headless component for collection header with product count
|
|
131
|
+
*
|
|
132
|
+
* @component
|
|
133
|
+
*/
|
|
134
|
+
export const Header = (props) => {
|
|
135
|
+
const service = useService(CollectionServiceDefinition);
|
|
136
|
+
// Error handling for undefined service
|
|
137
|
+
if (!service) {
|
|
138
|
+
console.error('CollectionService is undefined in Header');
|
|
139
|
+
return props.children({
|
|
140
|
+
totalProducts: 0,
|
|
141
|
+
isLoading: false,
|
|
142
|
+
hasProducts: false,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
const totalProducts = service.totalProducts?.get() || 0;
|
|
147
|
+
const isLoading = service.isLoading?.get() || false;
|
|
148
|
+
const hasProducts = service.hasProducts?.get() || false;
|
|
149
|
+
return props.children({
|
|
150
|
+
totalProducts,
|
|
151
|
+
isLoading,
|
|
152
|
+
hasProducts,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
console.error('Error in Header:', err);
|
|
157
|
+
return props.children({
|
|
158
|
+
totalProducts: 0,
|
|
159
|
+
isLoading: false,
|
|
160
|
+
hasProducts: false,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Headless component for collection actions (refresh, load more)
|
|
166
|
+
* Replaces traditional pagination for V3 API
|
|
167
|
+
*
|
|
168
|
+
* @component
|
|
169
|
+
*/
|
|
170
|
+
export const Actions = (props) => {
|
|
171
|
+
const service = useService(CollectionServiceDefinition);
|
|
172
|
+
// Error handling for undefined service
|
|
173
|
+
if (!service) {
|
|
174
|
+
console.error('CollectionService is undefined in Actions');
|
|
175
|
+
return props.children({
|
|
176
|
+
refresh: async () => { },
|
|
177
|
+
loadMore: async () => { },
|
|
178
|
+
isLoading: false,
|
|
179
|
+
error: 'Service not available',
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
const isLoading = service.isLoading?.get() || false;
|
|
184
|
+
const error = service.error?.get() || null;
|
|
185
|
+
return props.children({
|
|
186
|
+
refresh: service.refresh || (async () => { }),
|
|
187
|
+
loadMore: service.loadMore || (async () => { }),
|
|
188
|
+
isLoading,
|
|
189
|
+
error,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
console.error('Error in Actions:', err);
|
|
194
|
+
return props.children({
|
|
195
|
+
refresh: async () => { },
|
|
196
|
+
loadMore: async () => { },
|
|
197
|
+
isLoading: false,
|
|
198
|
+
error: 'Failed to load actions',
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
import { type AvailableOptions, type FilterServiceAPI, type Filter } from '../services/filter-service';
|
|
3
|
+
import { type V3Product } from '@wix/auto_sdk_stores_products-v-3';
|
|
4
|
+
import { type CollectionServiceAPI } from '../services/collection-service';
|
|
5
|
+
export interface FilteredCollectionProviderProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Headless component for providing a filtered collection
|
|
10
|
+
*
|
|
11
|
+
* @component
|
|
12
|
+
*/
|
|
13
|
+
export declare const Provider: React.FC<FilteredCollectionProviderProps>;
|
|
14
|
+
export declare const useFilteredCollection: () => {
|
|
15
|
+
filter: FilterServiceAPI | null;
|
|
16
|
+
collection: CollectionServiceAPI | null;
|
|
17
|
+
};
|
|
18
|
+
export interface FiltersLoadingProps {
|
|
19
|
+
children: (data: {
|
|
20
|
+
isFullyLoaded: boolean;
|
|
21
|
+
}) => ReactNode;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Headless component for displaying a loading state for filters
|
|
25
|
+
*
|
|
26
|
+
* @component
|
|
27
|
+
*/
|
|
28
|
+
export declare const FiltersLoading: React.FC<FiltersLoadingProps>;
|
|
29
|
+
export interface FilteredGridProps {
|
|
30
|
+
children: (data: {
|
|
31
|
+
products: V3Product[];
|
|
32
|
+
totalProducts: number;
|
|
33
|
+
isLoading: boolean;
|
|
34
|
+
error: string | null;
|
|
35
|
+
isEmpty: boolean;
|
|
36
|
+
hasMoreProducts: boolean;
|
|
37
|
+
}) => ReactNode;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Headless component for displaying a grid of filtered products
|
|
41
|
+
*
|
|
42
|
+
* @component
|
|
43
|
+
*/
|
|
44
|
+
export declare const Grid: React.FC<FilteredGridProps>;
|
|
45
|
+
export interface FilteredItemProps {
|
|
46
|
+
product: V3Product;
|
|
47
|
+
children: (data: {
|
|
48
|
+
title: string;
|
|
49
|
+
image: string | null;
|
|
50
|
+
imageAltText: string | null;
|
|
51
|
+
price: string;
|
|
52
|
+
compareAtPrice: string | null;
|
|
53
|
+
available: boolean;
|
|
54
|
+
slug: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
}) => ReactNode;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Headless component for displaying an individual product item
|
|
60
|
+
*
|
|
61
|
+
* @component
|
|
62
|
+
*/
|
|
63
|
+
export declare const Item: React.FC<FilteredItemProps>;
|
|
64
|
+
export interface FilteredLoadMoreProps {
|
|
65
|
+
children: (data: {
|
|
66
|
+
loadMore: () => Promise<void>;
|
|
67
|
+
refresh: () => Promise<void>;
|
|
68
|
+
isLoading: boolean;
|
|
69
|
+
hasProducts: boolean;
|
|
70
|
+
totalProducts: number;
|
|
71
|
+
hasMoreProducts: boolean;
|
|
72
|
+
}) => ReactNode;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Headless component for displaying a load more button
|
|
76
|
+
*
|
|
77
|
+
* @component
|
|
78
|
+
*/
|
|
79
|
+
export declare const LoadMore: React.FC<FilteredLoadMoreProps>;
|
|
80
|
+
export interface FilteredFiltersProps {
|
|
81
|
+
children: (data: {
|
|
82
|
+
applyFilters: (filters: Filter) => void;
|
|
83
|
+
clearFilters: () => void;
|
|
84
|
+
currentFilters: Filter;
|
|
85
|
+
allProducts: V3Product[];
|
|
86
|
+
availableOptions: AvailableOptions;
|
|
87
|
+
isFiltered: boolean;
|
|
88
|
+
}) => ReactNode;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Headless component for displaying a filters component
|
|
92
|
+
*
|
|
93
|
+
* @component
|
|
94
|
+
*/
|
|
95
|
+
export declare const Filters: React.FC<FilteredFiltersProps>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
|
+
import { FilterServiceDefinition, } from '../services/filter-service';
|
|
4
|
+
import { useService } from '@wix/services-manager-react';
|
|
5
|
+
import { InventoryAvailabilityStatus, } from '@wix/auto_sdk_stores_products-v-3';
|
|
6
|
+
import { CollectionServiceDefinition, } from '../services/collection-service';
|
|
7
|
+
const FilteredCollectionContext = createContext({ filter: null, collection: null });
|
|
8
|
+
/**
|
|
9
|
+
* Headless component for providing a filtered collection
|
|
10
|
+
*
|
|
11
|
+
* @component
|
|
12
|
+
*/
|
|
13
|
+
export const Provider = ({ children, }) => {
|
|
14
|
+
const filter = useService(FilterServiceDefinition);
|
|
15
|
+
const collection = useService(CollectionServiceDefinition);
|
|
16
|
+
return (_jsx(FilteredCollectionContext.Provider, { value: { filter, collection }, children: children }));
|
|
17
|
+
};
|
|
18
|
+
export const useFilteredCollection = () => {
|
|
19
|
+
const context = useContext(FilteredCollectionContext);
|
|
20
|
+
if (!context) {
|
|
21
|
+
throw new Error('useFilteredCollection must be used within a FilteredCollectionProvider');
|
|
22
|
+
}
|
|
23
|
+
return context;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Headless component for displaying a loading state for filters
|
|
27
|
+
*
|
|
28
|
+
* @component
|
|
29
|
+
*/
|
|
30
|
+
export const FiltersLoading = ({ children }) => {
|
|
31
|
+
const { filter } = useFilteredCollection();
|
|
32
|
+
const isFullyLoaded = filter.isFullyLoaded.get();
|
|
33
|
+
return _jsx(_Fragment, { children: children({ isFullyLoaded }) });
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Headless component for displaying a grid of filtered products
|
|
37
|
+
*
|
|
38
|
+
* @component
|
|
39
|
+
*/
|
|
40
|
+
export const Grid = ({ children }) => {
|
|
41
|
+
const { collection } = useFilteredCollection();
|
|
42
|
+
const products = collection.products.get() || [];
|
|
43
|
+
const totalProducts = collection.totalProducts.get();
|
|
44
|
+
const isLoading = collection.isLoading.get();
|
|
45
|
+
const error = collection.error.get();
|
|
46
|
+
const hasProducts = collection.hasProducts.get();
|
|
47
|
+
const hasMoreProducts = collection.hasMoreProducts.get();
|
|
48
|
+
return (_jsx(_Fragment, { children: children({
|
|
49
|
+
products,
|
|
50
|
+
isLoading,
|
|
51
|
+
error,
|
|
52
|
+
isEmpty: !hasProducts,
|
|
53
|
+
totalProducts,
|
|
54
|
+
hasMoreProducts,
|
|
55
|
+
}) }));
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Headless component for displaying an individual product item
|
|
59
|
+
*
|
|
60
|
+
* @component
|
|
61
|
+
*/
|
|
62
|
+
export const Item = ({ product, children }) => {
|
|
63
|
+
// Safe conversion of product data with type safety guards
|
|
64
|
+
const title = String(product.name || '');
|
|
65
|
+
const image = product.media?.main?.image || null;
|
|
66
|
+
const imageAltText = product.media?.main?.altText || '';
|
|
67
|
+
const price = product.actualPriceRange?.minValue?.formattedAmount ||
|
|
68
|
+
product.actualPriceRange?.maxValue?.formattedAmount ||
|
|
69
|
+
(product.actualPriceRange?.minValue?.amount
|
|
70
|
+
? `$${product.actualPriceRange.minValue.amount}`
|
|
71
|
+
: '$0.00');
|
|
72
|
+
// Add compare at price
|
|
73
|
+
const compareAtPrice = product.compareAtPriceRange?.minValue?.formattedAmount ||
|
|
74
|
+
(product.compareAtPriceRange?.minValue?.amount
|
|
75
|
+
? `$${product.compareAtPriceRange.minValue.amount}`
|
|
76
|
+
: null);
|
|
77
|
+
const availabilityStatus = product.inventory?.availabilityStatus;
|
|
78
|
+
const available = availabilityStatus === InventoryAvailabilityStatus.IN_STOCK ||
|
|
79
|
+
availabilityStatus === InventoryAvailabilityStatus.PARTIALLY_OUT_OF_STOCK;
|
|
80
|
+
const slug = String(product.slug || product._id || '');
|
|
81
|
+
const description = product.plainDescription
|
|
82
|
+
? String(product.plainDescription)
|
|
83
|
+
: undefined;
|
|
84
|
+
return (_jsx(_Fragment, { children: children({
|
|
85
|
+
title,
|
|
86
|
+
image,
|
|
87
|
+
imageAltText,
|
|
88
|
+
price: String(price),
|
|
89
|
+
compareAtPrice,
|
|
90
|
+
available,
|
|
91
|
+
slug,
|
|
92
|
+
description,
|
|
93
|
+
}) }));
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Headless component for displaying a load more button
|
|
97
|
+
*
|
|
98
|
+
* @component
|
|
99
|
+
*/
|
|
100
|
+
export const LoadMore = ({ children }) => {
|
|
101
|
+
const { collection } = useFilteredCollection();
|
|
102
|
+
const loadMore = collection.loadMore;
|
|
103
|
+
const refresh = collection.refresh;
|
|
104
|
+
const isLoading = collection.isLoading.get();
|
|
105
|
+
const hasProducts = collection.hasProducts.get();
|
|
106
|
+
const totalProducts = collection.totalProducts.get();
|
|
107
|
+
const hasMoreProducts = collection.hasMoreProducts.get();
|
|
108
|
+
return (_jsx(_Fragment, { children: children({
|
|
109
|
+
loadMore,
|
|
110
|
+
refresh,
|
|
111
|
+
isLoading,
|
|
112
|
+
hasProducts,
|
|
113
|
+
totalProducts,
|
|
114
|
+
hasMoreProducts,
|
|
115
|
+
}) }));
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Headless component for displaying a filters component
|
|
119
|
+
*
|
|
120
|
+
* @component
|
|
121
|
+
*/
|
|
122
|
+
export const Filters = ({ children }) => {
|
|
123
|
+
const { collection, filter } = useFilteredCollection();
|
|
124
|
+
const applyFilters = filter.applyFilters;
|
|
125
|
+
const clearFilters = filter.clearFilters;
|
|
126
|
+
const currentFilters = filter.currentFilters.get();
|
|
127
|
+
const allProducts = collection.products.get();
|
|
128
|
+
const availableOptions = filter.availableOptions.get();
|
|
129
|
+
const isFiltered = currentFilters.priceRange.min !== availableOptions.priceRange.min ||
|
|
130
|
+
currentFilters.priceRange.max !== availableOptions.priceRange.max ||
|
|
131
|
+
Object.keys(currentFilters.selectedOptions).length > 0;
|
|
132
|
+
return (_jsx(_Fragment, { children: children({
|
|
133
|
+
applyFilters,
|
|
134
|
+
clearFilters,
|
|
135
|
+
currentFilters,
|
|
136
|
+
allProducts,
|
|
137
|
+
availableOptions,
|
|
138
|
+
isFiltered,
|
|
139
|
+
}) }));
|
|
140
|
+
};
|
package/dist/react/PayNow.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export type PayNowRedirectToCheckout = () => void;
|
|
2
1
|
/**
|
|
3
2
|
* Props passed to the render function of the PayNow component
|
|
4
3
|
*/
|
|
@@ -6,17 +5,16 @@ export interface PayNowRenderProps {
|
|
|
6
5
|
/** Whether the buy now operation is currently loading */
|
|
7
6
|
isLoading: boolean;
|
|
8
7
|
/** Function to redirect the user to the checkout page */
|
|
9
|
-
redirectToCheckout:
|
|
8
|
+
redirectToCheckout: () => void;
|
|
10
9
|
/** The error message if the buy now operation fails */
|
|
11
10
|
error: string | null;
|
|
12
11
|
}
|
|
13
|
-
export type PayNowChildren = (props: PayNowRenderProps) => React.ReactNode;
|
|
14
12
|
/**
|
|
15
13
|
* Props for the PayNow component
|
|
16
14
|
*/
|
|
17
15
|
export interface PayNowProps {
|
|
18
16
|
/** Render function that receives buy now state and actions */
|
|
19
|
-
children:
|
|
17
|
+
children: (props: PayNowRenderProps) => React.ReactNode;
|
|
20
18
|
}
|
|
21
19
|
/**
|
|
22
20
|
* A headless component that provides pay now functionality using the render props pattern.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { V3Product } from '@wix/auto_sdk_stores_products-v-3';
|
|
2
|
+
/**
|
|
3
|
+
* Props for ProductName headless component
|
|
4
|
+
*/
|
|
5
|
+
export interface ProductNameProps {
|
|
6
|
+
/** Render prop function that receives product name data */
|
|
7
|
+
children: (props: ProductNameRenderProps) => React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Render props for ProductName component
|
|
11
|
+
*/
|
|
12
|
+
export interface ProductNameRenderProps {
|
|
13
|
+
/** Product name */
|
|
14
|
+
name: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Headless component for product name display
|
|
18
|
+
*
|
|
19
|
+
* @component
|
|
20
|
+
*/
|
|
21
|
+
export declare const Name: (props: ProductNameProps) => import("react").ReactNode;
|
|
22
|
+
/**
|
|
23
|
+
* Props for ProductDescription headless component
|
|
24
|
+
*/
|
|
25
|
+
export interface ProductDescriptionProps {
|
|
26
|
+
/** Render prop function that receives product description data */
|
|
27
|
+
children: (props: ProductDescriptionRenderProps) => React.ReactNode;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Render props for ProductDescription component
|
|
31
|
+
*/
|
|
32
|
+
export interface ProductDescriptionRenderProps {
|
|
33
|
+
/** Product description (may contain HTML) */
|
|
34
|
+
description: NonNullable<V3Product['description']>;
|
|
35
|
+
/** Product plain description */
|
|
36
|
+
plainDescription: NonNullable<V3Product['plainDescription']>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Headless component for product description display
|
|
40
|
+
*
|
|
41
|
+
* @component
|
|
42
|
+
*/
|
|
43
|
+
export declare const Description: (props: ProductDescriptionProps) => import("react").ReactNode;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useService } from '@wix/services-manager-react';
|
|
2
|
+
import { ProductServiceDefinition } from '../services/product-service';
|
|
3
|
+
/**
|
|
4
|
+
* Headless component for product name display
|
|
5
|
+
*
|
|
6
|
+
* @component
|
|
7
|
+
*/
|
|
8
|
+
export const Name = (props) => {
|
|
9
|
+
const service = useService(ProductServiceDefinition);
|
|
10
|
+
const product = service.product.get();
|
|
11
|
+
const name = product.name;
|
|
12
|
+
return props.children({
|
|
13
|
+
name,
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Headless component for product description display
|
|
18
|
+
*
|
|
19
|
+
* @component
|
|
20
|
+
*/
|
|
21
|
+
export const Description = (props) => {
|
|
22
|
+
const service = useService(ProductServiceDefinition);
|
|
23
|
+
const product = service.product.get();
|
|
24
|
+
const descriptionRichContent = product.description;
|
|
25
|
+
const plainDescription = product.plainDescription;
|
|
26
|
+
return props.children({
|
|
27
|
+
description: descriptionRichContent,
|
|
28
|
+
plainDescription: plainDescription,
|
|
29
|
+
});
|
|
30
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Props for Actions headless component
|
|
3
|
+
*/
|
|
4
|
+
export interface ActionsProps {
|
|
5
|
+
/** Quantity to add (optional) */
|
|
6
|
+
quantity?: number;
|
|
7
|
+
/** Render prop function that receives actions data */
|
|
8
|
+
children: (props: ActionsRenderProps) => React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Render props for Actions component
|
|
12
|
+
*/
|
|
13
|
+
export interface ActionsRenderProps {
|
|
14
|
+
/** Function to add product to cart */
|
|
15
|
+
onAddToCart: () => Promise<void>;
|
|
16
|
+
/** Function to buy now (clear cart, add product, proceed to checkout) */
|
|
17
|
+
onBuyNow: () => Promise<void>;
|
|
18
|
+
/** Function to open cart */
|
|
19
|
+
onOpenCart: () => void;
|
|
20
|
+
/** Whether add to cart is available */
|
|
21
|
+
canAddToCart: boolean;
|
|
22
|
+
/** Whether add to cart is currently loading */
|
|
23
|
+
isLoading: boolean;
|
|
24
|
+
/** Current variant price */
|
|
25
|
+
price: string;
|
|
26
|
+
/** Whether variant is in stock */
|
|
27
|
+
inStock: boolean;
|
|
28
|
+
/** Whether pre-order is enabled */
|
|
29
|
+
isPreOrderEnabled: boolean;
|
|
30
|
+
/** Pre-order message */
|
|
31
|
+
preOrderMessage: string | null;
|
|
32
|
+
/** Error message if any */
|
|
33
|
+
error: string | null;
|
|
34
|
+
/** Available quantity */
|
|
35
|
+
availableQuantity: number | null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Headless component for product actions (add to cart, buy now)
|
|
39
|
+
*
|
|
40
|
+
* @component
|
|
41
|
+
*/
|
|
42
|
+
export declare const Actions: (props: ActionsProps) => import("react").ReactNode;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useService } from '@wix/services-manager-react';
|
|
2
|
+
import { SelectedVariantServiceDefinition } from '../services/selected-variant-service';
|
|
3
|
+
import { ProductModifiersServiceDefinition } from '../services/product-modifiers-service';
|
|
4
|
+
/**
|
|
5
|
+
* Headless component for product actions (add to cart, buy now)
|
|
6
|
+
*
|
|
7
|
+
* @component
|
|
8
|
+
*/
|
|
9
|
+
export const Actions = (props) => {
|
|
10
|
+
const variantService = useService(SelectedVariantServiceDefinition);
|
|
11
|
+
// const cartService = useService(CurrentCartServiceDefinition) as ServiceAPI<
|
|
12
|
+
// typeof CurrentCartServiceDefinition
|
|
13
|
+
// >;
|
|
14
|
+
// Try to get modifiers service - it may not exist for all products
|
|
15
|
+
let modifiersService = null;
|
|
16
|
+
try {
|
|
17
|
+
modifiersService = useService(ProductModifiersServiceDefinition);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Modifiers service not available for this product
|
|
21
|
+
modifiersService = null;
|
|
22
|
+
}
|
|
23
|
+
const price = variantService.currentPrice.get();
|
|
24
|
+
const inStock = variantService.isInStock.get();
|
|
25
|
+
const isPreOrderEnabled = variantService.isPreOrderEnabled.get();
|
|
26
|
+
const preOrderMessage = variantService.preOrderMessage.get();
|
|
27
|
+
const isLoading = variantService.isLoading.get();
|
|
28
|
+
const error = variantService.error.get();
|
|
29
|
+
const availableQuantity = variantService.quantityAvailable.get();
|
|
30
|
+
const quantity = variantService.selectedQuantity.get();
|
|
31
|
+
// Check if all required modifiers are filled
|
|
32
|
+
const areAllRequiredModifiersFilled = modifiersService
|
|
33
|
+
? modifiersService.areAllRequiredModifiersFilled()
|
|
34
|
+
: true; // If no modifiers service, assume no required modifiers
|
|
35
|
+
const canAddToCart = (inStock || isPreOrderEnabled) &&
|
|
36
|
+
!isLoading &&
|
|
37
|
+
areAllRequiredModifiersFilled;
|
|
38
|
+
const onAddToCart = async () => {
|
|
39
|
+
// Get modifiers data if available
|
|
40
|
+
let modifiersData;
|
|
41
|
+
if (modifiersService) {
|
|
42
|
+
const selectedModifiers = modifiersService.selectedModifiers.get();
|
|
43
|
+
if (Object.keys(selectedModifiers).length > 0) {
|
|
44
|
+
modifiersData = selectedModifiers;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
await variantService.addToCart(quantity, modifiersData);
|
|
48
|
+
};
|
|
49
|
+
const onBuyNow = async () => {
|
|
50
|
+
try {
|
|
51
|
+
// Clear the cart first
|
|
52
|
+
// await cartService.clearCart();
|
|
53
|
+
// Add the product to cart
|
|
54
|
+
await onAddToCart();
|
|
55
|
+
// Proceed to checkout
|
|
56
|
+
// await cartService.proceedToCheckout();
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
console.error('Buy now failed:', error);
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const onOpenCart = () => {
|
|
64
|
+
// cartService.openCart();
|
|
65
|
+
};
|
|
66
|
+
return props.children({
|
|
67
|
+
onAddToCart,
|
|
68
|
+
onBuyNow,
|
|
69
|
+
onOpenCart,
|
|
70
|
+
canAddToCart,
|
|
71
|
+
isLoading,
|
|
72
|
+
price,
|
|
73
|
+
inStock,
|
|
74
|
+
isPreOrderEnabled,
|
|
75
|
+
preOrderMessage,
|
|
76
|
+
error,
|
|
77
|
+
availableQuantity,
|
|
78
|
+
});
|
|
79
|
+
};
|