@wix/headless-stores 0.0.8 → 0.0.10
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/BuyNow.d.ts +1 -0
- package/cjs/dist/react/BuyNow.js +1 -0
- package/cjs/dist/react/Category.d.ts +17 -0
- package/cjs/dist/react/Category.js +37 -0
- package/cjs/dist/react/Collection.d.ts +141 -0
- package/cjs/dist/react/Collection.js +198 -0
- package/cjs/dist/react/FilteredCollection.d.ts +65 -0
- package/cjs/dist/react/FilteredCollection.js +117 -0
- package/cjs/dist/react/PayNow.d.ts +1 -0
- package/cjs/dist/react/PayNow.js +1 -0
- package/cjs/dist/react/Product.d.ts +70 -0
- package/cjs/dist/react/Product.js +56 -0
- package/cjs/dist/react/ProductMediaGallery.d.ts +128 -0
- package/cjs/dist/react/ProductMediaGallery.js +100 -0
- package/cjs/dist/react/ProductModifiers.d.ts +156 -0
- package/cjs/dist/react/ProductModifiers.js +159 -0
- package/cjs/dist/react/ProductVariantSelector.d.ts +169 -0
- package/cjs/dist/react/ProductVariantSelector.js +166 -0
- package/cjs/dist/react/RelatedProducts.d.ts +60 -0
- package/cjs/dist/react/RelatedProducts.js +68 -0
- package/cjs/dist/react/SocialSharing.d.ts +119 -0
- package/cjs/dist/react/SocialSharing.js +80 -0
- package/cjs/dist/react/Sort.d.ts +17 -0
- package/cjs/dist/react/Sort.js +41 -0
- package/cjs/dist/react/index.d.ts +10 -0
- package/cjs/dist/react/index.js +33 -0
- package/cjs/dist/services/catalog-options-service.d.ts +30 -0
- package/cjs/dist/services/catalog-options-service.js +162 -0
- package/cjs/dist/services/catalog-price-range-service.d.ts +23 -0
- package/cjs/dist/services/catalog-price-range-service.js +95 -0
- package/cjs/dist/services/category-service.d.ts +25 -0
- package/cjs/dist/services/category-service.js +67 -0
- package/cjs/dist/services/collection-service.d.ts +37 -0
- package/cjs/dist/services/collection-service.js +454 -0
- package/cjs/dist/services/filter-service.d.ts +56 -0
- package/cjs/dist/services/filter-service.js +155 -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 +36 -0
- package/cjs/dist/services/product-modifiers-service.js +104 -0
- package/cjs/dist/services/product-service.d.ts +27 -0
- package/cjs/dist/services/product-service.js +51 -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 +51 -0
- package/cjs/dist/services/selected-variant-service.js +396 -0
- package/cjs/dist/services/social-sharing-service.d.ts +41 -0
- package/cjs/dist/services/social-sharing-service.js +157 -0
- package/cjs/dist/services/sort-service.d.ts +19 -0
- package/cjs/dist/services/sort-service.js +37 -0
- package/cjs/dist/utils/url-params.d.ts +5 -0
- package/cjs/dist/utils/url-params.js +50 -0
- package/dist/react/BuyNow.d.ts +1 -0
- package/dist/react/BuyNow.js +1 -0
- package/dist/react/Category.d.ts +17 -0
- package/dist/react/Category.js +31 -0
- package/dist/react/Collection.d.ts +141 -0
- package/dist/react/Collection.js +190 -0
- package/dist/react/FilteredCollection.d.ts +65 -0
- package/dist/react/FilteredCollection.js +107 -0
- package/dist/react/PayNow.d.ts +1 -0
- package/dist/react/PayNow.js +1 -0
- package/dist/react/Product.d.ts +70 -0
- package/dist/react/Product.js +50 -0
- package/dist/react/ProductMediaGallery.d.ts +128 -0
- package/dist/react/ProductMediaGallery.js +92 -0
- package/dist/react/ProductModifiers.d.ts +156 -0
- package/dist/react/ProductModifiers.js +151 -0
- package/dist/react/ProductVariantSelector.d.ts +169 -0
- package/dist/react/ProductVariantSelector.js +157 -0
- package/dist/react/RelatedProducts.d.ts +60 -0
- package/dist/react/RelatedProducts.js +60 -0
- package/dist/react/SocialSharing.d.ts +119 -0
- package/dist/react/SocialSharing.js +71 -0
- package/dist/react/Sort.d.ts +17 -0
- package/dist/react/Sort.js +36 -0
- package/dist/react/index.d.ts +10 -0
- package/dist/react/index.js +10 -0
- package/dist/services/catalog-options-service.d.ts +30 -0
- package/dist/services/catalog-options-service.js +158 -0
- package/dist/services/catalog-price-range-service.d.ts +23 -0
- package/dist/services/catalog-price-range-service.js +91 -0
- package/dist/services/category-service.d.ts +25 -0
- package/dist/services/category-service.js +63 -0
- package/dist/services/collection-service.d.ts +37 -0
- package/dist/services/collection-service.js +417 -0
- package/dist/services/filter-service.d.ts +56 -0
- package/dist/services/filter-service.js +152 -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 +36 -0
- package/dist/services/product-modifiers-service.js +100 -0
- package/dist/services/product-service.d.ts +27 -0
- package/dist/services/product-service.js +47 -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 +51 -0
- package/dist/services/selected-variant-service.js +392 -0
- package/dist/services/social-sharing-service.d.ts +41 -0
- package/dist/services/social-sharing-service.js +153 -0
- package/dist/services/sort-service.d.ts +19 -0
- package/dist/services/sort-service.js +34 -0
- package/dist/utils/url-params.d.ts +5 -0
- package/dist/utils/url-params.js +46 -0
- package/package.json +2 -1
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { productsV3 } from "@wix/stores";
|
|
2
|
+
/**
|
|
3
|
+
* Props for Options headless component
|
|
4
|
+
*/
|
|
5
|
+
export interface OptionsProps {
|
|
6
|
+
/** Render prop function that receives options data */
|
|
7
|
+
children: (props: OptionsRenderProps) => React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Render props for Options component
|
|
11
|
+
*/
|
|
12
|
+
export interface OptionsRenderProps {
|
|
13
|
+
/** Array of product options */
|
|
14
|
+
options: productsV3.ConnectedOption[];
|
|
15
|
+
/** Whether product has options */
|
|
16
|
+
hasOptions: boolean;
|
|
17
|
+
/** Currently selected choices */
|
|
18
|
+
selectedChoices: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Headless component for all product options
|
|
22
|
+
*/
|
|
23
|
+
export declare const Options: (props: OptionsProps) => import("react").ReactNode;
|
|
24
|
+
/**
|
|
25
|
+
* Props for Option headless component
|
|
26
|
+
*/
|
|
27
|
+
export interface OptionProps {
|
|
28
|
+
/** Product option data */
|
|
29
|
+
option: productsV3.ConnectedOption;
|
|
30
|
+
/** Render prop function that receives option data */
|
|
31
|
+
children: (props: OptionRenderProps) => React.ReactNode;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Render props for Option component
|
|
35
|
+
*/
|
|
36
|
+
export interface OptionRenderProps {
|
|
37
|
+
/** Option name */
|
|
38
|
+
name: string;
|
|
39
|
+
/** Option type */
|
|
40
|
+
type: any;
|
|
41
|
+
/** Array of choices for this option */
|
|
42
|
+
choices: productsV3.ConnectedOptionChoice[];
|
|
43
|
+
/** Currently selected value for this option */
|
|
44
|
+
selectedValue: string | null;
|
|
45
|
+
/** Whether this option has choices */
|
|
46
|
+
hasChoices: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Headless component for choices within a specific product option
|
|
50
|
+
*/
|
|
51
|
+
export declare const Option: (props: OptionProps) => import("react").ReactNode;
|
|
52
|
+
/**
|
|
53
|
+
* Props for Choice headless component
|
|
54
|
+
*/
|
|
55
|
+
export interface ChoiceProps {
|
|
56
|
+
/** Product option data */
|
|
57
|
+
option: productsV3.ConnectedOption;
|
|
58
|
+
/** Choice data */
|
|
59
|
+
choice: productsV3.ConnectedOptionChoice;
|
|
60
|
+
/** Render prop function that receives choice data */
|
|
61
|
+
children: (props: ChoiceRenderProps) => React.ReactNode;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Render props for Choice component
|
|
65
|
+
*/
|
|
66
|
+
export interface ChoiceRenderProps {
|
|
67
|
+
/** Choice value to display */
|
|
68
|
+
value: string;
|
|
69
|
+
/** Choice description (for color options) */
|
|
70
|
+
description: string | undefined;
|
|
71
|
+
/** Whether this choice is currently selected */
|
|
72
|
+
isSelected: boolean;
|
|
73
|
+
/** Whether this choice is available for selection */
|
|
74
|
+
isAvailable: boolean;
|
|
75
|
+
/** Function to select this choice */
|
|
76
|
+
onSelect: () => void;
|
|
77
|
+
/** Option name */
|
|
78
|
+
optionName: string;
|
|
79
|
+
/** Choice value */
|
|
80
|
+
choiceValue: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Headless component for individual choice selection
|
|
84
|
+
*/
|
|
85
|
+
export declare const Choice: (props: ChoiceProps) => import("react").ReactNode;
|
|
86
|
+
/**
|
|
87
|
+
* Props for Trigger headless component
|
|
88
|
+
*/
|
|
89
|
+
export interface TriggerProps {
|
|
90
|
+
/** Quantity to add (optional) */
|
|
91
|
+
quantity?: number;
|
|
92
|
+
/** Render prop function that receives trigger data */
|
|
93
|
+
children: (props: TriggerRenderProps) => React.ReactNode;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Render props for Trigger component
|
|
97
|
+
*/
|
|
98
|
+
export interface TriggerRenderProps {
|
|
99
|
+
/** Function to add product to cart */
|
|
100
|
+
onAddToCart: () => Promise<void>;
|
|
101
|
+
/** Whether add to cart is available */
|
|
102
|
+
canAddToCart: boolean;
|
|
103
|
+
/** Whether add to cart is currently loading */
|
|
104
|
+
isLoading: boolean;
|
|
105
|
+
/** Current product price */
|
|
106
|
+
price: string;
|
|
107
|
+
/** Whether product is in stock */
|
|
108
|
+
inStock: boolean;
|
|
109
|
+
/** Whether pre-order is enabled */
|
|
110
|
+
isPreOrderEnabled: boolean;
|
|
111
|
+
/** Error message if any */
|
|
112
|
+
error: string | null;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Headless component for add to cart trigger
|
|
116
|
+
*/
|
|
117
|
+
export declare const Trigger: (props: TriggerProps) => import("react").ReactNode;
|
|
118
|
+
/**
|
|
119
|
+
* Props for Price headless component
|
|
120
|
+
*/
|
|
121
|
+
export interface PriceProps {
|
|
122
|
+
/** Render prop function that receives price data */
|
|
123
|
+
children: (props: PriceRenderProps) => React.ReactNode;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Render props for Price component
|
|
127
|
+
*/
|
|
128
|
+
export interface PriceRenderProps {
|
|
129
|
+
/** Current price (formatted) */
|
|
130
|
+
price: string;
|
|
131
|
+
/** Compare at price (formatted) - null if no compare price */
|
|
132
|
+
compareAtPrice: string | null;
|
|
133
|
+
/** Whether price is for a variant */
|
|
134
|
+
isVariantPrice: boolean;
|
|
135
|
+
/** Currency code */
|
|
136
|
+
currency: string;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Headless component for product price display
|
|
140
|
+
*/
|
|
141
|
+
export declare const Price: (props: PriceProps) => import("react").ReactNode;
|
|
142
|
+
/**
|
|
143
|
+
* Props for Stock headless component
|
|
144
|
+
*/
|
|
145
|
+
export interface StockProps {
|
|
146
|
+
/** Render prop function that receives stock data */
|
|
147
|
+
children: (props: StockRenderProps) => React.ReactNode;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Render props for Stock component
|
|
151
|
+
*/
|
|
152
|
+
export interface StockRenderProps {
|
|
153
|
+
/** Whether product is in stock */
|
|
154
|
+
inStock: boolean;
|
|
155
|
+
/** Whether pre-order is enabled */
|
|
156
|
+
isPreOrderEnabled: boolean;
|
|
157
|
+
/** Stock status message */
|
|
158
|
+
status: string;
|
|
159
|
+
/** Stock quantity (if available) */
|
|
160
|
+
quantity: number | null;
|
|
161
|
+
/** Whether stock tracking is enabled */
|
|
162
|
+
trackInventory: boolean;
|
|
163
|
+
/** Current variant id */
|
|
164
|
+
currentVariantId: string | null;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Headless component for product stock status
|
|
168
|
+
*/
|
|
169
|
+
export declare const Stock: (props: StockProps) => import("react").ReactNode;
|
|
@@ -0,0 +1,157 @@
|
|
|
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 all product options
|
|
6
|
+
*/
|
|
7
|
+
export const Options = (props) => {
|
|
8
|
+
const variantService = useService(SelectedVariantServiceDefinition);
|
|
9
|
+
const selectedChoices = variantService.selectedChoices.get();
|
|
10
|
+
const options = variantService.productOptions.get();
|
|
11
|
+
return props.children({
|
|
12
|
+
options,
|
|
13
|
+
hasOptions: options.length > 0,
|
|
14
|
+
selectedChoices,
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Headless component for choices within a specific product option
|
|
19
|
+
*/
|
|
20
|
+
export const Option = (props) => {
|
|
21
|
+
const variantService = useService(SelectedVariantServiceDefinition);
|
|
22
|
+
const selectedChoices = variantService.selectedChoices.get();
|
|
23
|
+
const { option } = props;
|
|
24
|
+
const name = option.name || "";
|
|
25
|
+
const choices = option.choicesSettings?.choices || [];
|
|
26
|
+
const selectedValue = selectedChoices[name] || null;
|
|
27
|
+
return props.children({
|
|
28
|
+
name,
|
|
29
|
+
type: option.optionRenderType,
|
|
30
|
+
choices,
|
|
31
|
+
selectedValue,
|
|
32
|
+
hasChoices: choices.length > 0,
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Headless component for individual choice selection
|
|
37
|
+
*/
|
|
38
|
+
export const Choice = (props) => {
|
|
39
|
+
const variantService = useService(SelectedVariantServiceDefinition);
|
|
40
|
+
const selectedChoices = variantService.selectedChoices.get();
|
|
41
|
+
const { option, choice } = props;
|
|
42
|
+
const optionName = option.name || "";
|
|
43
|
+
const choiceValue = choice.name || "";
|
|
44
|
+
const isSelected = selectedChoices[optionName] === choiceValue;
|
|
45
|
+
// Check if this choice is available based on current selections
|
|
46
|
+
const isAvailable = variantService.isChoiceAvailable(optionName, choiceValue);
|
|
47
|
+
const value = choiceValue;
|
|
48
|
+
const onSelect = () => {
|
|
49
|
+
const newChoices = {
|
|
50
|
+
...selectedChoices,
|
|
51
|
+
[optionName]: choiceValue,
|
|
52
|
+
};
|
|
53
|
+
variantService.setSelectedChoices(newChoices);
|
|
54
|
+
};
|
|
55
|
+
return props.children({
|
|
56
|
+
value,
|
|
57
|
+
description: undefined, // v3 choices don't have separate description field
|
|
58
|
+
isSelected,
|
|
59
|
+
isAvailable,
|
|
60
|
+
onSelect,
|
|
61
|
+
optionName,
|
|
62
|
+
choiceValue,
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Headless component for add to cart trigger
|
|
67
|
+
*/
|
|
68
|
+
export const Trigger = (props) => {
|
|
69
|
+
const variantService = useService(SelectedVariantServiceDefinition);
|
|
70
|
+
// Try to get modifiers service - it may not exist for all products
|
|
71
|
+
let modifiersService = null;
|
|
72
|
+
try {
|
|
73
|
+
modifiersService = useService(ProductModifiersServiceDefinition);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Modifiers service not available for this product
|
|
77
|
+
modifiersService = null;
|
|
78
|
+
}
|
|
79
|
+
const price = variantService.currentPrice.get();
|
|
80
|
+
const inStock = variantService.isInStock.get();
|
|
81
|
+
const isPreOrderEnabled = variantService.isPreOrderEnabled.get();
|
|
82
|
+
const isLoading = variantService.isLoading.get();
|
|
83
|
+
const error = variantService.error.get();
|
|
84
|
+
const quantity = props.quantity || 1;
|
|
85
|
+
// Check if all required modifiers are filled
|
|
86
|
+
const areAllRequiredModifiersFilled = modifiersService
|
|
87
|
+
? modifiersService.areAllRequiredModifiersFilled()
|
|
88
|
+
: true; // If no modifiers service, assume no required modifiers
|
|
89
|
+
const canAddToCart = (inStock || isPreOrderEnabled) && !isLoading && areAllRequiredModifiersFilled;
|
|
90
|
+
const onAddToCart = async () => {
|
|
91
|
+
// Get modifiers data if available
|
|
92
|
+
let modifiersData;
|
|
93
|
+
if (modifiersService) {
|
|
94
|
+
const selectedModifiers = modifiersService.selectedModifiers.get();
|
|
95
|
+
if (Object.keys(selectedModifiers).length > 0) {
|
|
96
|
+
modifiersData = selectedModifiers;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
await variantService.addToCart(quantity, modifiersData);
|
|
100
|
+
};
|
|
101
|
+
return props.children({
|
|
102
|
+
onAddToCart,
|
|
103
|
+
canAddToCart,
|
|
104
|
+
isLoading,
|
|
105
|
+
price,
|
|
106
|
+
inStock,
|
|
107
|
+
isPreOrderEnabled,
|
|
108
|
+
error,
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Headless component for product price display
|
|
113
|
+
*/
|
|
114
|
+
export const Price = (props) => {
|
|
115
|
+
const variantService = useService(SelectedVariantServiceDefinition);
|
|
116
|
+
const price = variantService.currentPrice.get();
|
|
117
|
+
const compareAtPrice = variantService.currentCompareAtPrice.get();
|
|
118
|
+
const currentVariant = variantService.currentVariant.get();
|
|
119
|
+
const currency = variantService.currency.get();
|
|
120
|
+
const isVariantPrice = !!currentVariant;
|
|
121
|
+
return props.children({
|
|
122
|
+
price,
|
|
123
|
+
compareAtPrice,
|
|
124
|
+
isVariantPrice,
|
|
125
|
+
currency,
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Headless component for product stock status
|
|
130
|
+
*/
|
|
131
|
+
export const Stock = (props) => {
|
|
132
|
+
const variantService = useService(SelectedVariantServiceDefinition);
|
|
133
|
+
const inStock = variantService.isInStock.get();
|
|
134
|
+
const isPreOrderEnabled = variantService.isPreOrderEnabled.get();
|
|
135
|
+
const currentVariantId = variantService.selectedVariantId.get();
|
|
136
|
+
const trackInventory = false; // V3 API has different inventory structure
|
|
137
|
+
const quantity = null; // Not directly available in v3 API
|
|
138
|
+
// Determine status based on stock and pre-order availability
|
|
139
|
+
let status;
|
|
140
|
+
if (inStock) {
|
|
141
|
+
status = "In Stock";
|
|
142
|
+
}
|
|
143
|
+
else if (isPreOrderEnabled) {
|
|
144
|
+
status = "Available for Pre-Order";
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
status = "Out of Stock";
|
|
148
|
+
}
|
|
149
|
+
return props.children({
|
|
150
|
+
inStock,
|
|
151
|
+
isPreOrderEnabled,
|
|
152
|
+
currentVariantId,
|
|
153
|
+
status,
|
|
154
|
+
quantity,
|
|
155
|
+
trackInventory,
|
|
156
|
+
});
|
|
157
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { productsV3 } from "@wix/stores";
|
|
3
|
+
/**
|
|
4
|
+
* Props for List headless component
|
|
5
|
+
*/
|
|
6
|
+
export interface ListProps {
|
|
7
|
+
/** Render prop function that receives list data */
|
|
8
|
+
children: (props: ListRenderProps) => React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Render props for List component
|
|
12
|
+
*/
|
|
13
|
+
export interface ListRenderProps {
|
|
14
|
+
/** Array of related products */
|
|
15
|
+
products: productsV3.V3Product[];
|
|
16
|
+
/** Whether products are loading */
|
|
17
|
+
isLoading: boolean;
|
|
18
|
+
/** Error message if any */
|
|
19
|
+
error: string | null;
|
|
20
|
+
/** Whether there are products available */
|
|
21
|
+
hasProducts: boolean;
|
|
22
|
+
/** Function to refresh products */
|
|
23
|
+
refresh: () => Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Headless component for displaying related products list
|
|
27
|
+
*/
|
|
28
|
+
export declare const List: (props: ListProps) => React.ReactNode;
|
|
29
|
+
/**
|
|
30
|
+
* Props for Item headless component
|
|
31
|
+
*/
|
|
32
|
+
export interface ItemProps {
|
|
33
|
+
/** Product data */
|
|
34
|
+
product: productsV3.V3Product;
|
|
35
|
+
/** Render prop function that receives item data */
|
|
36
|
+
children: (props: ItemRenderProps) => React.ReactNode;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Render props for Item component
|
|
40
|
+
*/
|
|
41
|
+
export interface ItemRenderProps {
|
|
42
|
+
/** Product title */
|
|
43
|
+
title: string;
|
|
44
|
+
/** Product image URL */
|
|
45
|
+
image: string | null;
|
|
46
|
+
/** Formatted price */
|
|
47
|
+
price: string;
|
|
48
|
+
/** Whether product is available */
|
|
49
|
+
available: boolean;
|
|
50
|
+
/** Product page URL */
|
|
51
|
+
href: string;
|
|
52
|
+
/** Product description */
|
|
53
|
+
description: string;
|
|
54
|
+
/** Function to add product to cart quickly */
|
|
55
|
+
onQuickAdd: () => void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Headless component for individual related product item
|
|
59
|
+
*/
|
|
60
|
+
export declare const Item: (props: ItemProps) => React.ReactNode;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useService } from "@wix/services-manager-react";
|
|
3
|
+
import { RelatedProductsServiceDefinition } from "../services/related-products-service";
|
|
4
|
+
/**
|
|
5
|
+
* Headless component for displaying related products list
|
|
6
|
+
*/
|
|
7
|
+
export const List = (props) => {
|
|
8
|
+
const service = useService(RelatedProductsServiceDefinition);
|
|
9
|
+
const [products, setProducts] = React.useState([]);
|
|
10
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
11
|
+
const [error, setError] = React.useState(null);
|
|
12
|
+
const [hasProducts, setHasProducts] = React.useState(false);
|
|
13
|
+
React.useEffect(() => {
|
|
14
|
+
const unsubscribes = [
|
|
15
|
+
service.relatedProducts.subscribe(setProducts),
|
|
16
|
+
service.isLoading.subscribe(setIsLoading),
|
|
17
|
+
service.error.subscribe(setError),
|
|
18
|
+
service.hasRelatedProducts.subscribe(setHasProducts),
|
|
19
|
+
];
|
|
20
|
+
return () => unsubscribes.forEach((fn) => fn());
|
|
21
|
+
}, [service]);
|
|
22
|
+
return props.children({
|
|
23
|
+
products,
|
|
24
|
+
isLoading,
|
|
25
|
+
error,
|
|
26
|
+
hasProducts,
|
|
27
|
+
refresh: service.refreshRelatedProducts,
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Headless component for individual related product item
|
|
32
|
+
*/
|
|
33
|
+
export const Item = (props) => {
|
|
34
|
+
const { product } = props;
|
|
35
|
+
const title = product.name || "Unknown Product";
|
|
36
|
+
// Use actual v3 media structure - image is directly a string URL
|
|
37
|
+
const image = product.media?.main?.image || null;
|
|
38
|
+
// Create formatted price from raw amount since formattedAmount may not be available
|
|
39
|
+
const rawPrice = product.actualPriceRange?.minValue?.amount;
|
|
40
|
+
const price = rawPrice ? `$${rawPrice}` : "Price unavailable";
|
|
41
|
+
const availabilityStatus = product.inventory?.availabilityStatus;
|
|
42
|
+
const available = availabilityStatus === "IN_STOCK" ||
|
|
43
|
+
availabilityStatus === "PARTIALLY_OUT_OF_STOCK";
|
|
44
|
+
const href = `/store/example-2/${product.slug}`;
|
|
45
|
+
const description = typeof product.description === "string" ? product.description : "";
|
|
46
|
+
const handleQuickAdd = () => {
|
|
47
|
+
// This would typically add the product to cart
|
|
48
|
+
// For now, we'll just log it
|
|
49
|
+
console.log("Quick add:", product.name);
|
|
50
|
+
};
|
|
51
|
+
return props.children({
|
|
52
|
+
title,
|
|
53
|
+
image,
|
|
54
|
+
price,
|
|
55
|
+
available,
|
|
56
|
+
href,
|
|
57
|
+
description,
|
|
58
|
+
onQuickAdd: handleQuickAdd,
|
|
59
|
+
});
|
|
60
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { SharingPlatform } from "../services/social-sharing-service";
|
|
3
|
+
export type { SharingPlatform };
|
|
4
|
+
export type RootChildren = (props: RootRenderProps) => React.ReactNode;
|
|
5
|
+
/**
|
|
6
|
+
* Props for Root headless component
|
|
7
|
+
*/
|
|
8
|
+
export interface RootProps {
|
|
9
|
+
/** Render prop function that receives sharing data */
|
|
10
|
+
children: RootChildren;
|
|
11
|
+
}
|
|
12
|
+
export type ShareFacebook = (url: string, title: string, description?: string) => void;
|
|
13
|
+
export type ShareTwitter = (url: string, text: string, hashtags?: string[]) => void;
|
|
14
|
+
export type ShareLinkedIn = (url: string, title: string, summary?: string) => void;
|
|
15
|
+
export type ShareWhatsApp = (url: string, text: string) => void;
|
|
16
|
+
export type ShareEmail = (url: string, subject: string, body: string) => void;
|
|
17
|
+
export type CopyLink = (url: string) => Promise<boolean>;
|
|
18
|
+
export type ShareNative = (data: {
|
|
19
|
+
title: string;
|
|
20
|
+
text: string;
|
|
21
|
+
url: string;
|
|
22
|
+
}) => Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* Render props for Root component
|
|
25
|
+
*/
|
|
26
|
+
export interface RootRenderProps {
|
|
27
|
+
/** Available sharing platforms */
|
|
28
|
+
platforms: SharingPlatform[];
|
|
29
|
+
/** Total share count */
|
|
30
|
+
shareCount: number;
|
|
31
|
+
/** Last shared platform */
|
|
32
|
+
lastShared: string | null;
|
|
33
|
+
/** Share to Facebook */
|
|
34
|
+
shareFacebook: ShareFacebook;
|
|
35
|
+
/** Share to Twitter */
|
|
36
|
+
shareTwitter: ShareTwitter;
|
|
37
|
+
/** Share to LinkedIn */
|
|
38
|
+
shareLinkedIn: ShareLinkedIn;
|
|
39
|
+
/** Share to WhatsApp */
|
|
40
|
+
shareWhatsApp: ShareWhatsApp;
|
|
41
|
+
/** Share via Email */
|
|
42
|
+
shareEmail: ShareEmail;
|
|
43
|
+
/** Copy to clipboard */
|
|
44
|
+
copyLink: CopyLink;
|
|
45
|
+
/** Native share API */
|
|
46
|
+
shareNative: ShareNative;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Headless component for social sharing root
|
|
50
|
+
*/
|
|
51
|
+
export declare const Root: (props: RootProps) => React.ReactNode;
|
|
52
|
+
export type OnClick = () => void;
|
|
53
|
+
export type PlatformChildren = (props: PlatformRenderProps) => React.ReactNode;
|
|
54
|
+
/**
|
|
55
|
+
* Props for Platform headless component
|
|
56
|
+
*/
|
|
57
|
+
export interface PlatformProps {
|
|
58
|
+
/** Platform data */
|
|
59
|
+
platform: SharingPlatform;
|
|
60
|
+
/** Click handler */
|
|
61
|
+
onClick: OnClick;
|
|
62
|
+
/** Render prop function that receives platform data */
|
|
63
|
+
children: PlatformChildren;
|
|
64
|
+
}
|
|
65
|
+
export type OnSelect = () => void;
|
|
66
|
+
/**
|
|
67
|
+
* Render props for Platform component
|
|
68
|
+
*/
|
|
69
|
+
export interface PlatformRenderProps {
|
|
70
|
+
/** Platform data */
|
|
71
|
+
platform: SharingPlatform;
|
|
72
|
+
/** Platform click handler */
|
|
73
|
+
onSelect: OnSelect;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Headless component for individual social platform
|
|
77
|
+
*/
|
|
78
|
+
export declare const Platform: (props: PlatformProps) => React.ReactNode;
|
|
79
|
+
export type PlatformsChildren = (props: PlatformsRenderProps) => React.ReactNode;
|
|
80
|
+
/**
|
|
81
|
+
* Props for Platforms headless component
|
|
82
|
+
*/
|
|
83
|
+
export interface PlatformsProps {
|
|
84
|
+
/** URL to share */
|
|
85
|
+
url: string;
|
|
86
|
+
/** Share title */
|
|
87
|
+
title: string;
|
|
88
|
+
/** Share description */
|
|
89
|
+
description?: string;
|
|
90
|
+
/** Hashtags for sharing */
|
|
91
|
+
hashtags?: string[];
|
|
92
|
+
/** Render prop function that receives platforms data */
|
|
93
|
+
children: PlatformsChildren;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Render props for Platforms component
|
|
97
|
+
*/
|
|
98
|
+
export interface PlatformsRenderProps {
|
|
99
|
+
/** Available platforms */
|
|
100
|
+
platforms: SharingPlatform[];
|
|
101
|
+
/** Share to Facebook */
|
|
102
|
+
shareFacebook: () => void;
|
|
103
|
+
/** Share to Twitter */
|
|
104
|
+
shareTwitter: () => void;
|
|
105
|
+
/** Share to LinkedIn */
|
|
106
|
+
shareLinkedIn: () => void;
|
|
107
|
+
/** Share to WhatsApp */
|
|
108
|
+
shareWhatsApp: () => void;
|
|
109
|
+
/** Share via Email */
|
|
110
|
+
shareEmail: () => void;
|
|
111
|
+
/** Copy link to clipboard */
|
|
112
|
+
copyLink: () => Promise<boolean>;
|
|
113
|
+
/** Share natively */
|
|
114
|
+
shareNative: () => Promise<boolean>;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Headless component for social sharing platforms with logic
|
|
118
|
+
*/
|
|
119
|
+
export declare const Platforms: (props: PlatformsProps) => React.ReactNode;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useService } from "@wix/services-manager-react";
|
|
3
|
+
import { SocialSharingServiceDefinition, } from "../services/social-sharing-service";
|
|
4
|
+
/**
|
|
5
|
+
* Headless component for social sharing root
|
|
6
|
+
*/
|
|
7
|
+
export const Root = (props) => {
|
|
8
|
+
const service = useService(SocialSharingServiceDefinition);
|
|
9
|
+
const [platforms, setPlatforms] = React.useState([]);
|
|
10
|
+
const [shareCount, setShareCount] = React.useState(0);
|
|
11
|
+
const [lastShared, setLastShared] = React.useState(null);
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
const unsubscribes = [
|
|
14
|
+
service.availablePlatforms.subscribe(setPlatforms),
|
|
15
|
+
service.shareCount.subscribe(setShareCount),
|
|
16
|
+
service.lastSharedPlatform.subscribe(setLastShared),
|
|
17
|
+
];
|
|
18
|
+
return () => unsubscribes.forEach((fn) => fn());
|
|
19
|
+
}, [service]);
|
|
20
|
+
return props.children({
|
|
21
|
+
platforms,
|
|
22
|
+
shareCount,
|
|
23
|
+
lastShared,
|
|
24
|
+
shareFacebook: service.shareToFacebook,
|
|
25
|
+
shareTwitter: service.shareToTwitter,
|
|
26
|
+
shareLinkedIn: service.shareToLinkedIn,
|
|
27
|
+
shareWhatsApp: service.shareToWhatsApp,
|
|
28
|
+
shareEmail: service.shareToEmail,
|
|
29
|
+
copyLink: service.copyToClipboard,
|
|
30
|
+
shareNative: service.shareNative,
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Headless component for individual social platform
|
|
35
|
+
*/
|
|
36
|
+
export const Platform = (props) => {
|
|
37
|
+
const { platform, onClick } = props;
|
|
38
|
+
return props.children({
|
|
39
|
+
platform,
|
|
40
|
+
onSelect: onClick,
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Headless component for social sharing platforms with logic
|
|
45
|
+
*/
|
|
46
|
+
export const Platforms = (props) => {
|
|
47
|
+
const { url, title, description = "", hashtags = [] } = props;
|
|
48
|
+
const service = useService(SocialSharingServiceDefinition);
|
|
49
|
+
const [platforms, setPlatforms] = React.useState([]);
|
|
50
|
+
React.useEffect(() => {
|
|
51
|
+
const unsubscribe = service.availablePlatforms.subscribe(setPlatforms);
|
|
52
|
+
return unsubscribe;
|
|
53
|
+
}, [service]);
|
|
54
|
+
const shareFacebook = () => service.shareToFacebook(url, title, description);
|
|
55
|
+
const shareTwitter = () => service.shareToTwitter(url, title, hashtags);
|
|
56
|
+
const shareLinkedIn = () => service.shareToLinkedIn(url, title, description);
|
|
57
|
+
const shareWhatsApp = () => service.shareToWhatsApp(url, `${title} - ${description}`);
|
|
58
|
+
const shareEmail = () => service.shareToEmail(url, title, description);
|
|
59
|
+
const copyLink = () => service.copyToClipboard(url);
|
|
60
|
+
const shareNative = () => service.shareNative({ title, text: description, url });
|
|
61
|
+
return props.children({
|
|
62
|
+
platforms,
|
|
63
|
+
shareFacebook,
|
|
64
|
+
shareTwitter,
|
|
65
|
+
shareLinkedIn,
|
|
66
|
+
shareWhatsApp,
|
|
67
|
+
shareEmail,
|
|
68
|
+
copyLink,
|
|
69
|
+
shareNative,
|
|
70
|
+
});
|
|
71
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { type SortBy } from "../services/sort-service";
|
|
3
|
+
interface SortContextValue {
|
|
4
|
+
currentSort: SortBy;
|
|
5
|
+
setSortBy: (sortBy: SortBy) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function useSortContext(): SortContextValue;
|
|
8
|
+
export interface ProviderProps {
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
export declare function Provider({ children }: ProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export type SortControllerChildren = (props: SortContextValue) => React.ReactNode;
|
|
13
|
+
export interface ControllerProps {
|
|
14
|
+
children: SortControllerChildren;
|
|
15
|
+
}
|
|
16
|
+
export declare function Controller({ children }: ControllerProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useEffect, useState } from "react";
|
|
3
|
+
import { SortServiceDefinition } from "../services/sort-service";
|
|
4
|
+
import { useService } from "@wix/services-manager-react";
|
|
5
|
+
const SortContext = createContext(null);
|
|
6
|
+
export function useSortContext() {
|
|
7
|
+
const context = useContext(SortContext);
|
|
8
|
+
if (!context) {
|
|
9
|
+
throw new Error("useSortContext must be used within a Sort.SortProvider");
|
|
10
|
+
}
|
|
11
|
+
return context;
|
|
12
|
+
}
|
|
13
|
+
export function Provider({ children }) {
|
|
14
|
+
const sortService = useService(SortServiceDefinition);
|
|
15
|
+
const [currentSort, setCurrentSort] = useState("");
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const unsubscribe = sortService.currentSort.subscribe((sort) => {
|
|
18
|
+
setCurrentSort(sort);
|
|
19
|
+
});
|
|
20
|
+
// Initialize with current value
|
|
21
|
+
setCurrentSort(sortService.currentSort.get());
|
|
22
|
+
return unsubscribe;
|
|
23
|
+
}, [sortService]);
|
|
24
|
+
const setSortBy = (sortBy) => {
|
|
25
|
+
sortService.setSortBy(sortBy);
|
|
26
|
+
};
|
|
27
|
+
const contextValue = {
|
|
28
|
+
currentSort,
|
|
29
|
+
setSortBy,
|
|
30
|
+
};
|
|
31
|
+
return (_jsx(SortContext.Provider, { value: contextValue, children: children }));
|
|
32
|
+
}
|
|
33
|
+
export function Controller({ children }) {
|
|
34
|
+
const context = useSortContext();
|
|
35
|
+
return _jsx(_Fragment, { children: children(context) });
|
|
36
|
+
}
|