@wix/headless-stores 0.0.57 → 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.
Files changed (33) hide show
  1. package/cjs/dist/react/ProductList.js +1 -0
  2. package/cjs/dist/react/ProductListSort.d.ts +14 -0
  3. package/cjs/dist/react/ProductListSort.js +14 -0
  4. package/cjs/dist/react/core/ProductList.d.ts +3 -0
  5. package/cjs/dist/react/core/ProductList.js +2 -0
  6. package/cjs/dist/react/core/ProductListFilters.d.ts +8 -180
  7. package/cjs/dist/react/core/ProductListFilters.js +137 -171
  8. package/cjs/dist/react/core/ProductListPagination.d.ts +0 -192
  9. package/cjs/dist/react/core/ProductListPagination.js +2 -160
  10. package/cjs/dist/react/core/ProductListSort.d.ts +9 -57
  11. package/cjs/dist/react/core/ProductListSort.js +32 -52
  12. package/cjs/dist/services/index.d.ts +2 -2
  13. package/cjs/dist/services/products-list-search-service.d.ts +3 -162
  14. package/cjs/dist/services/products-list-search-service.js +31 -424
  15. package/cjs/dist/services/products-list-service.d.ts +86 -4
  16. package/cjs/dist/services/products-list-service.js +125 -4
  17. package/dist/react/ProductList.js +1 -0
  18. package/dist/react/ProductListSort.d.ts +14 -0
  19. package/dist/react/ProductListSort.js +14 -0
  20. package/dist/react/core/ProductList.d.ts +3 -0
  21. package/dist/react/core/ProductList.js +2 -0
  22. package/dist/react/core/ProductListFilters.d.ts +8 -180
  23. package/dist/react/core/ProductListFilters.js +137 -171
  24. package/dist/react/core/ProductListPagination.d.ts +0 -192
  25. package/dist/react/core/ProductListPagination.js +2 -160
  26. package/dist/react/core/ProductListSort.d.ts +9 -57
  27. package/dist/react/core/ProductListSort.js +32 -52
  28. package/dist/services/index.d.ts +2 -2
  29. package/dist/services/products-list-search-service.d.ts +3 -162
  30. package/dist/services/products-list-search-service.js +31 -424
  31. package/dist/services/products-list-service.d.ts +86 -4
  32. package/dist/services/products-list-service.js +125 -4
  33. package/package.json +4 -4
@@ -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, ProductsListServiceDefinition, } from './products-list-service.js';
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 { initialSearchState: parsedState } = await parseUrlToSearchOptions(input, categoriesListConfig.categories);
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, config }) => {
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
- // Build complete new search options
562
- const newSearchOptions = {
563
- ...productsListService.searchOptions.peek(),
564
- };
565
- // Update pagination
566
- if (limit > 0) {
567
- newSearchOptions.cursorPaging = {
568
- limit,
569
- ...(cursor && { cursor }),
570
- };
571
- }
572
- else {
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 { type InitialSearchState } from './products-list-search-service.js';
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>;