@wix/headless-stores 0.0.56 → 0.0.58
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/Category.d.ts +1 -0
- package/cjs/dist/react/Category.js +11 -22
- package/cjs/dist/react/CategoryList.js +2 -3
- package/cjs/dist/react/Product.d.ts +73 -30
- package/cjs/dist/react/Product.js +27 -145
- package/cjs/dist/react/ProductList.d.ts +9 -4
- package/cjs/dist/react/ProductList.js +4 -32
- package/cjs/dist/react/ProductListSort.d.ts +14 -0
- package/cjs/dist/react/ProductListSort.js +14 -0
- package/cjs/dist/react/core/ProductList.d.ts +3 -0
- package/cjs/dist/react/core/ProductList.js +2 -0
- package/cjs/dist/react/core/ProductListFilters.d.ts +8 -180
- package/cjs/dist/react/core/ProductListFilters.js +137 -171
- package/cjs/dist/react/core/ProductListPagination.d.ts +0 -192
- package/cjs/dist/react/core/ProductListPagination.js +2 -160
- package/cjs/dist/react/core/ProductListSort.d.ts +9 -57
- package/cjs/dist/react/core/ProductListSort.js +32 -52
- package/cjs/dist/react/core/SelectedVariant.js +2 -2
- package/cjs/dist/services/index.d.ts +2 -2
- package/cjs/dist/services/products-list-search-service.d.ts +3 -162
- package/cjs/dist/services/products-list-search-service.js +31 -424
- package/cjs/dist/services/products-list-service.d.ts +86 -4
- package/cjs/dist/services/products-list-service.js +125 -4
- package/cjs/dist/utils/renderChildren.d.ts +2 -1
- package/cjs/dist/utils/renderChildren.js +5 -2
- package/dist/react/Category.d.ts +1 -0
- package/dist/react/Category.js +11 -22
- package/dist/react/CategoryList.js +2 -3
- package/dist/react/Product.d.ts +73 -30
- package/dist/react/Product.js +27 -145
- package/dist/react/ProductList.d.ts +9 -4
- package/dist/react/ProductList.js +4 -32
- package/dist/react/ProductListSort.d.ts +14 -0
- package/dist/react/ProductListSort.js +14 -0
- package/dist/react/core/ProductList.d.ts +3 -0
- package/dist/react/core/ProductList.js +2 -0
- package/dist/react/core/ProductListFilters.d.ts +8 -180
- package/dist/react/core/ProductListFilters.js +137 -171
- package/dist/react/core/ProductListPagination.d.ts +0 -192
- package/dist/react/core/ProductListPagination.js +2 -160
- package/dist/react/core/ProductListSort.d.ts +9 -57
- package/dist/react/core/ProductListSort.js +32 -52
- package/dist/react/core/SelectedVariant.js +2 -2
- package/dist/services/index.d.ts +2 -2
- package/dist/services/products-list-search-service.d.ts +3 -162
- package/dist/services/products-list-search-service.js +31 -424
- package/dist/services/products-list-service.d.ts +86 -4
- package/dist/services/products-list-service.js +125 -4
- package/dist/utils/renderChildren.d.ts +2 -1
- package/dist/utils/renderChildren.js +5 -2
- package/package.json +4 -3
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
2
2
|
import { SignalsServiceDefinition } from '@wix/services-definitions/core-services/signals';
|
|
3
|
-
import { DEFAULT_QUERY_LIMIT
|
|
3
|
+
import { DEFAULT_QUERY_LIMIT } from './products-list-service.js';
|
|
4
4
|
import { productsV3, customizationsV3 } from '@wix/stores';
|
|
5
5
|
import { loadCategoriesListServiceConfig } from './categories-list-service.js';
|
|
6
|
-
const PRICE_FILTER_DEBOUNCE_TIME = 300;
|
|
7
6
|
import { SortType } from './../enums/sort-enums.js';
|
|
8
7
|
export { SortType } from './../enums/sort-enums.js';
|
|
9
8
|
/**
|
|
@@ -61,6 +60,7 @@ export function convertUrlSortToSortType(urlSort) {
|
|
|
61
60
|
/**
|
|
62
61
|
* Update URL with current search state (sort, filters, pagination)
|
|
63
62
|
*/
|
|
63
|
+
//@ts-expect-error
|
|
64
64
|
function updateUrlWithSearchState(searchState) {
|
|
65
65
|
if (typeof window === 'undefined')
|
|
66
66
|
return;
|
|
@@ -190,13 +190,9 @@ function updateUrlWithSearchState(searchState) {
|
|
|
190
190
|
* const filterState = initialSearchState.productOptions; // { colorId: ['red-id', 'blue-id'] }
|
|
191
191
|
* ```
|
|
192
192
|
*/
|
|
193
|
-
export async function parseUrlToSearchOptions(url, categoriesList, defaultSearchOptions) {
|
|
193
|
+
export async function parseUrlToSearchOptions(url, categoriesList, customizations, defaultSearchOptions) {
|
|
194
194
|
const urlObj = new URL(url);
|
|
195
195
|
const searchParams = urlObj.searchParams;
|
|
196
|
-
// Get customizations for product option parsing
|
|
197
|
-
const { items: customizations = [] } = await customizationsV3
|
|
198
|
-
.queryCustomizations()
|
|
199
|
-
.find();
|
|
200
196
|
// Build search options
|
|
201
197
|
const searchOptions = {
|
|
202
198
|
cursorPaging: {
|
|
@@ -325,6 +321,12 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
325
321
|
}
|
|
326
322
|
}
|
|
327
323
|
}
|
|
324
|
+
const inventoryStatus = searchParams.get('inventoryStatus');
|
|
325
|
+
if (inventoryStatus) {
|
|
326
|
+
filter['inventory.availabilityStatus'] = {
|
|
327
|
+
$in: inventoryStatus.split(','),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
328
330
|
// Parse product options from URL parameters
|
|
329
331
|
const reservedParams = [
|
|
330
332
|
'minPrice',
|
|
@@ -358,15 +360,15 @@ export async function parseUrlToSearchOptions(url, categoriesList, defaultSearch
|
|
|
358
360
|
}
|
|
359
361
|
if (choiceIds.length > 0) {
|
|
360
362
|
productOptionsById[option._id] = choiceIds;
|
|
361
|
-
// Add product option filter to search options
|
|
362
|
-
filter[`options.choicesSettings.choices.choiceId`] = {
|
|
363
|
-
$hasSome: choiceIds,
|
|
364
|
-
};
|
|
365
363
|
}
|
|
366
364
|
}
|
|
367
365
|
}
|
|
368
366
|
if (Object.keys(productOptionsById).length > 0) {
|
|
369
367
|
initialSearchState.productOptions = productOptionsById;
|
|
368
|
+
// Add product option filter to search options
|
|
369
|
+
filter[`options.choicesSettings.choices.choiceId`] = {
|
|
370
|
+
$hasSome: Object.values(productOptionsById).flat(),
|
|
371
|
+
};
|
|
370
372
|
}
|
|
371
373
|
// Add filter to search options if any filters were set
|
|
372
374
|
if (Object.keys(filter).length > 0) {
|
|
@@ -459,442 +461,47 @@ export async function loadProductsListSearchServiceConfig(input) {
|
|
|
459
461
|
if (typeof input === 'string') {
|
|
460
462
|
// URL input - parse it
|
|
461
463
|
const categoriesListConfig = await loadCategoriesListServiceConfig();
|
|
462
|
-
const {
|
|
464
|
+
const { items: customizations = [] } = await customizationsV3
|
|
465
|
+
.queryCustomizations()
|
|
466
|
+
.find();
|
|
467
|
+
const { initialSearchState: parsedState } = await parseUrlToSearchOptions(input, categoriesListConfig.categories, customizations);
|
|
463
468
|
initialSearchState = parsedState;
|
|
464
469
|
}
|
|
465
470
|
else {
|
|
466
471
|
// Parsed URL result - use initialSearchState directly (no duplicate work)
|
|
467
472
|
initialSearchState = input.initialSearchState;
|
|
468
473
|
}
|
|
469
|
-
const { items: customizations = [] } = await customizationsV3
|
|
470
|
-
.queryCustomizations()
|
|
471
|
-
.find();
|
|
472
474
|
return {
|
|
473
|
-
customizations,
|
|
474
475
|
initialSearchState,
|
|
475
476
|
};
|
|
476
477
|
}
|
|
477
478
|
/**
|
|
478
479
|
* Implementation of the Products List Search service
|
|
479
480
|
*/
|
|
480
|
-
export const ProductsListSearchService = implementService.withConfig()(ProductsListSearchServiceDefinition, ({ getService
|
|
481
|
+
export const ProductsListSearchService = implementService.withConfig()(ProductsListSearchServiceDefinition, ({ getService }) => {
|
|
481
482
|
let firstRun = true;
|
|
482
483
|
const signalsService = getService(SignalsServiceDefinition);
|
|
483
|
-
const productsListService = getService(ProductsListServiceDefinition);
|
|
484
|
-
const { customizations, initialSearchState } = config;
|
|
485
|
-
const aggregationData = productsListService.aggregations.get()?.results;
|
|
486
|
-
const currentSearchOptions = productsListService.searchOptions.get();
|
|
487
|
-
// Sort signals
|
|
488
|
-
const selectedSortOptionSignal = signalsService.signal(initialSearchState?.sort || SortType.NAME_ASC);
|
|
489
|
-
// Pagination signals
|
|
490
|
-
const currentLimitSignal = signalsService.signal(initialSearchState?.limit || getCurrentLimit(currentSearchOptions));
|
|
491
|
-
const currentCursorSignal = signalsService.signal(initialSearchState?.cursor || getCurrentCursor(currentSearchOptions));
|
|
492
|
-
// Filter signals
|
|
493
|
-
const catalogPriceRange = getCatalogPriceRange(aggregationData || []);
|
|
494
|
-
const userFilterMinPriceSignal = signalsService.signal(initialSearchState?.priceRange?.min ?? catalogPriceRange.minPrice);
|
|
495
|
-
const userFilterMaxPriceSignal = signalsService.signal(initialSearchState?.priceRange?.max ?? catalogPriceRange.maxPrice);
|
|
496
|
-
const catalogMinPriceSignal = signalsService.signal(catalogPriceRange.minPrice);
|
|
497
|
-
const catalogMaxPriceSignal = signalsService.signal(catalogPriceRange.maxPrice);
|
|
498
|
-
const availableInventoryStatusesSignal = signalsService.signal([
|
|
499
|
-
InventoryStatusType.IN_STOCK,
|
|
500
|
-
InventoryStatusType.OUT_OF_STOCK,
|
|
501
|
-
InventoryStatusType.PARTIALLY_OUT_OF_STOCK,
|
|
502
|
-
]);
|
|
503
|
-
const selectedInventoryStatusesSignal = signalsService.signal(initialSearchState?.inventoryStatuses || []);
|
|
504
|
-
const availableProductOptionsSignal = signalsService.signal(getAvailableProductOptions(aggregationData, customizations));
|
|
505
|
-
const selectedProductOptionsSignal = signalsService.signal(initialSearchState?.productOptions || {});
|
|
506
|
-
const selectedCategorySignal = signalsService.signal(initialSearchState?.category || null);
|
|
507
|
-
const selectedVisibleSignal = signalsService.signal(initialSearchState?.visible ?? null);
|
|
508
|
-
const selectedProductTypeSignal = signalsService.signal(initialSearchState?.productType || null);
|
|
509
|
-
// Computed signal to check if any filters are applied
|
|
510
|
-
const isFilteredSignal = signalsService.computed(() => {
|
|
511
|
-
const catalogPriceRange = getCatalogPriceRange(productsListService.aggregations.get()?.results || []);
|
|
512
|
-
const minPrice = userFilterMinPriceSignal.get();
|
|
513
|
-
const maxPrice = userFilterMaxPriceSignal.get();
|
|
514
|
-
const selectedInventoryStatuses = selectedInventoryStatusesSignal.get();
|
|
515
|
-
const selectedProductOptions = selectedProductOptionsSignal.get();
|
|
516
|
-
const selectedVisible = selectedVisibleSignal.get();
|
|
517
|
-
const selectedProductType = selectedProductTypeSignal.get();
|
|
518
|
-
// Check if any filters are different from default values
|
|
519
|
-
const hasPriceFilter = minPrice > catalogPriceRange.minPrice ||
|
|
520
|
-
maxPrice < catalogPriceRange.maxPrice;
|
|
521
|
-
const hasInventoryFilter = selectedInventoryStatuses.length > 0;
|
|
522
|
-
const hasProductOptionsFilter = Object.keys(selectedProductOptions).length > 0;
|
|
523
|
-
const hasVisibilityFilter = selectedVisible !== null;
|
|
524
|
-
const hasProductTypeFilter = selectedProductType !== null;
|
|
525
|
-
return (hasPriceFilter ||
|
|
526
|
-
hasInventoryFilter ||
|
|
527
|
-
hasProductOptionsFilter ||
|
|
528
|
-
hasVisibilityFilter ||
|
|
529
|
-
hasProductTypeFilter);
|
|
530
|
-
});
|
|
531
|
-
// Computed signals for pagination
|
|
532
|
-
const hasNextPageSignal = signalsService.computed(() => {
|
|
533
|
-
const pagingMetadata = productsListService.pagingMetadata.get();
|
|
534
|
-
return pagingMetadata?.hasNext || false;
|
|
535
|
-
});
|
|
536
|
-
const hasPrevPageSignal = signalsService.computed(() => {
|
|
537
|
-
const pagingMetadata = productsListService.pagingMetadata.get();
|
|
538
|
-
return typeof pagingMetadata.cursors?.prev !== 'undefined';
|
|
539
|
-
});
|
|
540
|
-
// Debounce timeout IDs for price filters
|
|
541
|
-
let minPriceTimeoutId = null;
|
|
542
|
-
let maxPriceTimeoutId = null;
|
|
543
484
|
if (typeof window !== 'undefined') {
|
|
544
485
|
// Watch for changes in any search parameters and update search options
|
|
545
486
|
signalsService.effect(() => {
|
|
546
487
|
// Read all signals to establish dependencies
|
|
547
|
-
const sort = selectedSortOptionSignal.get();
|
|
548
|
-
const limit = currentLimitSignal.get();
|
|
549
|
-
const cursor = currentCursorSignal.get();
|
|
550
|
-
const minPrice = userFilterMinPriceSignal.get();
|
|
551
|
-
const maxPrice = userFilterMaxPriceSignal.get();
|
|
552
|
-
const selectedInventoryStatuses = selectedInventoryStatusesSignal.get();
|
|
553
|
-
const selectedProductOptions = selectedProductOptionsSignal.get();
|
|
554
|
-
const selectedCategory = selectedCategorySignal.get();
|
|
555
|
-
const selectedVisible = selectedVisibleSignal.get();
|
|
556
|
-
const selectedProductType = selectedProductTypeSignal.get();
|
|
557
488
|
if (firstRun) {
|
|
558
489
|
firstRun = false;
|
|
559
490
|
return;
|
|
560
491
|
}
|
|
561
|
-
//
|
|
562
|
-
const
|
|
563
|
-
|
|
564
|
-
}
|
|
565
|
-
//
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
delete newSearchOptions.cursorPaging;
|
|
574
|
-
}
|
|
575
|
-
// Update sort
|
|
576
|
-
switch (sort) {
|
|
577
|
-
case SortType.NAME_ASC:
|
|
578
|
-
newSearchOptions.sort = [
|
|
579
|
-
{ fieldName: 'name', order: productsV3.SortDirection.ASC },
|
|
580
|
-
];
|
|
581
|
-
break;
|
|
582
|
-
case SortType.NAME_DESC:
|
|
583
|
-
newSearchOptions.sort = [
|
|
584
|
-
{ fieldName: 'name', order: productsV3.SortDirection.DESC },
|
|
585
|
-
];
|
|
586
|
-
break;
|
|
587
|
-
case SortType.PRICE_ASC:
|
|
588
|
-
newSearchOptions.sort = [
|
|
589
|
-
{
|
|
590
|
-
fieldName: 'actualPriceRange.minValue.amount',
|
|
591
|
-
order: productsV3.SortDirection.ASC,
|
|
592
|
-
},
|
|
593
|
-
];
|
|
594
|
-
break;
|
|
595
|
-
case SortType.PRICE_DESC:
|
|
596
|
-
newSearchOptions.sort = [
|
|
597
|
-
{
|
|
598
|
-
fieldName: 'actualPriceRange.minValue.amount',
|
|
599
|
-
order: productsV3.SortDirection.DESC,
|
|
600
|
-
},
|
|
601
|
-
];
|
|
602
|
-
break;
|
|
603
|
-
case SortType.RECOMMENDED:
|
|
604
|
-
newSearchOptions.sort = [
|
|
605
|
-
{
|
|
606
|
-
fieldName: 'name',
|
|
607
|
-
order: productsV3.SortDirection.DESC,
|
|
608
|
-
},
|
|
609
|
-
];
|
|
610
|
-
break;
|
|
611
|
-
}
|
|
612
|
-
// Update filters
|
|
613
|
-
if (!newSearchOptions.filter) {
|
|
614
|
-
newSearchOptions.filter = {};
|
|
615
|
-
}
|
|
616
|
-
else {
|
|
617
|
-
newSearchOptions.filter = { ...newSearchOptions.filter };
|
|
618
|
-
}
|
|
619
|
-
// Remove existing filters
|
|
620
|
-
delete newSearchOptions.filter['actualPriceRange.minValue.amount'];
|
|
621
|
-
delete newSearchOptions.filter['actualPriceRange.maxValue.amount'];
|
|
622
|
-
delete newSearchOptions.filter['inventory.availabilityStatus'];
|
|
623
|
-
delete newSearchOptions.filter['allCategoriesInfo.categories'];
|
|
624
|
-
delete newSearchOptions.filter['visible'];
|
|
625
|
-
delete newSearchOptions.filter['productType'];
|
|
626
|
-
// Remove existing product option filters
|
|
627
|
-
Object.keys(newSearchOptions.filter).forEach((key) => {
|
|
628
|
-
if (key.startsWith('options.')) {
|
|
629
|
-
delete newSearchOptions.filter[key];
|
|
630
|
-
}
|
|
631
|
-
});
|
|
632
|
-
// Add new filters
|
|
633
|
-
if (minPrice > 0) {
|
|
634
|
-
newSearchOptions.filter['actualPriceRange.minValue.amount'] = { $gte: minPrice };
|
|
635
|
-
}
|
|
636
|
-
if (maxPrice > 0) {
|
|
637
|
-
newSearchOptions.filter['actualPriceRange.maxValue.amount'] = { $lte: maxPrice };
|
|
638
|
-
}
|
|
639
|
-
if (selectedInventoryStatuses.length > 0) {
|
|
640
|
-
if (selectedInventoryStatuses.length === 1) {
|
|
641
|
-
newSearchOptions.filter['inventory.availabilityStatus'] =
|
|
642
|
-
selectedInventoryStatuses[0];
|
|
643
|
-
}
|
|
644
|
-
else {
|
|
645
|
-
newSearchOptions.filter['inventory.availabilityStatus'] =
|
|
646
|
-
{ $in: selectedInventoryStatuses };
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
if (selectedProductOptions &&
|
|
650
|
-
Object.keys(selectedProductOptions).length > 0) {
|
|
651
|
-
const allChoiceIds = [];
|
|
652
|
-
for (const choiceIds of Object.values(selectedProductOptions)) {
|
|
653
|
-
allChoiceIds.push(...choiceIds);
|
|
654
|
-
}
|
|
655
|
-
if (allChoiceIds.length > 0) {
|
|
656
|
-
newSearchOptions.filter['options.choicesSettings.choices.choiceId'] = { $hasSome: allChoiceIds };
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
if (selectedCategory) {
|
|
660
|
-
newSearchOptions.filter['allCategoriesInfo.categories'] = {
|
|
661
|
-
$matchItems: [{ _id: { $in: [selectedCategory._id] } }],
|
|
662
|
-
};
|
|
663
|
-
}
|
|
664
|
-
if (selectedVisible !== null) {
|
|
665
|
-
newSearchOptions.filter['visible'] = selectedVisible;
|
|
666
|
-
}
|
|
667
|
-
if (selectedProductType) {
|
|
668
|
-
newSearchOptions.filter['productType'] =
|
|
669
|
-
selectedProductType;
|
|
670
|
-
}
|
|
671
|
-
// Update the products list service
|
|
672
|
-
productsListService.setSearchOptions(newSearchOptions);
|
|
673
|
-
// Update URL with current search state
|
|
674
|
-
const catalogBounds = {
|
|
675
|
-
minPrice: catalogMinPriceSignal.get(),
|
|
676
|
-
maxPrice: catalogMaxPriceSignal.get(),
|
|
677
|
-
};
|
|
678
|
-
const currentFilters = {
|
|
679
|
-
priceRange: { min: minPrice, max: maxPrice },
|
|
680
|
-
inventoryStatuses: selectedInventoryStatuses,
|
|
681
|
-
productOptions: selectedProductOptions,
|
|
682
|
-
...(selectedVisible !== null && { visible: selectedVisible }),
|
|
683
|
-
...(selectedProductType && { productType: selectedProductType }),
|
|
684
|
-
};
|
|
685
|
-
updateUrlWithSearchState({
|
|
686
|
-
sort,
|
|
687
|
-
filters: currentFilters,
|
|
688
|
-
customizations,
|
|
689
|
-
catalogBounds,
|
|
690
|
-
categorySlug: selectedCategory?.slug || undefined,
|
|
691
|
-
});
|
|
492
|
+
// TODO fix it blat
|
|
493
|
+
// const currentFilters = {
|
|
494
|
+
// ...(selectedVisible !== null && { visible: selectedVisible }),
|
|
495
|
+
// ...(selectedProductType && { productType: selectedProductType }),
|
|
496
|
+
// };
|
|
497
|
+
// updateUrlWithSearchState({
|
|
498
|
+
// sort,
|
|
499
|
+
// filters: currentFilters,
|
|
500
|
+
// customizations,
|
|
501
|
+
// catalogBounds,
|
|
502
|
+
// categorySlug: selectedCategory?.slug || undefined,
|
|
503
|
+
// });
|
|
692
504
|
});
|
|
693
505
|
}
|
|
694
|
-
return {
|
|
695
|
-
// Sort functionality
|
|
696
|
-
selectedSortOption: selectedSortOptionSignal,
|
|
697
|
-
sortOptions: Object.values(SortType),
|
|
698
|
-
setSelectedSortOption: (sort) => selectedSortOptionSignal.set(sort),
|
|
699
|
-
// Pagination functionality
|
|
700
|
-
currentLimit: currentLimitSignal,
|
|
701
|
-
currentCursor: currentCursorSignal,
|
|
702
|
-
hasNextPage: hasNextPageSignal,
|
|
703
|
-
hasPrevPage: hasPrevPageSignal,
|
|
704
|
-
setLimit: (limit) => {
|
|
705
|
-
currentLimitSignal.set(limit);
|
|
706
|
-
currentCursorSignal.set(null); // Reset pagination when changing page size
|
|
707
|
-
},
|
|
708
|
-
loadMore: (count) => {
|
|
709
|
-
const limit = currentLimitSignal.get();
|
|
710
|
-
currentLimitSignal.set(limit + count);
|
|
711
|
-
},
|
|
712
|
-
nextPage: () => {
|
|
713
|
-
const pagingMetadata = productsListService.pagingMetadata.get();
|
|
714
|
-
const nextCursor = pagingMetadata?.cursors?.next;
|
|
715
|
-
if (nextCursor) {
|
|
716
|
-
currentCursorSignal.set(nextCursor);
|
|
717
|
-
}
|
|
718
|
-
},
|
|
719
|
-
prevPage: () => {
|
|
720
|
-
const pagingMetadata = productsListService.pagingMetadata.get();
|
|
721
|
-
const previousCursor = pagingMetadata?.cursors?.prev;
|
|
722
|
-
if (previousCursor) {
|
|
723
|
-
currentCursorSignal.set(previousCursor);
|
|
724
|
-
}
|
|
725
|
-
},
|
|
726
|
-
navigateToFirstPage: () => {
|
|
727
|
-
currentCursorSignal.set(null);
|
|
728
|
-
},
|
|
729
|
-
// Filter functionality
|
|
730
|
-
selectedMinPrice: userFilterMinPriceSignal,
|
|
731
|
-
selectedMaxPrice: userFilterMaxPriceSignal,
|
|
732
|
-
availableMinPrice: catalogMinPriceSignal,
|
|
733
|
-
availableMaxPrice: catalogMaxPriceSignal,
|
|
734
|
-
availableInventoryStatuses: availableInventoryStatusesSignal,
|
|
735
|
-
selectedInventoryStatuses: selectedInventoryStatusesSignal,
|
|
736
|
-
availableProductOptions: availableProductOptionsSignal,
|
|
737
|
-
selectedProductOptions: selectedProductOptionsSignal,
|
|
738
|
-
selectedCategory: selectedCategorySignal,
|
|
739
|
-
setSelectedMinPrice: (minPrice) => {
|
|
740
|
-
if (minPriceTimeoutId) {
|
|
741
|
-
clearTimeout(minPriceTimeoutId);
|
|
742
|
-
}
|
|
743
|
-
minPriceTimeoutId = setTimeout(() => {
|
|
744
|
-
userFilterMinPriceSignal.set(minPrice);
|
|
745
|
-
minPriceTimeoutId = null;
|
|
746
|
-
}, PRICE_FILTER_DEBOUNCE_TIME);
|
|
747
|
-
},
|
|
748
|
-
setSelectedMaxPrice: (maxPrice) => {
|
|
749
|
-
if (maxPriceTimeoutId) {
|
|
750
|
-
clearTimeout(maxPriceTimeoutId);
|
|
751
|
-
}
|
|
752
|
-
maxPriceTimeoutId = setTimeout(() => {
|
|
753
|
-
userFilterMaxPriceSignal.set(maxPrice);
|
|
754
|
-
maxPriceTimeoutId = null;
|
|
755
|
-
}, PRICE_FILTER_DEBOUNCE_TIME);
|
|
756
|
-
},
|
|
757
|
-
toggleInventoryStatus: (status) => {
|
|
758
|
-
const current = selectedInventoryStatusesSignal.get();
|
|
759
|
-
const isSelected = current.includes(status);
|
|
760
|
-
if (isSelected) {
|
|
761
|
-
selectedInventoryStatusesSignal.set(current.filter((s) => s !== status));
|
|
762
|
-
}
|
|
763
|
-
else {
|
|
764
|
-
selectedInventoryStatusesSignal.set([...current, status]);
|
|
765
|
-
}
|
|
766
|
-
},
|
|
767
|
-
toggleProductOption: (optionId, choiceId) => {
|
|
768
|
-
const current = selectedProductOptionsSignal.get();
|
|
769
|
-
const currentChoices = current[optionId] || [];
|
|
770
|
-
const isSelected = currentChoices.includes(choiceId);
|
|
771
|
-
if (isSelected) {
|
|
772
|
-
const newChoices = currentChoices.filter((id) => id !== choiceId);
|
|
773
|
-
if (newChoices.length === 0) {
|
|
774
|
-
const newOptions = { ...current };
|
|
775
|
-
delete newOptions[optionId];
|
|
776
|
-
selectedProductOptionsSignal.set(newOptions);
|
|
777
|
-
}
|
|
778
|
-
else {
|
|
779
|
-
selectedProductOptionsSignal.set({
|
|
780
|
-
...current,
|
|
781
|
-
[optionId]: newChoices,
|
|
782
|
-
});
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
else {
|
|
786
|
-
selectedProductOptionsSignal.set({
|
|
787
|
-
...current,
|
|
788
|
-
[optionId]: [...currentChoices, choiceId],
|
|
789
|
-
});
|
|
790
|
-
}
|
|
791
|
-
},
|
|
792
|
-
setSelectedCategory: (category) => {
|
|
793
|
-
selectedCategorySignal.set(category);
|
|
794
|
-
},
|
|
795
|
-
setSelectedVisible: (visible) => {
|
|
796
|
-
selectedVisibleSignal.set(visible);
|
|
797
|
-
},
|
|
798
|
-
setSelectedProductType: (productType) => {
|
|
799
|
-
selectedProductTypeSignal.set(productType);
|
|
800
|
-
},
|
|
801
|
-
isFiltered: isFilteredSignal,
|
|
802
|
-
reset: () => {
|
|
803
|
-
selectedSortOptionSignal.set(SortType.NAME_ASC);
|
|
804
|
-
currentLimitSignal.set(DEFAULT_QUERY_LIMIT);
|
|
805
|
-
currentCursorSignal.set(null);
|
|
806
|
-
userFilterMinPriceSignal.set(catalogMinPriceSignal.get());
|
|
807
|
-
userFilterMaxPriceSignal.set(catalogMaxPriceSignal.get());
|
|
808
|
-
selectedInventoryStatusesSignal.set([]);
|
|
809
|
-
selectedProductOptionsSignal.set({});
|
|
810
|
-
selectedVisibleSignal.set(null);
|
|
811
|
-
selectedProductTypeSignal.set(null);
|
|
812
|
-
},
|
|
813
|
-
};
|
|
506
|
+
return {};
|
|
814
507
|
});
|
|
815
|
-
// Helper functions (copied from the original services)
|
|
816
|
-
function getCurrentLimit(searchOptions) {
|
|
817
|
-
return searchOptions.cursorPaging?.limit || DEFAULT_QUERY_LIMIT;
|
|
818
|
-
}
|
|
819
|
-
function getCurrentCursor(searchOptions) {
|
|
820
|
-
return searchOptions.cursorPaging?.cursor || null;
|
|
821
|
-
}
|
|
822
|
-
function getCatalogPriceRange(aggregationData) {
|
|
823
|
-
const minPrice = getMinPrice(aggregationData);
|
|
824
|
-
const maxPrice = getMaxPrice(aggregationData);
|
|
825
|
-
return { minPrice, maxPrice };
|
|
826
|
-
}
|
|
827
|
-
function getMinPrice(aggregationData) {
|
|
828
|
-
const minPriceAggregation = aggregationData.find((data) => data.fieldPath === 'actualPriceRange.minValue.amount');
|
|
829
|
-
if (minPriceAggregation?.scalar?.value) {
|
|
830
|
-
return Number(minPriceAggregation.scalar.value) || 0;
|
|
831
|
-
}
|
|
832
|
-
return 0;
|
|
833
|
-
}
|
|
834
|
-
function getMaxPrice(aggregationData) {
|
|
835
|
-
const maxPriceAggregation = aggregationData.find((data) => data.fieldPath === 'actualPriceRange.maxValue.amount');
|
|
836
|
-
if (maxPriceAggregation?.scalar?.value) {
|
|
837
|
-
return Number(maxPriceAggregation.scalar.value) || 0;
|
|
838
|
-
}
|
|
839
|
-
return 0;
|
|
840
|
-
}
|
|
841
|
-
function getAvailableProductOptions(aggregationData = [], customizations = []) {
|
|
842
|
-
const matchesAggregationName = (name, aggregationNames) => {
|
|
843
|
-
return aggregationNames.some((aggName) => aggName.toLowerCase() === name.toLowerCase());
|
|
844
|
-
};
|
|
845
|
-
const sortChoicesIntelligently = (choices) => {
|
|
846
|
-
return [...choices].sort((a, b) => {
|
|
847
|
-
const aIsNumber = /^\d+$/.test(a.name);
|
|
848
|
-
const bIsNumber = /^\d+$/.test(b.name);
|
|
849
|
-
if (aIsNumber && bIsNumber) {
|
|
850
|
-
return parseInt(a.name) - parseInt(b.name);
|
|
851
|
-
}
|
|
852
|
-
if (aIsNumber && !bIsNumber)
|
|
853
|
-
return -1;
|
|
854
|
-
if (!aIsNumber && bIsNumber)
|
|
855
|
-
return 1;
|
|
856
|
-
return a.name.localeCompare(b.name);
|
|
857
|
-
});
|
|
858
|
-
};
|
|
859
|
-
const optionNames = [];
|
|
860
|
-
const choiceNames = [];
|
|
861
|
-
aggregationData.forEach((result) => {
|
|
862
|
-
if (result.name === 'optionNames' && result.values?.results) {
|
|
863
|
-
optionNames.push(...result.values.results
|
|
864
|
-
.map((item) => item.value)
|
|
865
|
-
.filter((value) => typeof value === 'string'));
|
|
866
|
-
}
|
|
867
|
-
if (result.name === 'choiceNames' && result.values?.results) {
|
|
868
|
-
choiceNames.push(...result.values.results
|
|
869
|
-
.map((item) => item.value)
|
|
870
|
-
.filter((value) => typeof value === 'string'));
|
|
871
|
-
}
|
|
872
|
-
});
|
|
873
|
-
const options = customizations
|
|
874
|
-
.filter((customization) => customization.name &&
|
|
875
|
-
customization._id &&
|
|
876
|
-
customization.customizationType ===
|
|
877
|
-
customizationsV3.CustomizationType.PRODUCT_OPTION &&
|
|
878
|
-
(optionNames.length === 0 ||
|
|
879
|
-
matchesAggregationName(customization.name, optionNames)))
|
|
880
|
-
.map((customization) => {
|
|
881
|
-
const choices = (customization.choicesSettings?.choices || [])
|
|
882
|
-
.filter((choice) => choice._id &&
|
|
883
|
-
choice.name &&
|
|
884
|
-
(choiceNames.length === 0 ||
|
|
885
|
-
matchesAggregationName(choice.name, choiceNames)))
|
|
886
|
-
.map((choice) => ({
|
|
887
|
-
id: choice._id,
|
|
888
|
-
name: choice.name,
|
|
889
|
-
colorCode: choice.colorCode,
|
|
890
|
-
}));
|
|
891
|
-
return {
|
|
892
|
-
id: customization._id,
|
|
893
|
-
name: customization.name,
|
|
894
|
-
choices: sortChoicesIntelligently(choices),
|
|
895
|
-
optionRenderType: customization.customizationRenderType,
|
|
896
|
-
};
|
|
897
|
-
})
|
|
898
|
-
.filter((option) => option.choices.length > 0);
|
|
899
|
-
return options;
|
|
900
|
-
}
|
|
@@ -1,7 +1,24 @@
|
|
|
1
|
-
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
2
|
-
import { productsV3 } from '@wix/stores';
|
|
3
|
-
import {
|
|
1
|
+
import { type Signal, type ReadOnlySignal } from '@wix/services-definitions/core-services/signals';
|
|
2
|
+
import { customizationsV3, productsV3 } from '@wix/stores';
|
|
3
|
+
import { InventoryStatusType } from './products-list-search-service.js';
|
|
4
4
|
export declare const DEFAULT_QUERY_LIMIT = 100;
|
|
5
|
+
/**
|
|
6
|
+
* Interface representing a product option (like Size, Color, etc.).
|
|
7
|
+
*/
|
|
8
|
+
export interface ProductOption {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
choices: ProductChoice[];
|
|
12
|
+
optionRenderType?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Interface representing a choice within a product option.
|
|
16
|
+
*/
|
|
17
|
+
export interface ProductChoice {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
colorCode?: string;
|
|
21
|
+
}
|
|
5
22
|
/**
|
|
6
23
|
* Configuration interface for the Products List service.
|
|
7
24
|
* Contains the initial products data, search options, and metadata.
|
|
@@ -17,6 +34,8 @@ export type ProductsListServiceConfig = {
|
|
|
17
34
|
pagingMetadata: productsV3.CommonCursorPagingMetadata;
|
|
18
35
|
/** Aggregation data containing filters, facets, and counts */
|
|
19
36
|
aggregations: productsV3.AggregationData;
|
|
37
|
+
/** Customizations used to fetch the products */
|
|
38
|
+
customizations: customizationsV3.Customization[];
|
|
20
39
|
};
|
|
21
40
|
/**
|
|
22
41
|
* Loads products list service configuration from the Wix Stores API for SSR initialization.
|
|
@@ -132,7 +151,6 @@ export type ProductsListServiceConfig = {
|
|
|
132
151
|
*/
|
|
133
152
|
export declare function loadProductsListServiceConfig(input: string | {
|
|
134
153
|
searchOptions: productsV3.V3ProductSearch;
|
|
135
|
-
initialSearchState: InitialSearchState;
|
|
136
154
|
}): Promise<ProductsListServiceConfig>;
|
|
137
155
|
/**
|
|
138
156
|
* Service definition for the Products List service.
|
|
@@ -154,12 +172,28 @@ export declare const ProductsListServiceDefinition: string & {
|
|
|
154
172
|
isLoading: Signal<boolean>;
|
|
155
173
|
/** Reactive signal containing any error message, or null if no error */
|
|
156
174
|
error: Signal<string | null>;
|
|
175
|
+
/** Reactive signal containing the minimum price of the products */
|
|
176
|
+
minPrice: Signal<number>;
|
|
177
|
+
/** Reactive signal containing the maximum price of the products */
|
|
178
|
+
maxPrice: Signal<number>;
|
|
179
|
+
/** Reactive signal containing the available inventory statuses */
|
|
180
|
+
availableInventoryStatuses: Signal<InventoryStatusType[]>;
|
|
181
|
+
/** Reactive signal containing the available product options */
|
|
182
|
+
availableProductOptions: Signal<ProductOption[]>;
|
|
157
183
|
/** Function to update search options and trigger a new search */
|
|
158
184
|
setSearchOptions: (searchOptions: productsV3.V3ProductSearch) => void;
|
|
159
185
|
/** Function to update only the sort part of search options */
|
|
160
186
|
setSort: (sort: productsV3.V3ProductSearch["sort"]) => void;
|
|
161
187
|
/** Function to update only the filter part of search options */
|
|
162
188
|
setFilter: (filter: productsV3.V3ProductSearch["filter"]) => void;
|
|
189
|
+
/** Function to reset the filter part of search options */
|
|
190
|
+
resetFilter: () => void;
|
|
191
|
+
/** Reactive signal indicating if any filters are currently applied */
|
|
192
|
+
isFiltered: () => ReadOnlySignal<boolean>;
|
|
193
|
+
/** Function to load more products */
|
|
194
|
+
loadMore: (count: number) => void;
|
|
195
|
+
/** Reactive signal indicating if there are more products to load */
|
|
196
|
+
hasMoreProducts: ReadOnlySignal<boolean>;
|
|
163
197
|
};
|
|
164
198
|
__config: ProductsListServiceConfig;
|
|
165
199
|
isServiceDefinition?: boolean;
|
|
@@ -176,12 +210,28 @@ export declare const ProductsListServiceDefinition: string & {
|
|
|
176
210
|
isLoading: Signal<boolean>;
|
|
177
211
|
/** Reactive signal containing any error message, or null if no error */
|
|
178
212
|
error: Signal<string | null>;
|
|
213
|
+
/** Reactive signal containing the minimum price of the products */
|
|
214
|
+
minPrice: Signal<number>;
|
|
215
|
+
/** Reactive signal containing the maximum price of the products */
|
|
216
|
+
maxPrice: Signal<number>;
|
|
217
|
+
/** Reactive signal containing the available inventory statuses */
|
|
218
|
+
availableInventoryStatuses: Signal<InventoryStatusType[]>;
|
|
219
|
+
/** Reactive signal containing the available product options */
|
|
220
|
+
availableProductOptions: Signal<ProductOption[]>;
|
|
179
221
|
/** Function to update search options and trigger a new search */
|
|
180
222
|
setSearchOptions: (searchOptions: productsV3.V3ProductSearch) => void;
|
|
181
223
|
/** Function to update only the sort part of search options */
|
|
182
224
|
setSort: (sort: productsV3.V3ProductSearch["sort"]) => void;
|
|
183
225
|
/** Function to update only the filter part of search options */
|
|
184
226
|
setFilter: (filter: productsV3.V3ProductSearch["filter"]) => void;
|
|
227
|
+
/** Function to reset the filter part of search options */
|
|
228
|
+
resetFilter: () => void;
|
|
229
|
+
/** Reactive signal indicating if any filters are currently applied */
|
|
230
|
+
isFiltered: () => ReadOnlySignal<boolean>;
|
|
231
|
+
/** Function to load more products */
|
|
232
|
+
loadMore: (count: number) => void;
|
|
233
|
+
/** Reactive signal indicating if there are more products to load */
|
|
234
|
+
hasMoreProducts: ReadOnlySignal<boolean>;
|
|
185
235
|
};
|
|
186
236
|
/**
|
|
187
237
|
* Implementation of the Products List service that manages reactive products data.
|
|
@@ -251,12 +301,28 @@ export declare const ProductListService: import("@wix/services-definitions").Ser
|
|
|
251
301
|
isLoading: Signal<boolean>;
|
|
252
302
|
/** Reactive signal containing any error message, or null if no error */
|
|
253
303
|
error: Signal<string | null>;
|
|
304
|
+
/** Reactive signal containing the minimum price of the products */
|
|
305
|
+
minPrice: Signal<number>;
|
|
306
|
+
/** Reactive signal containing the maximum price of the products */
|
|
307
|
+
maxPrice: Signal<number>;
|
|
308
|
+
/** Reactive signal containing the available inventory statuses */
|
|
309
|
+
availableInventoryStatuses: Signal<InventoryStatusType[]>;
|
|
310
|
+
/** Reactive signal containing the available product options */
|
|
311
|
+
availableProductOptions: Signal<ProductOption[]>;
|
|
254
312
|
/** Function to update search options and trigger a new search */
|
|
255
313
|
setSearchOptions: (searchOptions: productsV3.V3ProductSearch) => void;
|
|
256
314
|
/** Function to update only the sort part of search options */
|
|
257
315
|
setSort: (sort: productsV3.V3ProductSearch["sort"]) => void;
|
|
258
316
|
/** Function to update only the filter part of search options */
|
|
259
317
|
setFilter: (filter: productsV3.V3ProductSearch["filter"]) => void;
|
|
318
|
+
/** Function to reset the filter part of search options */
|
|
319
|
+
resetFilter: () => void;
|
|
320
|
+
/** Reactive signal indicating if any filters are currently applied */
|
|
321
|
+
isFiltered: () => ReadOnlySignal<boolean>;
|
|
322
|
+
/** Function to load more products */
|
|
323
|
+
loadMore: (count: number) => void;
|
|
324
|
+
/** Reactive signal indicating if there are more products to load */
|
|
325
|
+
hasMoreProducts: ReadOnlySignal<boolean>;
|
|
260
326
|
};
|
|
261
327
|
__config: ProductsListServiceConfig;
|
|
262
328
|
isServiceDefinition?: boolean;
|
|
@@ -273,10 +339,26 @@ export declare const ProductListService: import("@wix/services-definitions").Ser
|
|
|
273
339
|
isLoading: Signal<boolean>;
|
|
274
340
|
/** Reactive signal containing any error message, or null if no error */
|
|
275
341
|
error: Signal<string | null>;
|
|
342
|
+
/** Reactive signal containing the minimum price of the products */
|
|
343
|
+
minPrice: Signal<number>;
|
|
344
|
+
/** Reactive signal containing the maximum price of the products */
|
|
345
|
+
maxPrice: Signal<number>;
|
|
346
|
+
/** Reactive signal containing the available inventory statuses */
|
|
347
|
+
availableInventoryStatuses: Signal<InventoryStatusType[]>;
|
|
348
|
+
/** Reactive signal containing the available product options */
|
|
349
|
+
availableProductOptions: Signal<ProductOption[]>;
|
|
276
350
|
/** Function to update search options and trigger a new search */
|
|
277
351
|
setSearchOptions: (searchOptions: productsV3.V3ProductSearch) => void;
|
|
278
352
|
/** Function to update only the sort part of search options */
|
|
279
353
|
setSort: (sort: productsV3.V3ProductSearch["sort"]) => void;
|
|
280
354
|
/** Function to update only the filter part of search options */
|
|
281
355
|
setFilter: (filter: productsV3.V3ProductSearch["filter"]) => void;
|
|
356
|
+
/** Function to reset the filter part of search options */
|
|
357
|
+
resetFilter: () => void;
|
|
358
|
+
/** Reactive signal indicating if any filters are currently applied */
|
|
359
|
+
isFiltered: () => ReadOnlySignal<boolean>;
|
|
360
|
+
/** Function to load more products */
|
|
361
|
+
loadMore: (count: number) => void;
|
|
362
|
+
/** Reactive signal indicating if there are more products to load */
|
|
363
|
+
hasMoreProducts: ReadOnlySignal<boolean>;
|
|
282
364
|
}, ProductsListServiceConfig>;
|