@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
package/dist/react/index.d.ts
CHANGED
|
@@ -1,2 +1,12 @@
|
|
|
1
1
|
export * from "./BuyNow";
|
|
2
2
|
export * from "./PayNow";
|
|
3
|
+
export * as Sort from "./Sort";
|
|
4
|
+
export * as Category from "./Category";
|
|
5
|
+
export * as FilteredCollection from "./FilteredCollection";
|
|
6
|
+
export * as ProductVariantSelector from "./ProductVariantSelector";
|
|
7
|
+
export * as RelatedProducts from "./RelatedProducts";
|
|
8
|
+
export * as SocialSharing from "./SocialSharing";
|
|
9
|
+
export * as Collection from "./Collection";
|
|
10
|
+
export * as Product from "./Product";
|
|
11
|
+
export * as ProductMediaGallery from "./ProductMediaGallery";
|
|
12
|
+
export * as ProductModifiers from "./ProductModifiers";
|
package/dist/react/index.js
CHANGED
|
@@ -1,2 +1,12 @@
|
|
|
1
1
|
export * from "./BuyNow";
|
|
2
2
|
export * from "./PayNow";
|
|
3
|
+
export * as Sort from "./Sort";
|
|
4
|
+
export * as Category from "./Category";
|
|
5
|
+
export * as FilteredCollection from "./FilteredCollection";
|
|
6
|
+
export * as ProductVariantSelector from "./ProductVariantSelector";
|
|
7
|
+
export * as RelatedProducts from "./RelatedProducts";
|
|
8
|
+
export * as SocialSharing from "./SocialSharing";
|
|
9
|
+
export * as Collection from "./Collection";
|
|
10
|
+
export * as Product from "./Product";
|
|
11
|
+
export * as ProductMediaGallery from "./ProductMediaGallery";
|
|
12
|
+
export * as ProductModifiers from "./ProductModifiers";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ServiceFactoryConfig } from "@wix/services-definitions";
|
|
2
|
+
import type { Signal } from "./Signal";
|
|
3
|
+
export interface ProductOption {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
choices: ProductChoice[];
|
|
7
|
+
optionRenderType?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ProductChoice {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
colorCode?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface CatalogOptionsServiceAPI {
|
|
15
|
+
catalogOptions: Signal<ProductOption[] | null>;
|
|
16
|
+
isLoading: Signal<boolean>;
|
|
17
|
+
error: Signal<string | null>;
|
|
18
|
+
loadCatalogOptions: (categoryId?: string) => Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export declare const CatalogOptionsServiceDefinition: string & {
|
|
21
|
+
__api: CatalogOptionsServiceAPI;
|
|
22
|
+
__config: {};
|
|
23
|
+
isServiceDefinition?: boolean;
|
|
24
|
+
} & CatalogOptionsServiceAPI;
|
|
25
|
+
export declare const CatalogOptionsService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
26
|
+
__api: CatalogOptionsServiceAPI;
|
|
27
|
+
__config: {};
|
|
28
|
+
isServiceDefinition?: boolean;
|
|
29
|
+
} & CatalogOptionsServiceAPI, {}, import("@wix/services-definitions").ThreadMode.MAIN>;
|
|
30
|
+
export declare function loadCatalogOptionsServiceConfig(): Promise<ServiceFactoryConfig<typeof CatalogOptionsService>>;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { defineService, implementService, } from "@wix/services-definitions";
|
|
2
|
+
import { SignalsServiceDefinition } from "@wix/services-definitions/core-services/signals";
|
|
3
|
+
import { productsV3, customizationsV3 } from "@wix/stores";
|
|
4
|
+
// Helper functions
|
|
5
|
+
const extractAggregationValues = (aggregationResponse, name) => {
|
|
6
|
+
const aggregation = aggregationResponse.aggregations?.[name] ||
|
|
7
|
+
aggregationResponse.aggregationData?.results?.find((r) => r.name === name);
|
|
8
|
+
return aggregation?.values?.results?.map((item) => item.value) || [];
|
|
9
|
+
};
|
|
10
|
+
const matchesAggregationName = (name, aggregationNames) => {
|
|
11
|
+
return aggregationNames.some((aggName) => aggName.toLowerCase() === name.toLowerCase());
|
|
12
|
+
};
|
|
13
|
+
const sortChoicesIntelligently = (choices) => {
|
|
14
|
+
return [...choices].sort((a, b) => {
|
|
15
|
+
const aIsNumber = /^\d+$/.test(a.name);
|
|
16
|
+
const bIsNumber = /^\d+$/.test(b.name);
|
|
17
|
+
if (aIsNumber && bIsNumber) {
|
|
18
|
+
return parseInt(b.name) - parseInt(a.name);
|
|
19
|
+
}
|
|
20
|
+
if (aIsNumber && !bIsNumber)
|
|
21
|
+
return -1;
|
|
22
|
+
if (!aIsNumber && bIsNumber)
|
|
23
|
+
return 1;
|
|
24
|
+
return a.name.localeCompare(b.name);
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
const buildCategoryFilter = (categoryId) => {
|
|
28
|
+
if (!categoryId) {
|
|
29
|
+
return { visible: true };
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
visible: true,
|
|
33
|
+
"allCategoriesInfo.categories": {
|
|
34
|
+
$matchItems: [{ _id: { $in: [categoryId] } }],
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export const CatalogOptionsServiceDefinition = defineService("catalogOptions");
|
|
39
|
+
export const CatalogOptionsService = implementService.withConfig()(CatalogOptionsServiceDefinition, ({ getService }) => {
|
|
40
|
+
const signalsService = getService(SignalsServiceDefinition);
|
|
41
|
+
const catalogOptions = signalsService.signal(null);
|
|
42
|
+
const isLoading = signalsService.signal(false);
|
|
43
|
+
const error = signalsService.signal(null);
|
|
44
|
+
const loadCatalogOptions = async (categoryId) => {
|
|
45
|
+
isLoading.set(true);
|
|
46
|
+
error.set(null);
|
|
47
|
+
try {
|
|
48
|
+
// Step 1: Get unique option and choice names from catalog via aggregation (no products returned)
|
|
49
|
+
const aggregationRequest = {
|
|
50
|
+
aggregations: [
|
|
51
|
+
{
|
|
52
|
+
name: "optionNames",
|
|
53
|
+
fieldPath: "options.name",
|
|
54
|
+
type: "VALUE",
|
|
55
|
+
value: {
|
|
56
|
+
limit: 20,
|
|
57
|
+
sortType: "VALUE",
|
|
58
|
+
sortDirection: "ASC",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "choiceNames",
|
|
63
|
+
fieldPath: "options.choicesSettings.choices.name",
|
|
64
|
+
type: "VALUE",
|
|
65
|
+
value: {
|
|
66
|
+
limit: 50,
|
|
67
|
+
sortType: "VALUE",
|
|
68
|
+
sortDirection: "ASC",
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "inventoryStatus",
|
|
73
|
+
fieldPath: "inventory.availabilityStatus",
|
|
74
|
+
type: "VALUE",
|
|
75
|
+
value: {
|
|
76
|
+
limit: 10,
|
|
77
|
+
sortType: "VALUE",
|
|
78
|
+
sortDirection: "ASC",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
filter: buildCategoryFilter(categoryId),
|
|
83
|
+
includeProducts: false,
|
|
84
|
+
cursorPaging: { limit: 0 },
|
|
85
|
+
};
|
|
86
|
+
const aggregationResponse = await productsV3.searchProducts(aggregationRequest);
|
|
87
|
+
const optionNames = extractAggregationValues(aggregationResponse, "optionNames");
|
|
88
|
+
const choiceNames = extractAggregationValues(aggregationResponse, "choiceNames");
|
|
89
|
+
const inventoryStatuses = extractAggregationValues(aggregationResponse, "inventoryStatus");
|
|
90
|
+
// Step 2: Get option structure from customizations API
|
|
91
|
+
const customizationsResponse = await customizationsV3
|
|
92
|
+
.queryCustomizations()
|
|
93
|
+
.find();
|
|
94
|
+
const customizations = customizationsResponse.items || [];
|
|
95
|
+
// Step 3: Build options by matching customizations with aggregation data
|
|
96
|
+
const options = customizations
|
|
97
|
+
.filter((customization) => customization.name &&
|
|
98
|
+
customization._id &&
|
|
99
|
+
customization.customizationType === "PRODUCT_OPTION" &&
|
|
100
|
+
matchesAggregationName(customization.name, optionNames))
|
|
101
|
+
.map((customization) => {
|
|
102
|
+
const choices = (customization.choicesSettings?.choices || [])
|
|
103
|
+
.filter((choice) => choice._id &&
|
|
104
|
+
choice.name &&
|
|
105
|
+
matchesAggregationName(choice.name, choiceNames))
|
|
106
|
+
.map((choice) => ({
|
|
107
|
+
id: choice._id,
|
|
108
|
+
name: choice.name,
|
|
109
|
+
colorCode: choice.colorCode,
|
|
110
|
+
}));
|
|
111
|
+
return {
|
|
112
|
+
id: customization._id,
|
|
113
|
+
name: customization.name,
|
|
114
|
+
choices: sortChoicesIntelligently(choices),
|
|
115
|
+
optionRenderType: customization.customizationRenderType,
|
|
116
|
+
};
|
|
117
|
+
})
|
|
118
|
+
.filter((option) => option.choices.length > 0);
|
|
119
|
+
// Step 4: Add inventory filter if there are multiple inventory statuses
|
|
120
|
+
if (inventoryStatuses.length > 1) {
|
|
121
|
+
const inventoryChoices = inventoryStatuses.map((status) => ({
|
|
122
|
+
id: status.toUpperCase(), // Use uppercase to match actual availabilityStatus values
|
|
123
|
+
name: status.toUpperCase() === "IN_STOCK"
|
|
124
|
+
? "In Stock"
|
|
125
|
+
: status.toUpperCase() === "OUT_OF_STOCK"
|
|
126
|
+
? "Out of Stock"
|
|
127
|
+
: status.toUpperCase() === "PARTIALLY_OUT_OF_STOCK"
|
|
128
|
+
? "Partially out of stock"
|
|
129
|
+
: status,
|
|
130
|
+
}));
|
|
131
|
+
options.push({
|
|
132
|
+
id: "inventory-filter",
|
|
133
|
+
name: "Availability",
|
|
134
|
+
choices: inventoryChoices,
|
|
135
|
+
optionRenderType: "TEXT_CHOICES",
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
catalogOptions.set(options);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
console.error("Failed to load catalog options:", err);
|
|
142
|
+
error.set(err instanceof Error ? err.message : "Failed to load catalog options");
|
|
143
|
+
catalogOptions.set([]);
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
isLoading.set(false);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
return {
|
|
150
|
+
catalogOptions,
|
|
151
|
+
isLoading,
|
|
152
|
+
error,
|
|
153
|
+
loadCatalogOptions,
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
export async function loadCatalogOptionsServiceConfig() {
|
|
157
|
+
return {};
|
|
158
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ServiceFactoryConfig } from "@wix/services-definitions";
|
|
2
|
+
import type { Signal } from "./Signal";
|
|
3
|
+
export interface CatalogPriceRange {
|
|
4
|
+
minPrice: number;
|
|
5
|
+
maxPrice: number;
|
|
6
|
+
}
|
|
7
|
+
export interface CatalogPriceRangeServiceAPI {
|
|
8
|
+
catalogPriceRange: Signal<CatalogPriceRange | null>;
|
|
9
|
+
isLoading: Signal<boolean>;
|
|
10
|
+
error: Signal<string | null>;
|
|
11
|
+
loadCatalogPriceRange: (categoryId?: string) => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export declare const CatalogPriceRangeServiceDefinition: string & {
|
|
14
|
+
__api: CatalogPriceRangeServiceAPI;
|
|
15
|
+
__config: {};
|
|
16
|
+
isServiceDefinition?: boolean;
|
|
17
|
+
} & CatalogPriceRangeServiceAPI;
|
|
18
|
+
export declare const CatalogPriceRangeService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
19
|
+
__api: CatalogPriceRangeServiceAPI;
|
|
20
|
+
__config: {};
|
|
21
|
+
isServiceDefinition?: boolean;
|
|
22
|
+
} & CatalogPriceRangeServiceAPI, {}, import("@wix/services-definitions").ThreadMode.MAIN>;
|
|
23
|
+
export declare function loadCatalogPriceRangeServiceConfig(): Promise<ServiceFactoryConfig<typeof CatalogPriceRangeService>>;
|
|
@@ -0,0 +1,91 @@
|
|
|
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
|
+
// Helper function to extract scalar aggregation values
|
|
5
|
+
const extractScalarAggregationValue = (aggregationResponse, name) => {
|
|
6
|
+
const aggregation = aggregationResponse.aggregations?.[name] ||
|
|
7
|
+
aggregationResponse.aggregationData?.results?.find((r) => r.name === name);
|
|
8
|
+
const value = aggregation?.scalar?.value;
|
|
9
|
+
return value !== undefined && value !== null ? parseFloat(value) : null;
|
|
10
|
+
};
|
|
11
|
+
const buildCategoryFilter = (categoryId) => {
|
|
12
|
+
if (!categoryId) {
|
|
13
|
+
return { visible: true };
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
visible: true,
|
|
17
|
+
'allCategoriesInfo.categories': {
|
|
18
|
+
$matchItems: [{ _id: { $in: [categoryId] } }]
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export const CatalogPriceRangeServiceDefinition = defineService("catalogPriceRange");
|
|
23
|
+
export const CatalogPriceRangeService = implementService.withConfig()(CatalogPriceRangeServiceDefinition, ({ getService }) => {
|
|
24
|
+
const signalsService = getService(SignalsServiceDefinition);
|
|
25
|
+
// Signal declarations
|
|
26
|
+
const catalogPriceRange = signalsService.signal(null);
|
|
27
|
+
const isLoading = signalsService.signal(false);
|
|
28
|
+
const error = signalsService.signal(null);
|
|
29
|
+
/**
|
|
30
|
+
* Load the catalog-wide price range using a single aggregation query
|
|
31
|
+
* This fetches min/max prices from ALL products in the catalog using SCALAR aggregations
|
|
32
|
+
*/
|
|
33
|
+
const loadCatalogPriceRange = async (categoryId) => {
|
|
34
|
+
isLoading.set(true);
|
|
35
|
+
error.set(null);
|
|
36
|
+
try {
|
|
37
|
+
// Single aggregation request to get both min and max prices (no products returned)
|
|
38
|
+
const aggregationRequest = {
|
|
39
|
+
aggregations: [
|
|
40
|
+
{
|
|
41
|
+
name: 'minPrice',
|
|
42
|
+
fieldPath: 'actualPriceRange.minValue.amount',
|
|
43
|
+
type: 'SCALAR',
|
|
44
|
+
scalar: { type: 'MIN' }
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'maxPrice',
|
|
48
|
+
fieldPath: 'actualPriceRange.maxValue.amount',
|
|
49
|
+
type: 'SCALAR',
|
|
50
|
+
scalar: { type: 'MAX' }
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
filter: buildCategoryFilter(categoryId),
|
|
54
|
+
includeProducts: false,
|
|
55
|
+
cursorPaging: { limit: 0 }
|
|
56
|
+
};
|
|
57
|
+
const aggregationResponse = await productsV3.searchProducts(aggregationRequest);
|
|
58
|
+
const minPrice = extractScalarAggregationValue(aggregationResponse, 'minPrice');
|
|
59
|
+
const maxPrice = extractScalarAggregationValue(aggregationResponse, 'maxPrice');
|
|
60
|
+
// Only set price range if we found valid prices
|
|
61
|
+
if (minPrice !== null && maxPrice !== null && (minPrice > 0 || maxPrice > 0)) {
|
|
62
|
+
catalogPriceRange.set({
|
|
63
|
+
minPrice,
|
|
64
|
+
maxPrice
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// No products found or no valid prices - don't show the filter
|
|
69
|
+
catalogPriceRange.set(null);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
console.error('Failed to load catalog price range:', err);
|
|
74
|
+
error.set(err instanceof Error ? err.message : 'Failed to load price range');
|
|
75
|
+
// Don't set fallback values - let the component handle the error state
|
|
76
|
+
catalogPriceRange.set(null);
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
isLoading.set(false);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
catalogPriceRange,
|
|
84
|
+
isLoading,
|
|
85
|
+
error,
|
|
86
|
+
loadCatalogPriceRange,
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
export async function loadCatalogPriceRangeServiceConfig() {
|
|
90
|
+
return {};
|
|
91
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Signal } from "./Signal";
|
|
2
|
+
import { categories } from "@wix/categories";
|
|
3
|
+
export interface CategoryServiceAPI {
|
|
4
|
+
selectedCategory: Signal<string | null>;
|
|
5
|
+
categories: Signal<categories.Category[]>;
|
|
6
|
+
setSelectedCategory: (categoryId: string | null) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const CategoryServiceDefinition: string & {
|
|
9
|
+
__api: CategoryServiceAPI;
|
|
10
|
+
__config: {};
|
|
11
|
+
isServiceDefinition?: boolean;
|
|
12
|
+
} & CategoryServiceAPI;
|
|
13
|
+
export interface CategoryServiceConfig {
|
|
14
|
+
categories: categories.Category[];
|
|
15
|
+
initialCategoryId?: string | null;
|
|
16
|
+
onCategoryChange?: (categoryId: string | null, category: categories.Category | null) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare const CategoryService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
19
|
+
__api: CategoryServiceAPI;
|
|
20
|
+
__config: {};
|
|
21
|
+
isServiceDefinition?: boolean;
|
|
22
|
+
} & CategoryServiceAPI, CategoryServiceConfig, import("@wix/services-definitions").ThreadMode.MAIN>;
|
|
23
|
+
export declare function loadCategoriesConfig(): Promise<{
|
|
24
|
+
categories: categories.Category[];
|
|
25
|
+
}>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { defineService, implementService } from "@wix/services-definitions";
|
|
2
|
+
import { SignalsServiceDefinition } from "@wix/services-definitions/core-services/signals";
|
|
3
|
+
import { categories } from "@wix/categories";
|
|
4
|
+
export const CategoryServiceDefinition = defineService("category-service");
|
|
5
|
+
export const CategoryService = implementService.withConfig()(CategoryServiceDefinition, ({ getService, config }) => {
|
|
6
|
+
const signalsService = getService(SignalsServiceDefinition);
|
|
7
|
+
const selectedCategory = signalsService.signal((config.initialCategoryId || null));
|
|
8
|
+
const categories = signalsService.signal(config.categories);
|
|
9
|
+
// Track if this is the initial load to prevent navigation on service creation
|
|
10
|
+
let isInitialLoad = true;
|
|
11
|
+
const setSelectedCategory = (categoryId) => {
|
|
12
|
+
selectedCategory.set(categoryId);
|
|
13
|
+
};
|
|
14
|
+
// Subscribe to category changes and handle navigation as a side effect
|
|
15
|
+
selectedCategory.subscribe((categoryId) => {
|
|
16
|
+
// Skip navigation on initial load (when service is first created)
|
|
17
|
+
if (isInitialLoad) {
|
|
18
|
+
isInitialLoad = false;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
// If a navigation handler is provided, use it
|
|
22
|
+
if (config.onCategoryChange) {
|
|
23
|
+
const category = categoryId
|
|
24
|
+
? config.categories.find((cat) => cat._id === categoryId) || null
|
|
25
|
+
: null;
|
|
26
|
+
config.onCategoryChange(categoryId, category);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
selectedCategory,
|
|
31
|
+
categories,
|
|
32
|
+
setSelectedCategory,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
export async function loadCategoriesConfig() {
|
|
36
|
+
try {
|
|
37
|
+
const categoriesResponse = await categories
|
|
38
|
+
.queryCategories({
|
|
39
|
+
treeReference: {
|
|
40
|
+
appNamespace: "@wix/stores",
|
|
41
|
+
treeKey: null,
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
.eq("visible", true)
|
|
45
|
+
.find();
|
|
46
|
+
const fetchedCategories = categoriesResponse.items || [];
|
|
47
|
+
// Sort categories to put "all-products" first, keep the rest in original order
|
|
48
|
+
const allProductsCategory = fetchedCategories.find(cat => cat.slug === "all-products");
|
|
49
|
+
const otherCategories = fetchedCategories.filter(cat => cat.slug !== "all-products");
|
|
50
|
+
const allCategories = allProductsCategory
|
|
51
|
+
? [allProductsCategory, ...otherCategories]
|
|
52
|
+
: fetchedCategories;
|
|
53
|
+
return {
|
|
54
|
+
categories: allCategories,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.warn("Failed to load categories:", error);
|
|
59
|
+
return {
|
|
60
|
+
categories: [],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type ServiceFactoryConfig } from "@wix/services-definitions";
|
|
2
|
+
import type { Signal } from "./Signal";
|
|
3
|
+
import { productsV3 } from "@wix/stores";
|
|
4
|
+
import { type Filter } from "./filter-service";
|
|
5
|
+
import { type SortBy } from "./sort-service";
|
|
6
|
+
export interface CollectionServiceAPI {
|
|
7
|
+
products: Signal<productsV3.V3Product[]>;
|
|
8
|
+
isLoading: Signal<boolean>;
|
|
9
|
+
error: Signal<string | null>;
|
|
10
|
+
totalProducts: Signal<number>;
|
|
11
|
+
hasProducts: Signal<boolean>;
|
|
12
|
+
hasMoreProducts: Signal<boolean>;
|
|
13
|
+
loadMore: () => Promise<void>;
|
|
14
|
+
refresh: () => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare const CollectionServiceDefinition: string & {
|
|
17
|
+
__api: CollectionServiceAPI;
|
|
18
|
+
__config: {};
|
|
19
|
+
isServiceDefinition?: boolean;
|
|
20
|
+
} & CollectionServiceAPI;
|
|
21
|
+
export declare const CollectionService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
22
|
+
__api: CollectionServiceAPI;
|
|
23
|
+
__config: {};
|
|
24
|
+
isServiceDefinition?: boolean;
|
|
25
|
+
} & CollectionServiceAPI, {
|
|
26
|
+
initialProducts?: productsV3.V3Product[];
|
|
27
|
+
pageSize?: number;
|
|
28
|
+
initialCursor?: string;
|
|
29
|
+
initialHasMore?: boolean;
|
|
30
|
+
categories?: any[];
|
|
31
|
+
}, import("@wix/services-definitions").ThreadMode.MAIN>;
|
|
32
|
+
export declare function loadCollectionServiceConfig(categoryId?: string, searchParams?: URLSearchParams): Promise<ServiceFactoryConfig<typeof CollectionService> & {
|
|
33
|
+
initialCursor?: string;
|
|
34
|
+
initialHasMore?: boolean;
|
|
35
|
+
initialSort?: SortBy;
|
|
36
|
+
initialFilters?: Filter;
|
|
37
|
+
}>;
|