@wix/headless-stores 0.0.18 → 0.0.20
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/services/catalog-service.d.ts +35 -0
- package/{dist/services/catalog-options-service.js → cjs/dist/services/catalog-service.js} +55 -17
- package/cjs/dist/services/collection-service.d.ts +2 -2
- package/cjs/dist/services/collection-service.js +6 -7
- package/cjs/dist/services/filter-service.d.ts +2 -13
- package/cjs/dist/services/filter-service.js +8 -22
- package/cjs/dist/services/index.d.ts +1 -2
- package/cjs/dist/services/index.js +1 -2
- package/dist/services/catalog-service.d.ts +35 -0
- package/{cjs/dist/services/catalog-options-service.js → dist/services/catalog-service.js} +55 -17
- package/dist/services/collection-service.d.ts +2 -2
- package/dist/services/collection-service.js +6 -7
- package/dist/services/filter-service.d.ts +2 -13
- package/dist/services/filter-service.js +8 -22
- package/dist/services/index.d.ts +1 -2
- package/dist/services/index.js +1 -2
- package/package.json +3 -3
- package/astro/actions/package.json +0 -4
- package/cjs/dist/services/catalog-options-service.d.ts +0 -30
- package/cjs/dist/services/catalog-price-range-service.d.ts +0 -23
- package/cjs/dist/services/catalog-price-range-service.js +0 -93
- package/dist/services/catalog-options-service.d.ts +0 -30
- package/dist/services/catalog-price-range-service.d.ts +0 -23
- package/dist/services/catalog-price-range-service.js +0 -93
- package/react/package.json +0 -4
- package/server-actions/package.json +0 -4
- package/services/package.json +0 -4
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ServiceFactoryConfig } from "@wix/services-definitions";
|
|
2
|
+
import { type Signal } from "@wix/services-definitions/core-services/signals";
|
|
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 CatalogPriceRange {
|
|
15
|
+
minPrice: number;
|
|
16
|
+
maxPrice: number;
|
|
17
|
+
}
|
|
18
|
+
export interface CatalogServiceAPI {
|
|
19
|
+
catalogOptions: Signal<ProductOption[] | null>;
|
|
20
|
+
catalogPriceRange: Signal<CatalogPriceRange | null>;
|
|
21
|
+
isLoading: Signal<boolean>;
|
|
22
|
+
error: Signal<string | null>;
|
|
23
|
+
loadCatalogData: (categoryId?: string) => Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export declare const CatalogServiceDefinition: string & {
|
|
26
|
+
__api: CatalogServiceAPI;
|
|
27
|
+
__config: {};
|
|
28
|
+
isServiceDefinition?: boolean;
|
|
29
|
+
} & CatalogServiceAPI;
|
|
30
|
+
export declare const CatalogService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
31
|
+
__api: CatalogServiceAPI;
|
|
32
|
+
__config: {};
|
|
33
|
+
isServiceDefinition?: boolean;
|
|
34
|
+
} & CatalogServiceAPI, {}>;
|
|
35
|
+
export declare function loadCatalogServiceConfig(): Promise<ServiceFactoryConfig<typeof CatalogService>>;
|
|
@@ -9,6 +9,12 @@ const extractAggregationValues = (aggregationResponse, name) => {
|
|
|
9
9
|
aggregationResponse.aggregationData?.results?.find((r) => r.name === name);
|
|
10
10
|
return aggregation?.values?.results?.map((item) => item.value) || [];
|
|
11
11
|
};
|
|
12
|
+
const extractScalarAggregationValue = (aggregationResponse, name) => {
|
|
13
|
+
const aggregation = aggregationResponse.aggregations?.[name] ||
|
|
14
|
+
aggregationResponse.aggregationData?.results?.find((r) => r.name === name);
|
|
15
|
+
const value = aggregation?.scalar?.value;
|
|
16
|
+
return value !== undefined && value !== null ? parseFloat(value) : null;
|
|
17
|
+
};
|
|
12
18
|
const matchesAggregationName = (name, aggregationNames) => {
|
|
13
19
|
return aggregationNames.some((aggName) => aggName.toLowerCase() === name.toLowerCase());
|
|
14
20
|
};
|
|
@@ -37,19 +43,34 @@ const buildCategoryFilter = (categoryId) => {
|
|
|
37
43
|
},
|
|
38
44
|
};
|
|
39
45
|
};
|
|
40
|
-
export const
|
|
41
|
-
export const
|
|
46
|
+
export const CatalogServiceDefinition = defineService("catalog");
|
|
47
|
+
export const CatalogService = implementService.withConfig()(CatalogServiceDefinition, ({ getService }) => {
|
|
42
48
|
const signalsService = getService(SignalsServiceDefinition);
|
|
43
49
|
const catalogOptions = signalsService.signal(null);
|
|
50
|
+
const catalogPriceRange = signalsService.signal(null);
|
|
44
51
|
const isLoading = signalsService.signal(false);
|
|
45
52
|
const error = signalsService.signal(null);
|
|
46
|
-
const
|
|
53
|
+
const loadCatalogData = async (categoryId) => {
|
|
47
54
|
isLoading.set(true);
|
|
48
55
|
error.set(null);
|
|
49
56
|
try {
|
|
50
|
-
//
|
|
57
|
+
// Single aggregation request to get ALL catalog data at once
|
|
51
58
|
const aggregationRequest = {
|
|
52
59
|
aggregations: [
|
|
60
|
+
// Price range aggregations
|
|
61
|
+
{
|
|
62
|
+
name: "minPrice",
|
|
63
|
+
fieldPath: "actualPriceRange.minValue.amount",
|
|
64
|
+
type: "SCALAR",
|
|
65
|
+
scalar: { type: "MIN" },
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "maxPrice",
|
|
69
|
+
fieldPath: "actualPriceRange.maxValue.amount",
|
|
70
|
+
type: "SCALAR",
|
|
71
|
+
scalar: { type: "MAX" },
|
|
72
|
+
},
|
|
73
|
+
// Options aggregations
|
|
53
74
|
{
|
|
54
75
|
name: "optionNames",
|
|
55
76
|
fieldPath: "options.name",
|
|
@@ -85,16 +106,31 @@ export const CatalogOptionsService = implementService.withConfig()(CatalogOption
|
|
|
85
106
|
includeProducts: false,
|
|
86
107
|
cursorPaging: { limit: 0 },
|
|
87
108
|
};
|
|
88
|
-
|
|
109
|
+
// Make the single aggregation request
|
|
110
|
+
const [aggregationResponse, customizationsResponse] = await Promise.all([
|
|
111
|
+
productsV3.searchProducts(aggregationRequest),
|
|
112
|
+
customizationsV3.queryCustomizations().find(),
|
|
113
|
+
]);
|
|
114
|
+
// Process price range data
|
|
115
|
+
const minPrice = extractScalarAggregationValue(aggregationResponse, "minPrice");
|
|
116
|
+
const maxPrice = extractScalarAggregationValue(aggregationResponse, "maxPrice");
|
|
117
|
+
if (minPrice !== null &&
|
|
118
|
+
maxPrice !== null &&
|
|
119
|
+
(minPrice > 0 || maxPrice > 0)) {
|
|
120
|
+
catalogPriceRange.set({
|
|
121
|
+
minPrice,
|
|
122
|
+
maxPrice,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
catalogPriceRange.set(null);
|
|
127
|
+
}
|
|
128
|
+
// Process options data
|
|
89
129
|
const optionNames = extractAggregationValues(aggregationResponse, "optionNames");
|
|
90
130
|
const choiceNames = extractAggregationValues(aggregationResponse, "choiceNames");
|
|
91
131
|
const inventoryStatuses = extractAggregationValues(aggregationResponse, "inventoryStatus");
|
|
92
|
-
// Step 2: Get option structure from customizations API
|
|
93
|
-
const customizationsResponse = await customizationsV3
|
|
94
|
-
.queryCustomizations()
|
|
95
|
-
.find();
|
|
96
132
|
const customizations = customizationsResponse.items || [];
|
|
97
|
-
//
|
|
133
|
+
// Build options by matching customizations with aggregation data
|
|
98
134
|
const options = customizations
|
|
99
135
|
.filter((customization) => customization.name &&
|
|
100
136
|
customization._id &&
|
|
@@ -119,11 +155,11 @@ export const CatalogOptionsService = implementService.withConfig()(CatalogOption
|
|
|
119
155
|
};
|
|
120
156
|
})
|
|
121
157
|
.filter((option) => option.choices.length > 0);
|
|
122
|
-
//
|
|
158
|
+
// Add inventory filter if there are multiple inventory statuses
|
|
123
159
|
if (inventoryStatuses.length > 1) {
|
|
124
160
|
const inventoryChoices = inventoryStatuses.map((status) => ({
|
|
125
|
-
id: status.toUpperCase(),
|
|
126
|
-
name: status.toUpperCase(),
|
|
161
|
+
id: status.toUpperCase(),
|
|
162
|
+
name: status.toUpperCase(),
|
|
127
163
|
}));
|
|
128
164
|
options.push({
|
|
129
165
|
id: "inventory-filter",
|
|
@@ -135,9 +171,10 @@ export const CatalogOptionsService = implementService.withConfig()(CatalogOption
|
|
|
135
171
|
catalogOptions.set(options);
|
|
136
172
|
}
|
|
137
173
|
catch (err) {
|
|
138
|
-
console.error("Failed to load catalog
|
|
139
|
-
error.set(err instanceof Error ? err.message : "Failed to load catalog
|
|
174
|
+
console.error("Failed to load catalog data:", err);
|
|
175
|
+
error.set(err instanceof Error ? err.message : "Failed to load catalog data");
|
|
140
176
|
catalogOptions.set([]);
|
|
177
|
+
catalogPriceRange.set(null);
|
|
141
178
|
}
|
|
142
179
|
finally {
|
|
143
180
|
isLoading.set(false);
|
|
@@ -145,11 +182,12 @@ export const CatalogOptionsService = implementService.withConfig()(CatalogOption
|
|
|
145
182
|
};
|
|
146
183
|
return {
|
|
147
184
|
catalogOptions,
|
|
185
|
+
catalogPriceRange,
|
|
148
186
|
isLoading,
|
|
149
187
|
error,
|
|
150
|
-
|
|
188
|
+
loadCatalogData,
|
|
151
189
|
};
|
|
152
190
|
});
|
|
153
|
-
export async function
|
|
191
|
+
export async function loadCatalogServiceConfig() {
|
|
154
192
|
return {};
|
|
155
193
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ServiceFactoryConfig } from "@wix/services-definitions";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import type { Signal } from "@wix/services-definitions/core-services/signals";
|
|
3
|
+
import { productsV3 } from "@wix/stores";
|
|
4
4
|
import { type Filter } from "./filter-service.js";
|
|
5
5
|
import { type SortBy } from "./sort-service.js";
|
|
6
6
|
export interface CollectionServiceAPI {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { defineService, implementService, } from "@wix/services-definitions";
|
|
2
|
-
import { SignalsServiceDefinition
|
|
3
|
-
import
|
|
4
|
-
import * as readOnlyVariantsV3 from "@wix/auto_sdk_stores_read-only-variants-v-3";
|
|
2
|
+
import { SignalsServiceDefinition } from "@wix/services-definitions/core-services/signals";
|
|
3
|
+
import { productsV3, readOnlyVariantsV3 } from "@wix/stores";
|
|
5
4
|
import { FilterServiceDefinition } from "./filter-service.js";
|
|
6
5
|
import { CategoryServiceDefinition } from "./category-service.js";
|
|
7
6
|
import { SortServiceDefinition } from "./sort-service.js";
|
|
7
|
+
import { CatalogServiceDefinition } from "./catalog-service.js";
|
|
8
8
|
import { URLParamsUtils } from "../utils/url-params.js";
|
|
9
9
|
import { SortType } from "../enums/sort-enums.js";
|
|
10
10
|
const { SortDirection } = productsV3;
|
|
@@ -159,6 +159,7 @@ export const CollectionService = implementService.withConfig()(CollectionService
|
|
|
159
159
|
const collectionFilters = getService(FilterServiceDefinition);
|
|
160
160
|
const categoryService = getService(CategoryServiceDefinition);
|
|
161
161
|
const sortService = getService(SortServiceDefinition);
|
|
162
|
+
const catalogService = getService(CatalogServiceDefinition);
|
|
162
163
|
const hasMoreProducts = signalsService.signal((config.initialHasMore ?? true));
|
|
163
164
|
let nextCursor = config.initialCursor;
|
|
164
165
|
const initialProducts = config.initialProducts || [];
|
|
@@ -287,13 +288,11 @@ export const CollectionService = implementService.withConfig()(CollectionService
|
|
|
287
288
|
const initializeCatalogData = async () => {
|
|
288
289
|
isInitializingCatalogData = true; // Set flag BEFORE loading
|
|
289
290
|
const selectedCategory = categoryService.selectedCategory.get();
|
|
290
|
-
|
|
291
|
-
await
|
|
291
|
+
// Load catalog data from the combined catalog service
|
|
292
|
+
await catalogService.loadCatalogData(selectedCategory || undefined);
|
|
292
293
|
// Reset flag to allow filter changes to trigger refreshes
|
|
293
294
|
isInitializingCatalogData = false;
|
|
294
295
|
};
|
|
295
|
-
// Load catalog data on initialization
|
|
296
|
-
void initializeCatalogData();
|
|
297
296
|
signalsService.effect(() => {
|
|
298
297
|
sortService.currentSort.get();
|
|
299
298
|
debouncedRefresh(false);
|
|
@@ -1,14 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
id: string;
|
|
4
|
-
name: string;
|
|
5
|
-
choices: {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
colorCode?: string;
|
|
9
|
-
}[];
|
|
10
|
-
optionRenderType?: string;
|
|
11
|
-
}
|
|
1
|
+
import type { Signal, ReadOnlySignal } from "@wix/services-definitions/core-services/signals";
|
|
2
|
+
import { type ProductOption } from "./catalog-service.js";
|
|
12
3
|
export interface PriceRange {
|
|
13
4
|
min: number;
|
|
14
5
|
max: number;
|
|
@@ -37,8 +28,6 @@ export interface FilterServiceAPI {
|
|
|
37
28
|
max: number;
|
|
38
29
|
};
|
|
39
30
|
}>;
|
|
40
|
-
loadCatalogPriceRange: (categoryId?: string) => Promise<void>;
|
|
41
|
-
loadCatalogOptions: (categoryId?: string) => Promise<void>;
|
|
42
31
|
isFullyLoaded: ReadOnlySignal<boolean>;
|
|
43
32
|
}
|
|
44
33
|
export declare const FilterServiceDefinition: string & {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { defineService, implementService } from "@wix/services-definitions";
|
|
2
|
-
import { SignalsServiceDefinition
|
|
2
|
+
import { SignalsServiceDefinition } from "@wix/services-definitions/core-services/signals";
|
|
3
3
|
import { URLParamsUtils } from "../utils/url-params.js";
|
|
4
|
-
import {
|
|
5
|
-
import { CatalogOptionsServiceDefinition } from "./catalog-options-service.js";
|
|
4
|
+
import { CatalogServiceDefinition, } from "./catalog-service.js";
|
|
6
5
|
export const FilterServiceDefinition = defineService("filtered-collection");
|
|
7
6
|
export const defaultFilter = {
|
|
8
7
|
priceRange: { min: 0, max: 0 },
|
|
@@ -10,13 +9,12 @@ export const defaultFilter = {
|
|
|
10
9
|
};
|
|
11
10
|
export const FilterService = implementService.withConfig()(FilterServiceDefinition, ({ getService, config }) => {
|
|
12
11
|
const signalsService = getService(SignalsServiceDefinition);
|
|
13
|
-
const
|
|
14
|
-
const catalogOptionsService = getService(CatalogOptionsServiceDefinition);
|
|
12
|
+
const catalogService = getService(CatalogServiceDefinition);
|
|
15
13
|
const currentFilters = signalsService.signal((config?.initialFilters || defaultFilter));
|
|
16
14
|
// Use computed signal for availableOptions to automatically track dependencies
|
|
17
15
|
const availableOptions = signalsService.computed(() => {
|
|
18
|
-
const catalogPriceRange =
|
|
19
|
-
const catalogOptions =
|
|
16
|
+
const catalogPriceRange = catalogService.catalogPriceRange.get();
|
|
17
|
+
const catalogOptions = catalogService.catalogOptions.get();
|
|
20
18
|
const priceRange = catalogPriceRange &&
|
|
21
19
|
catalogPriceRange.minPrice < catalogPriceRange.maxPrice
|
|
22
20
|
? { min: catalogPriceRange.minPrice, max: catalogPriceRange.maxPrice }
|
|
@@ -29,8 +27,8 @@ export const FilterService = implementService.withConfig()(FilterServiceDefiniti
|
|
|
29
27
|
});
|
|
30
28
|
// Use computed signal for isFullyLoaded to automatically track dependencies
|
|
31
29
|
const isFullyLoaded = signalsService.computed(() => {
|
|
32
|
-
const catalogPriceRange =
|
|
33
|
-
const catalogOptions =
|
|
30
|
+
const catalogPriceRange = catalogService.catalogPriceRange.get();
|
|
31
|
+
const catalogOptions = catalogService.catalogOptions.get();
|
|
34
32
|
// Price range data is considered loaded whether it's null (no prices) or has valid data
|
|
35
33
|
const hasPriceRangeData = catalogPriceRange !== undefined; // includes null case
|
|
36
34
|
const hasOptionsData = !!(catalogOptions && catalogOptions.length >= 0); // Even 0 options is valid
|
|
@@ -38,7 +36,7 @@ export const FilterService = implementService.withConfig()(FilterServiceDefiniti
|
|
|
38
36
|
});
|
|
39
37
|
// Effect to update currentFilters when catalog data loads (only if filters are at defaults)
|
|
40
38
|
signalsService.effect(() => {
|
|
41
|
-
const catalogPriceRange =
|
|
39
|
+
const catalogPriceRange = catalogService.catalogPriceRange.get();
|
|
42
40
|
if (catalogPriceRange &&
|
|
43
41
|
catalogPriceRange.minPrice < catalogPriceRange.maxPrice) {
|
|
44
42
|
const priceRange = {
|
|
@@ -111,23 +109,11 @@ export const FilterService = implementService.withConfig()(FilterServiceDefiniti
|
|
|
111
109
|
}
|
|
112
110
|
URLParamsUtils.updateURL(urlParams);
|
|
113
111
|
};
|
|
114
|
-
// Note: calculateAvailableOptions was removed as it's no longer needed
|
|
115
|
-
// Options are now loaded from the catalog-wide service via loadCatalogOptions
|
|
116
|
-
const loadCatalogPriceRange = async (categoryId) => {
|
|
117
|
-
// Just call the catalog service - subscriptions will handle signal updates
|
|
118
|
-
await catalogPriceRangeService.loadCatalogPriceRange(categoryId);
|
|
119
|
-
};
|
|
120
|
-
const loadCatalogOptions = async (categoryId) => {
|
|
121
|
-
// Just call the catalog service - subscriptions will handle signal updates
|
|
122
|
-
await catalogOptionsService.loadCatalogOptions(categoryId);
|
|
123
|
-
};
|
|
124
112
|
return {
|
|
125
113
|
currentFilters,
|
|
126
114
|
applyFilters,
|
|
127
115
|
clearFilters,
|
|
128
116
|
availableOptions,
|
|
129
|
-
loadCatalogPriceRange,
|
|
130
|
-
loadCatalogOptions,
|
|
131
117
|
isFullyLoaded,
|
|
132
118
|
};
|
|
133
119
|
});
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export { buyNowServiceBinding, loadBuyNowServiceInitialData, } from "./buy-now-service.js";
|
|
2
2
|
export { payNowServiceBinding, loadPayNowServiceInitialData, } from "./pay-now-service.js";
|
|
3
|
-
export {
|
|
3
|
+
export { CatalogService, CatalogServiceDefinition, loadCatalogServiceConfig, } from "./catalog-service.js";
|
|
4
4
|
export { CategoryService, CategoryServiceDefinition, loadCategoriesConfig, } from "./category-service.js";
|
|
5
5
|
export { CollectionService, CollectionServiceDefinition, loadCollectionServiceConfig, } from "./collection-service.js";
|
|
6
|
-
export { CatalogPriceRangeService, CatalogPriceRangeServiceDefinition, loadCatalogPriceRangeServiceConfig, } from "./catalog-price-range-service.js";
|
|
7
6
|
export { FilterService, FilterServiceDefinition, Filter, AvailableOptions, } from "./filter-service.js";
|
|
8
7
|
export { ProductModifiersService, ProductModifiersServiceDefinition, } from "./product-modifiers-service.js";
|
|
9
8
|
export { ProductService, ProductServiceDefinition, loadProductServiceConfig, } from "./product-service.js";
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export { buyNowServiceBinding, loadBuyNowServiceInitialData, } from "./buy-now-service.js";
|
|
2
2
|
export { payNowServiceBinding, loadPayNowServiceInitialData, } from "./pay-now-service.js";
|
|
3
|
-
export {
|
|
3
|
+
export { CatalogService, CatalogServiceDefinition, loadCatalogServiceConfig, } from "./catalog-service.js";
|
|
4
4
|
export { CategoryService, CategoryServiceDefinition, loadCategoriesConfig, } from "./category-service.js";
|
|
5
5
|
export { CollectionService, CollectionServiceDefinition, loadCollectionServiceConfig, } from "./collection-service.js";
|
|
6
|
-
export { CatalogPriceRangeService, CatalogPriceRangeServiceDefinition, loadCatalogPriceRangeServiceConfig, } from "./catalog-price-range-service.js";
|
|
7
6
|
export { FilterService, FilterServiceDefinition, } from "./filter-service.js";
|
|
8
7
|
export { ProductModifiersService, ProductModifiersServiceDefinition, } from "./product-modifiers-service.js";
|
|
9
8
|
export { ProductService, ProductServiceDefinition, loadProductServiceConfig, } from "./product-service.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ServiceFactoryConfig } from "@wix/services-definitions";
|
|
2
|
+
import { type Signal } from "@wix/services-definitions/core-services/signals";
|
|
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 CatalogPriceRange {
|
|
15
|
+
minPrice: number;
|
|
16
|
+
maxPrice: number;
|
|
17
|
+
}
|
|
18
|
+
export interface CatalogServiceAPI {
|
|
19
|
+
catalogOptions: Signal<ProductOption[] | null>;
|
|
20
|
+
catalogPriceRange: Signal<CatalogPriceRange | null>;
|
|
21
|
+
isLoading: Signal<boolean>;
|
|
22
|
+
error: Signal<string | null>;
|
|
23
|
+
loadCatalogData: (categoryId?: string) => Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export declare const CatalogServiceDefinition: string & {
|
|
26
|
+
__api: CatalogServiceAPI;
|
|
27
|
+
__config: {};
|
|
28
|
+
isServiceDefinition?: boolean;
|
|
29
|
+
} & CatalogServiceAPI;
|
|
30
|
+
export declare const CatalogService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
31
|
+
__api: CatalogServiceAPI;
|
|
32
|
+
__config: {};
|
|
33
|
+
isServiceDefinition?: boolean;
|
|
34
|
+
} & CatalogServiceAPI, {}>;
|
|
35
|
+
export declare function loadCatalogServiceConfig(): Promise<ServiceFactoryConfig<typeof CatalogService>>;
|
|
@@ -9,6 +9,12 @@ const extractAggregationValues = (aggregationResponse, name) => {
|
|
|
9
9
|
aggregationResponse.aggregationData?.results?.find((r) => r.name === name);
|
|
10
10
|
return aggregation?.values?.results?.map((item) => item.value) || [];
|
|
11
11
|
};
|
|
12
|
+
const extractScalarAggregationValue = (aggregationResponse, name) => {
|
|
13
|
+
const aggregation = aggregationResponse.aggregations?.[name] ||
|
|
14
|
+
aggregationResponse.aggregationData?.results?.find((r) => r.name === name);
|
|
15
|
+
const value = aggregation?.scalar?.value;
|
|
16
|
+
return value !== undefined && value !== null ? parseFloat(value) : null;
|
|
17
|
+
};
|
|
12
18
|
const matchesAggregationName = (name, aggregationNames) => {
|
|
13
19
|
return aggregationNames.some((aggName) => aggName.toLowerCase() === name.toLowerCase());
|
|
14
20
|
};
|
|
@@ -37,19 +43,34 @@ const buildCategoryFilter = (categoryId) => {
|
|
|
37
43
|
},
|
|
38
44
|
};
|
|
39
45
|
};
|
|
40
|
-
export const
|
|
41
|
-
export const
|
|
46
|
+
export const CatalogServiceDefinition = defineService("catalog");
|
|
47
|
+
export const CatalogService = implementService.withConfig()(CatalogServiceDefinition, ({ getService }) => {
|
|
42
48
|
const signalsService = getService(SignalsServiceDefinition);
|
|
43
49
|
const catalogOptions = signalsService.signal(null);
|
|
50
|
+
const catalogPriceRange = signalsService.signal(null);
|
|
44
51
|
const isLoading = signalsService.signal(false);
|
|
45
52
|
const error = signalsService.signal(null);
|
|
46
|
-
const
|
|
53
|
+
const loadCatalogData = async (categoryId) => {
|
|
47
54
|
isLoading.set(true);
|
|
48
55
|
error.set(null);
|
|
49
56
|
try {
|
|
50
|
-
//
|
|
57
|
+
// Single aggregation request to get ALL catalog data at once
|
|
51
58
|
const aggregationRequest = {
|
|
52
59
|
aggregations: [
|
|
60
|
+
// Price range aggregations
|
|
61
|
+
{
|
|
62
|
+
name: "minPrice",
|
|
63
|
+
fieldPath: "actualPriceRange.minValue.amount",
|
|
64
|
+
type: "SCALAR",
|
|
65
|
+
scalar: { type: "MIN" },
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "maxPrice",
|
|
69
|
+
fieldPath: "actualPriceRange.maxValue.amount",
|
|
70
|
+
type: "SCALAR",
|
|
71
|
+
scalar: { type: "MAX" },
|
|
72
|
+
},
|
|
73
|
+
// Options aggregations
|
|
53
74
|
{
|
|
54
75
|
name: "optionNames",
|
|
55
76
|
fieldPath: "options.name",
|
|
@@ -85,16 +106,31 @@ export const CatalogOptionsService = implementService.withConfig()(CatalogOption
|
|
|
85
106
|
includeProducts: false,
|
|
86
107
|
cursorPaging: { limit: 0 },
|
|
87
108
|
};
|
|
88
|
-
|
|
109
|
+
// Make the single aggregation request
|
|
110
|
+
const [aggregationResponse, customizationsResponse] = await Promise.all([
|
|
111
|
+
productsV3.searchProducts(aggregationRequest),
|
|
112
|
+
customizationsV3.queryCustomizations().find(),
|
|
113
|
+
]);
|
|
114
|
+
// Process price range data
|
|
115
|
+
const minPrice = extractScalarAggregationValue(aggregationResponse, "minPrice");
|
|
116
|
+
const maxPrice = extractScalarAggregationValue(aggregationResponse, "maxPrice");
|
|
117
|
+
if (minPrice !== null &&
|
|
118
|
+
maxPrice !== null &&
|
|
119
|
+
(minPrice > 0 || maxPrice > 0)) {
|
|
120
|
+
catalogPriceRange.set({
|
|
121
|
+
minPrice,
|
|
122
|
+
maxPrice,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
catalogPriceRange.set(null);
|
|
127
|
+
}
|
|
128
|
+
// Process options data
|
|
89
129
|
const optionNames = extractAggregationValues(aggregationResponse, "optionNames");
|
|
90
130
|
const choiceNames = extractAggregationValues(aggregationResponse, "choiceNames");
|
|
91
131
|
const inventoryStatuses = extractAggregationValues(aggregationResponse, "inventoryStatus");
|
|
92
|
-
// Step 2: Get option structure from customizations API
|
|
93
|
-
const customizationsResponse = await customizationsV3
|
|
94
|
-
.queryCustomizations()
|
|
95
|
-
.find();
|
|
96
132
|
const customizations = customizationsResponse.items || [];
|
|
97
|
-
//
|
|
133
|
+
// Build options by matching customizations with aggregation data
|
|
98
134
|
const options = customizations
|
|
99
135
|
.filter((customization) => customization.name &&
|
|
100
136
|
customization._id &&
|
|
@@ -119,11 +155,11 @@ export const CatalogOptionsService = implementService.withConfig()(CatalogOption
|
|
|
119
155
|
};
|
|
120
156
|
})
|
|
121
157
|
.filter((option) => option.choices.length > 0);
|
|
122
|
-
//
|
|
158
|
+
// Add inventory filter if there are multiple inventory statuses
|
|
123
159
|
if (inventoryStatuses.length > 1) {
|
|
124
160
|
const inventoryChoices = inventoryStatuses.map((status) => ({
|
|
125
|
-
id: status.toUpperCase(),
|
|
126
|
-
name: status.toUpperCase(),
|
|
161
|
+
id: status.toUpperCase(),
|
|
162
|
+
name: status.toUpperCase(),
|
|
127
163
|
}));
|
|
128
164
|
options.push({
|
|
129
165
|
id: "inventory-filter",
|
|
@@ -135,9 +171,10 @@ export const CatalogOptionsService = implementService.withConfig()(CatalogOption
|
|
|
135
171
|
catalogOptions.set(options);
|
|
136
172
|
}
|
|
137
173
|
catch (err) {
|
|
138
|
-
console.error("Failed to load catalog
|
|
139
|
-
error.set(err instanceof Error ? err.message : "Failed to load catalog
|
|
174
|
+
console.error("Failed to load catalog data:", err);
|
|
175
|
+
error.set(err instanceof Error ? err.message : "Failed to load catalog data");
|
|
140
176
|
catalogOptions.set([]);
|
|
177
|
+
catalogPriceRange.set(null);
|
|
141
178
|
}
|
|
142
179
|
finally {
|
|
143
180
|
isLoading.set(false);
|
|
@@ -145,11 +182,12 @@ export const CatalogOptionsService = implementService.withConfig()(CatalogOption
|
|
|
145
182
|
};
|
|
146
183
|
return {
|
|
147
184
|
catalogOptions,
|
|
185
|
+
catalogPriceRange,
|
|
148
186
|
isLoading,
|
|
149
187
|
error,
|
|
150
|
-
|
|
188
|
+
loadCatalogData,
|
|
151
189
|
};
|
|
152
190
|
});
|
|
153
|
-
export async function
|
|
191
|
+
export async function loadCatalogServiceConfig() {
|
|
154
192
|
return {};
|
|
155
193
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ServiceFactoryConfig } from "@wix/services-definitions";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import type { Signal } from "@wix/services-definitions/core-services/signals";
|
|
3
|
+
import { productsV3 } from "@wix/stores";
|
|
4
4
|
import { type Filter } from "./filter-service.js";
|
|
5
5
|
import { type SortBy } from "./sort-service.js";
|
|
6
6
|
export interface CollectionServiceAPI {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { defineService, implementService, } from "@wix/services-definitions";
|
|
2
|
-
import { SignalsServiceDefinition
|
|
3
|
-
import
|
|
4
|
-
import * as readOnlyVariantsV3 from "@wix/auto_sdk_stores_read-only-variants-v-3";
|
|
2
|
+
import { SignalsServiceDefinition } from "@wix/services-definitions/core-services/signals";
|
|
3
|
+
import { productsV3, readOnlyVariantsV3 } from "@wix/stores";
|
|
5
4
|
import { FilterServiceDefinition } from "./filter-service.js";
|
|
6
5
|
import { CategoryServiceDefinition } from "./category-service.js";
|
|
7
6
|
import { SortServiceDefinition } from "./sort-service.js";
|
|
7
|
+
import { CatalogServiceDefinition } from "./catalog-service.js";
|
|
8
8
|
import { URLParamsUtils } from "../utils/url-params.js";
|
|
9
9
|
import { SortType } from "../enums/sort-enums.js";
|
|
10
10
|
const { SortDirection } = productsV3;
|
|
@@ -159,6 +159,7 @@ export const CollectionService = implementService.withConfig()(CollectionService
|
|
|
159
159
|
const collectionFilters = getService(FilterServiceDefinition);
|
|
160
160
|
const categoryService = getService(CategoryServiceDefinition);
|
|
161
161
|
const sortService = getService(SortServiceDefinition);
|
|
162
|
+
const catalogService = getService(CatalogServiceDefinition);
|
|
162
163
|
const hasMoreProducts = signalsService.signal((config.initialHasMore ?? true));
|
|
163
164
|
let nextCursor = config.initialCursor;
|
|
164
165
|
const initialProducts = config.initialProducts || [];
|
|
@@ -287,13 +288,11 @@ export const CollectionService = implementService.withConfig()(CollectionService
|
|
|
287
288
|
const initializeCatalogData = async () => {
|
|
288
289
|
isInitializingCatalogData = true; // Set flag BEFORE loading
|
|
289
290
|
const selectedCategory = categoryService.selectedCategory.get();
|
|
290
|
-
|
|
291
|
-
await
|
|
291
|
+
// Load catalog data from the combined catalog service
|
|
292
|
+
await catalogService.loadCatalogData(selectedCategory || undefined);
|
|
292
293
|
// Reset flag to allow filter changes to trigger refreshes
|
|
293
294
|
isInitializingCatalogData = false;
|
|
294
295
|
};
|
|
295
|
-
// Load catalog data on initialization
|
|
296
|
-
void initializeCatalogData();
|
|
297
296
|
signalsService.effect(() => {
|
|
298
297
|
sortService.currentSort.get();
|
|
299
298
|
debouncedRefresh(false);
|
|
@@ -1,14 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
id: string;
|
|
4
|
-
name: string;
|
|
5
|
-
choices: {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
colorCode?: string;
|
|
9
|
-
}[];
|
|
10
|
-
optionRenderType?: string;
|
|
11
|
-
}
|
|
1
|
+
import type { Signal, ReadOnlySignal } from "@wix/services-definitions/core-services/signals";
|
|
2
|
+
import { type ProductOption } from "./catalog-service.js";
|
|
12
3
|
export interface PriceRange {
|
|
13
4
|
min: number;
|
|
14
5
|
max: number;
|
|
@@ -37,8 +28,6 @@ export interface FilterServiceAPI {
|
|
|
37
28
|
max: number;
|
|
38
29
|
};
|
|
39
30
|
}>;
|
|
40
|
-
loadCatalogPriceRange: (categoryId?: string) => Promise<void>;
|
|
41
|
-
loadCatalogOptions: (categoryId?: string) => Promise<void>;
|
|
42
31
|
isFullyLoaded: ReadOnlySignal<boolean>;
|
|
43
32
|
}
|
|
44
33
|
export declare const FilterServiceDefinition: string & {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { defineService, implementService } from "@wix/services-definitions";
|
|
2
|
-
import { SignalsServiceDefinition
|
|
2
|
+
import { SignalsServiceDefinition } from "@wix/services-definitions/core-services/signals";
|
|
3
3
|
import { URLParamsUtils } from "../utils/url-params.js";
|
|
4
|
-
import {
|
|
5
|
-
import { CatalogOptionsServiceDefinition } from "./catalog-options-service.js";
|
|
4
|
+
import { CatalogServiceDefinition, } from "./catalog-service.js";
|
|
6
5
|
export const FilterServiceDefinition = defineService("filtered-collection");
|
|
7
6
|
export const defaultFilter = {
|
|
8
7
|
priceRange: { min: 0, max: 0 },
|
|
@@ -10,13 +9,12 @@ export const defaultFilter = {
|
|
|
10
9
|
};
|
|
11
10
|
export const FilterService = implementService.withConfig()(FilterServiceDefinition, ({ getService, config }) => {
|
|
12
11
|
const signalsService = getService(SignalsServiceDefinition);
|
|
13
|
-
const
|
|
14
|
-
const catalogOptionsService = getService(CatalogOptionsServiceDefinition);
|
|
12
|
+
const catalogService = getService(CatalogServiceDefinition);
|
|
15
13
|
const currentFilters = signalsService.signal((config?.initialFilters || defaultFilter));
|
|
16
14
|
// Use computed signal for availableOptions to automatically track dependencies
|
|
17
15
|
const availableOptions = signalsService.computed(() => {
|
|
18
|
-
const catalogPriceRange =
|
|
19
|
-
const catalogOptions =
|
|
16
|
+
const catalogPriceRange = catalogService.catalogPriceRange.get();
|
|
17
|
+
const catalogOptions = catalogService.catalogOptions.get();
|
|
20
18
|
const priceRange = catalogPriceRange &&
|
|
21
19
|
catalogPriceRange.minPrice < catalogPriceRange.maxPrice
|
|
22
20
|
? { min: catalogPriceRange.minPrice, max: catalogPriceRange.maxPrice }
|
|
@@ -29,8 +27,8 @@ export const FilterService = implementService.withConfig()(FilterServiceDefiniti
|
|
|
29
27
|
});
|
|
30
28
|
// Use computed signal for isFullyLoaded to automatically track dependencies
|
|
31
29
|
const isFullyLoaded = signalsService.computed(() => {
|
|
32
|
-
const catalogPriceRange =
|
|
33
|
-
const catalogOptions =
|
|
30
|
+
const catalogPriceRange = catalogService.catalogPriceRange.get();
|
|
31
|
+
const catalogOptions = catalogService.catalogOptions.get();
|
|
34
32
|
// Price range data is considered loaded whether it's null (no prices) or has valid data
|
|
35
33
|
const hasPriceRangeData = catalogPriceRange !== undefined; // includes null case
|
|
36
34
|
const hasOptionsData = !!(catalogOptions && catalogOptions.length >= 0); // Even 0 options is valid
|
|
@@ -38,7 +36,7 @@ export const FilterService = implementService.withConfig()(FilterServiceDefiniti
|
|
|
38
36
|
});
|
|
39
37
|
// Effect to update currentFilters when catalog data loads (only if filters are at defaults)
|
|
40
38
|
signalsService.effect(() => {
|
|
41
|
-
const catalogPriceRange =
|
|
39
|
+
const catalogPriceRange = catalogService.catalogPriceRange.get();
|
|
42
40
|
if (catalogPriceRange &&
|
|
43
41
|
catalogPriceRange.minPrice < catalogPriceRange.maxPrice) {
|
|
44
42
|
const priceRange = {
|
|
@@ -111,23 +109,11 @@ export const FilterService = implementService.withConfig()(FilterServiceDefiniti
|
|
|
111
109
|
}
|
|
112
110
|
URLParamsUtils.updateURL(urlParams);
|
|
113
111
|
};
|
|
114
|
-
// Note: calculateAvailableOptions was removed as it's no longer needed
|
|
115
|
-
// Options are now loaded from the catalog-wide service via loadCatalogOptions
|
|
116
|
-
const loadCatalogPriceRange = async (categoryId) => {
|
|
117
|
-
// Just call the catalog service - subscriptions will handle signal updates
|
|
118
|
-
await catalogPriceRangeService.loadCatalogPriceRange(categoryId);
|
|
119
|
-
};
|
|
120
|
-
const loadCatalogOptions = async (categoryId) => {
|
|
121
|
-
// Just call the catalog service - subscriptions will handle signal updates
|
|
122
|
-
await catalogOptionsService.loadCatalogOptions(categoryId);
|
|
123
|
-
};
|
|
124
112
|
return {
|
|
125
113
|
currentFilters,
|
|
126
114
|
applyFilters,
|
|
127
115
|
clearFilters,
|
|
128
116
|
availableOptions,
|
|
129
|
-
loadCatalogPriceRange,
|
|
130
|
-
loadCatalogOptions,
|
|
131
117
|
isFullyLoaded,
|
|
132
118
|
};
|
|
133
119
|
});
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export { buyNowServiceBinding, loadBuyNowServiceInitialData, } from "./buy-now-service.js";
|
|
2
2
|
export { payNowServiceBinding, loadPayNowServiceInitialData, } from "./pay-now-service.js";
|
|
3
|
-
export {
|
|
3
|
+
export { CatalogService, CatalogServiceDefinition, loadCatalogServiceConfig, } from "./catalog-service.js";
|
|
4
4
|
export { CategoryService, CategoryServiceDefinition, loadCategoriesConfig, } from "./category-service.js";
|
|
5
5
|
export { CollectionService, CollectionServiceDefinition, loadCollectionServiceConfig, } from "./collection-service.js";
|
|
6
|
-
export { CatalogPriceRangeService, CatalogPriceRangeServiceDefinition, loadCatalogPriceRangeServiceConfig, } from "./catalog-price-range-service.js";
|
|
7
6
|
export { FilterService, FilterServiceDefinition, Filter, AvailableOptions, } from "./filter-service.js";
|
|
8
7
|
export { ProductModifiersService, ProductModifiersServiceDefinition, } from "./product-modifiers-service.js";
|
|
9
8
|
export { ProductService, ProductServiceDefinition, loadProductServiceConfig, } from "./product-service.js";
|
package/dist/services/index.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export { buyNowServiceBinding, loadBuyNowServiceInitialData, } from "./buy-now-service.js";
|
|
2
2
|
export { payNowServiceBinding, loadPayNowServiceInitialData, } from "./pay-now-service.js";
|
|
3
|
-
export {
|
|
3
|
+
export { CatalogService, CatalogServiceDefinition, loadCatalogServiceConfig, } from "./catalog-service.js";
|
|
4
4
|
export { CategoryService, CategoryServiceDefinition, loadCategoriesConfig, } from "./category-service.js";
|
|
5
5
|
export { CollectionService, CollectionServiceDefinition, loadCollectionServiceConfig, } from "./collection-service.js";
|
|
6
|
-
export { CatalogPriceRangeService, CatalogPriceRangeServiceDefinition, loadCatalogPriceRangeServiceConfig, } from "./catalog-price-range-service.js";
|
|
7
6
|
export { FilterService, FilterServiceDefinition, } from "./filter-service.js";
|
|
8
7
|
export { ProductModifiersService, ProductModifiersServiceDefinition, } from "./product-modifiers-service.js";
|
|
9
8
|
export { ProductService, ProductServiceDefinition, loadProductServiceConfig, } from "./product-service.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/headless-stores",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"prebuild": "cd ../media && yarn build && cd ../ecom && yarn build",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"@wix/auto_sdk_stores_read-only-variants-v-3": "^1.0.23",
|
|
59
59
|
"@wix/ecom": "^1.0.1238",
|
|
60
60
|
"@wix/essentials": "^0.1.22",
|
|
61
|
-
"@wix/headless-ecom": "^0.0.
|
|
62
|
-
"@wix/headless-media": "^0.0.
|
|
61
|
+
"@wix/headless-ecom": "^0.0.7",
|
|
62
|
+
"@wix/headless-media": "^0.0.4",
|
|
63
63
|
"@wix/redirects": "^1.0.79",
|
|
64
64
|
"@wix/services-definitions": "^0.1.4",
|
|
65
65
|
"@wix/services-manager-react": "^0.1.26"
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { type ServiceFactoryConfig } from "@wix/services-definitions";
|
|
2
|
-
import { type Signal } from "@wix/services-definitions/core-services/signals";
|
|
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, {}>;
|
|
30
|
-
export declare function loadCatalogOptionsServiceConfig(): Promise<ServiceFactoryConfig<typeof CatalogOptionsService>>;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { type ServiceFactoryConfig } from "@wix/services-definitions";
|
|
2
|
-
import { type Signal } from "@wix/services-definitions/core-services/signals";
|
|
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, {}>;
|
|
23
|
-
export declare function loadCatalogPriceRangeServiceConfig(): Promise<ServiceFactoryConfig<typeof CatalogPriceRangeService>>;
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { defineService, implementService, } from "@wix/services-definitions";
|
|
2
|
-
import { SignalsServiceDefinition, } from "@wix/services-definitions/core-services/signals";
|
|
3
|
-
import * as productsV3 from "@wix/auto_sdk_stores_products-v-3";
|
|
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 &&
|
|
62
|
-
maxPrice !== null &&
|
|
63
|
-
(minPrice > 0 || maxPrice > 0)) {
|
|
64
|
-
catalogPriceRange.set({
|
|
65
|
-
minPrice,
|
|
66
|
-
maxPrice,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
// No products found or no valid prices - don't show the filter
|
|
71
|
-
catalogPriceRange.set(null);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
catch (err) {
|
|
75
|
-
console.error("Failed to load catalog price range:", err);
|
|
76
|
-
error.set(err instanceof Error ? err.message : "Failed to load price range");
|
|
77
|
-
// Don't set fallback values - let the component handle the error state
|
|
78
|
-
catalogPriceRange.set(null);
|
|
79
|
-
}
|
|
80
|
-
finally {
|
|
81
|
-
isLoading.set(false);
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
return {
|
|
85
|
-
catalogPriceRange,
|
|
86
|
-
isLoading,
|
|
87
|
-
error,
|
|
88
|
-
loadCatalogPriceRange,
|
|
89
|
-
};
|
|
90
|
-
});
|
|
91
|
-
export async function loadCatalogPriceRangeServiceConfig() {
|
|
92
|
-
return {};
|
|
93
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { type ServiceFactoryConfig } from "@wix/services-definitions";
|
|
2
|
-
import { type Signal } from "@wix/services-definitions/core-services/signals";
|
|
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, {}>;
|
|
30
|
-
export declare function loadCatalogOptionsServiceConfig(): Promise<ServiceFactoryConfig<typeof CatalogOptionsService>>;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { type ServiceFactoryConfig } from "@wix/services-definitions";
|
|
2
|
-
import { type Signal } from "@wix/services-definitions/core-services/signals";
|
|
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, {}>;
|
|
23
|
-
export declare function loadCatalogPriceRangeServiceConfig(): Promise<ServiceFactoryConfig<typeof CatalogPriceRangeService>>;
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { defineService, implementService, } from "@wix/services-definitions";
|
|
2
|
-
import { SignalsServiceDefinition, } from "@wix/services-definitions/core-services/signals";
|
|
3
|
-
import * as productsV3 from "@wix/auto_sdk_stores_products-v-3";
|
|
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 &&
|
|
62
|
-
maxPrice !== null &&
|
|
63
|
-
(minPrice > 0 || maxPrice > 0)) {
|
|
64
|
-
catalogPriceRange.set({
|
|
65
|
-
minPrice,
|
|
66
|
-
maxPrice,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
// No products found or no valid prices - don't show the filter
|
|
71
|
-
catalogPriceRange.set(null);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
catch (err) {
|
|
75
|
-
console.error("Failed to load catalog price range:", err);
|
|
76
|
-
error.set(err instanceof Error ? err.message : "Failed to load price range");
|
|
77
|
-
// Don't set fallback values - let the component handle the error state
|
|
78
|
-
catalogPriceRange.set(null);
|
|
79
|
-
}
|
|
80
|
-
finally {
|
|
81
|
-
isLoading.set(false);
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
return {
|
|
85
|
-
catalogPriceRange,
|
|
86
|
-
isLoading,
|
|
87
|
-
error,
|
|
88
|
-
loadCatalogPriceRange,
|
|
89
|
-
};
|
|
90
|
-
});
|
|
91
|
-
export async function loadCatalogPriceRangeServiceConfig() {
|
|
92
|
-
return {};
|
|
93
|
-
}
|
package/react/package.json
DELETED
package/services/package.json
DELETED