@jay-framework/wix-stores 0.15.4 → 0.15.6
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/dist/actions/get-variant-stock.jay-action +7 -0
- package/dist/actions/search-products.jay-action +12 -0
- package/dist/contracts/category-list.jay-contract +5 -0
- package/dist/contracts/category-list.jay-contract.d.ts +5 -1
- package/dist/contracts/media-gallery.jay-contract +1 -0
- package/dist/contracts/media.jay-contract +1 -0
- package/dist/contracts/product-card.jay-contract +1 -0
- package/dist/contracts/product-page.jay-contract +6 -52
- package/dist/contracts/product-page.jay-contract.d.ts +11 -39
- package/dist/contracts/product-search.jay-contract +74 -1
- package/dist/contracts/product-search.jay-contract.d.ts +48 -2
- package/dist/index.client.js +132 -38
- package/dist/index.d.ts +109 -126
- package/dist/index.js +286 -66
- package/package.json +21 -17
- package/plugin.yaml +11 -2
- package/dist/contracts/category-page.jay-contract +0 -193
- package/dist/contracts/category-page.jay-contract.d.ts +0 -133
package/dist/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { getCurrentCartClient } from "@jay-framework/wix-cart";
|
|
2
1
|
import { WIX_CART_CONTEXT, WIX_CART_SERVICE, cartIndicator, cartPage, provideWixCartContext, provideWixCartService } from "@jay-framework/wix-cart";
|
|
3
2
|
import { createJayService, makeJayQuery, ActionError, makeJayStackComponent, RenderPipeline, makeJayInit } from "@jay-framework/fullstack-component";
|
|
4
|
-
import { inventoryItemsV3, productsV3 } from "@wix/stores";
|
|
3
|
+
import { customizationsV3, inventoryItemsV3, productsV3 } from "@wix/stores";
|
|
5
4
|
import { categories } from "@wix/categories";
|
|
6
5
|
import { registerService, getService } from "@jay-framework/stack-server-runtime";
|
|
7
6
|
import { createJayContext } from "@jay-framework/runtime";
|
|
@@ -10,6 +9,11 @@ import { WIX_CLIENT_SERVICE } from "@jay-framework/wix-server-client";
|
|
|
10
9
|
import * as fs from "fs";
|
|
11
10
|
import * as path from "path";
|
|
12
11
|
import * as yaml from "js-yaml";
|
|
12
|
+
var OptionRenderType$2 = /* @__PURE__ */ ((OptionRenderType2) => {
|
|
13
|
+
OptionRenderType2[OptionRenderType2["TEXT_CHOICES"] = 0] = "TEXT_CHOICES";
|
|
14
|
+
OptionRenderType2[OptionRenderType2["SWATCH_CHOICES"] = 1] = "SWATCH_CHOICES";
|
|
15
|
+
return OptionRenderType2;
|
|
16
|
+
})(OptionRenderType$2 || {});
|
|
13
17
|
var CurrentSort = /* @__PURE__ */ ((CurrentSort2) => {
|
|
14
18
|
CurrentSort2[CurrentSort2["relevance"] = 0] = "relevance";
|
|
15
19
|
CurrentSort2[CurrentSort2["priceAsc"] = 1] = "priceAsc";
|
|
@@ -22,7 +26,8 @@ var CurrentSort = /* @__PURE__ */ ((CurrentSort2) => {
|
|
|
22
26
|
const instances = {
|
|
23
27
|
productsV3ClientInstance: void 0,
|
|
24
28
|
categoriesClientInstance: void 0,
|
|
25
|
-
inventoryV3ClientInstance: void 0
|
|
29
|
+
inventoryV3ClientInstance: void 0,
|
|
30
|
+
customizationsV3ClientInstance: void 0
|
|
26
31
|
};
|
|
27
32
|
function getProductsV3Client(wixClient) {
|
|
28
33
|
if (!instances.productsV3ClientInstance) {
|
|
@@ -42,15 +47,23 @@ function getInventoryClient(wixClient) {
|
|
|
42
47
|
}
|
|
43
48
|
return instances.inventoryV3ClientInstance;
|
|
44
49
|
}
|
|
50
|
+
function getCustomizationsV3Client(wixClient) {
|
|
51
|
+
if (!instances.customizationsV3ClientInstance) {
|
|
52
|
+
instances.customizationsV3ClientInstance = wixClient.use(customizationsV3);
|
|
53
|
+
}
|
|
54
|
+
return instances.customizationsV3ClientInstance;
|
|
55
|
+
}
|
|
45
56
|
const WIX_STORES_SERVICE_MARKER = createJayService("Wix Store Service");
|
|
46
57
|
function provideWixStoresService(wixClient, options) {
|
|
47
58
|
let cachedTree = null;
|
|
59
|
+
let cachedCustomizations = null;
|
|
48
60
|
const categoriesClient = getCategoriesClient(wixClient);
|
|
61
|
+
const customizationsClient = getCustomizationsV3Client(wixClient);
|
|
49
62
|
const service = {
|
|
50
63
|
products: getProductsV3Client(wixClient),
|
|
51
64
|
categories: categoriesClient,
|
|
52
65
|
inventory: getInventoryClient(wixClient),
|
|
53
|
-
|
|
66
|
+
customizations: customizationsClient,
|
|
54
67
|
urls: options?.urls ?? { product: "/products/{slug}", category: null },
|
|
55
68
|
defaultCategory: options?.defaultCategory ?? null,
|
|
56
69
|
async getCategoryTree() {
|
|
@@ -86,6 +99,17 @@ function provideWixStoresService(wixClient, options) {
|
|
|
86
99
|
}
|
|
87
100
|
cachedTree = { slugMap, parentMap, rootIds, imageMap };
|
|
88
101
|
return cachedTree;
|
|
102
|
+
},
|
|
103
|
+
async getCustomizations() {
|
|
104
|
+
if (cachedCustomizations) return cachedCustomizations;
|
|
105
|
+
try {
|
|
106
|
+
const result = await customizationsClient.queryCustomizations().eq("customizationType", "PRODUCT_OPTION").limit(100).find();
|
|
107
|
+
cachedCustomizations = result.items || [];
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error("[wix-stores] Failed to load customizations:", error);
|
|
110
|
+
cachedCustomizations = [];
|
|
111
|
+
}
|
|
112
|
+
return cachedCustomizations;
|
|
89
113
|
}
|
|
90
114
|
};
|
|
91
115
|
registerService(WIX_STORES_SERVICE_MARKER, service);
|
|
@@ -214,12 +238,16 @@ function buildProductUrl(urls, tree, slug, mainCategoryId) {
|
|
|
214
238
|
function buildCategoryUrl(urls, tree, categorySlug, categoryId) {
|
|
215
239
|
if (!urls.category) return null;
|
|
216
240
|
let url = urls.category;
|
|
217
|
-
url = url.replace("{category}", categorySlug);
|
|
218
241
|
if (url.includes("{prefix}")) {
|
|
219
242
|
const prefixSlug = findRootCategorySlug(categoryId, tree);
|
|
220
243
|
if (!prefixSlug) return null;
|
|
221
244
|
url = url.replace("{prefix}", prefixSlug);
|
|
245
|
+
const isRoot = tree.rootIds.has(categoryId);
|
|
246
|
+
url = url.replace("{category}", isRoot ? "" : categorySlug);
|
|
247
|
+
} else {
|
|
248
|
+
url = url.replace("{category}", categorySlug);
|
|
222
249
|
}
|
|
250
|
+
url = url.replace(/\/\/+/g, "/").replace(/\/+$/, "/");
|
|
223
251
|
return url.includes("{") ? null : url;
|
|
224
252
|
}
|
|
225
253
|
function mapAvailabilityStatus(status) {
|
|
@@ -329,8 +357,8 @@ function buildVariantStockMap(product) {
|
|
|
329
357
|
const options = product.options;
|
|
330
358
|
const variants = product.variantsInfo?.variants;
|
|
331
359
|
if (!options || options.length !== 2 || !variants) return stockMap;
|
|
332
|
-
const colorOption = options.find((o) => o.optionRenderType === "
|
|
333
|
-
const textOption = options.find((o) => o.optionRenderType
|
|
360
|
+
const colorOption = options.find((o) => o.optionRenderType === "SWATCH_CHOICES");
|
|
361
|
+
const textOption = options.find((o) => o.optionRenderType === "TEXT_CHOICES");
|
|
334
362
|
if (!colorOption || !textOption) return stockMap;
|
|
335
363
|
const colorOptionId = colorOption._id || "";
|
|
336
364
|
const textOptionId = textOption._id || "";
|
|
@@ -428,6 +456,31 @@ const PRICE_BUCKETS = PRICE_BUCKET_BOUNDARIES.slice(0, -1).map((from, i) => ({
|
|
|
428
456
|
to: PRICE_BUCKET_BOUNDARIES[i + 1]
|
|
429
457
|
}));
|
|
430
458
|
PRICE_BUCKETS.push({ from: PRICE_BUCKET_BOUNDARIES[PRICE_BUCKET_BOUNDARIES.length - 1] });
|
|
459
|
+
function getAvailableProductOptions(aggResults, customizations) {
|
|
460
|
+
const optionNamesAgg = aggResults.find((a) => a.name === "optionNames")?.values;
|
|
461
|
+
const choiceNamesAgg = aggResults.find((a) => a.name === "choiceNames")?.values;
|
|
462
|
+
if (!optionNamesAgg?.results?.length || !choiceNamesAgg?.results?.length) {
|
|
463
|
+
return [];
|
|
464
|
+
}
|
|
465
|
+
const optionNames = new Set(optionNamesAgg.results.map((e) => e.value));
|
|
466
|
+
const choiceCounts = new Map(
|
|
467
|
+
choiceNamesAgg.results.map((e) => [e.value.toLowerCase(), e.count ?? 0])
|
|
468
|
+
);
|
|
469
|
+
return customizations.filter(
|
|
470
|
+
(c) => c.customizationType === "PRODUCT_OPTION" && c.name && optionNames.has(c.name) && (c.customizationRenderType === "TEXT_CHOICES" || c.customizationRenderType === "SWATCH_CHOICES")
|
|
471
|
+
).map((c) => ({
|
|
472
|
+
optionId: c._id || "",
|
|
473
|
+
optionName: c.name || "",
|
|
474
|
+
optionRenderType: c.customizationRenderType,
|
|
475
|
+
// Sort by product count descending (most used choices first)
|
|
476
|
+
choices: (c.choicesSettings?.choices || []).filter((ch) => ch.name && choiceCounts.has(ch.name.toLowerCase())).map((ch) => ({
|
|
477
|
+
choiceId: ch._id || "",
|
|
478
|
+
choiceName: ch.name || "",
|
|
479
|
+
colorCode: ch.colorCode || "",
|
|
480
|
+
productCount: choiceCounts.get(ch.name.toLowerCase()) ?? 0
|
|
481
|
+
})).sort((a, b) => b.productCount - a.productCount)
|
|
482
|
+
})).filter((o) => o.choices.length > 0);
|
|
483
|
+
}
|
|
431
484
|
const searchProducts = makeJayQuery("wixStores.searchProducts").withServices(WIX_STORES_SERVICE_MARKER).withHandler(
|
|
432
485
|
async (input, wixStores) => {
|
|
433
486
|
const { query, filters = {}, sortBy = "relevance", cursor, pageSize = 12 } = input;
|
|
@@ -460,6 +513,22 @@ const searchProducts = makeJayQuery("wixStores.searchProducts").withServices(WIX
|
|
|
460
513
|
}
|
|
461
514
|
});
|
|
462
515
|
}
|
|
516
|
+
if (filters.optionFilters && filters.optionFilters.length > 0) {
|
|
517
|
+
for (const optFilter of filters.optionFilters) {
|
|
518
|
+
if (optFilter.choiceNames.length > 0) {
|
|
519
|
+
filterConditions.push({
|
|
520
|
+
$and: [
|
|
521
|
+
{ "options.name": { $hasSome: [optFilter.optionName] } },
|
|
522
|
+
{
|
|
523
|
+
"options.choicesSettings.choices.name": {
|
|
524
|
+
$hasSome: optFilter.choiceNames
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
]
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
463
532
|
const filter = filterConditions.length === 1 ? filterConditions[0] : { $and: filterConditions };
|
|
464
533
|
const sort = [];
|
|
465
534
|
switch (sortBy) {
|
|
@@ -513,6 +582,28 @@ const searchProducts = makeJayQuery("wixStores.searchProducts").withServices(WIX
|
|
|
513
582
|
name: "max-price",
|
|
514
583
|
type: "SCALAR",
|
|
515
584
|
scalar: { type: "MAX" }
|
|
585
|
+
},
|
|
586
|
+
// Option names for option-based filtering
|
|
587
|
+
{
|
|
588
|
+
fieldPath: "options.name",
|
|
589
|
+
name: "optionNames",
|
|
590
|
+
type: "VALUE",
|
|
591
|
+
value: {
|
|
592
|
+
limit: 20,
|
|
593
|
+
sortType: "VALUE",
|
|
594
|
+
sortDirection: "DESC"
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
// Choice names for option-based filtering
|
|
598
|
+
{
|
|
599
|
+
fieldPath: "options.choicesSettings.choices.name",
|
|
600
|
+
name: "choiceNames",
|
|
601
|
+
type: "VALUE",
|
|
602
|
+
value: {
|
|
603
|
+
limit: 50,
|
|
604
|
+
sortType: "COUNT",
|
|
605
|
+
sortDirection: "DESC"
|
|
606
|
+
}
|
|
516
607
|
}
|
|
517
608
|
];
|
|
518
609
|
const searchResult = await wixStores.products.searchProducts(
|
|
@@ -567,6 +658,8 @@ const searchProducts = makeJayQuery("wixStores.searchProducts").withServices(WIX
|
|
|
567
658
|
};
|
|
568
659
|
});
|
|
569
660
|
priceRanges.push(...bucketRanges);
|
|
661
|
+
const customizations = await wixStores.getCustomizations();
|
|
662
|
+
const optionFilters = getAvailableProductOptions(aggResults, customizations);
|
|
570
663
|
const tree = await wixStores.getCategoryTree();
|
|
571
664
|
const mappedProducts = products.map(
|
|
572
665
|
(p) => mapProductToCard(p, wixStores.urls, tree)
|
|
@@ -580,7 +673,8 @@ const searchProducts = makeJayQuery("wixStores.searchProducts").withServices(WIX
|
|
|
580
673
|
minBound,
|
|
581
674
|
maxBound,
|
|
582
675
|
ranges: priceRanges
|
|
583
|
-
}
|
|
676
|
+
},
|
|
677
|
+
optionFilters
|
|
584
678
|
};
|
|
585
679
|
} catch (error) {
|
|
586
680
|
console.error("[wixStores.searchProducts] Search failed:", error);
|
|
@@ -666,13 +760,28 @@ function mapSortToAction(sort) {
|
|
|
666
760
|
function parseUrlFilters(url) {
|
|
667
761
|
try {
|
|
668
762
|
const params = new URL(url, "http://x").searchParams;
|
|
763
|
+
const optionSelections = /* @__PURE__ */ new Map();
|
|
764
|
+
const optParam = params.get("opt");
|
|
765
|
+
if (optParam) {
|
|
766
|
+
for (const segment of optParam.split(";")) {
|
|
767
|
+
const colonIdx = segment.indexOf(":");
|
|
768
|
+
if (colonIdx === -1)
|
|
769
|
+
continue;
|
|
770
|
+
const name = decodeURIComponent(segment.slice(0, colonIdx));
|
|
771
|
+
const choices = segment.slice(colonIdx + 1).split(",").map((c) => decodeURIComponent(c)).filter(Boolean);
|
|
772
|
+
if (choices.length > 0) {
|
|
773
|
+
optionSelections.set(name, new Set(choices));
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
669
777
|
return {
|
|
670
778
|
searchTerm: params.get("q") || "",
|
|
671
779
|
selectedCategorySlugs: params.get("cat")?.split(",").filter(Boolean) || [],
|
|
672
780
|
minPrice: params.has("min") ? Number(params.get("min")) : null,
|
|
673
781
|
maxPrice: params.has("max") ? Number(params.get("max")) : null,
|
|
674
782
|
inStockOnly: params.get("inStock") === "1",
|
|
675
|
-
sort: params.get("sort") || "relevance"
|
|
783
|
+
sort: params.get("sort") || "relevance",
|
|
784
|
+
optionSelections
|
|
676
785
|
};
|
|
677
786
|
} catch {
|
|
678
787
|
return {
|
|
@@ -681,7 +790,8 @@ function parseUrlFilters(url) {
|
|
|
681
790
|
minPrice: null,
|
|
682
791
|
maxPrice: null,
|
|
683
792
|
inStockOnly: false,
|
|
684
|
-
sort: "relevance"
|
|
793
|
+
sort: "relevance",
|
|
794
|
+
optionSelections: /* @__PURE__ */ new Map()
|
|
685
795
|
};
|
|
686
796
|
}
|
|
687
797
|
}
|
|
@@ -696,6 +806,30 @@ function parseSortParam(sort) {
|
|
|
696
806
|
};
|
|
697
807
|
return sortMap[sort] ?? CurrentSort.relevance;
|
|
698
808
|
}
|
|
809
|
+
function buildOptionFiltersViewState(baseOptionFilters, filteredResult, optionSelections) {
|
|
810
|
+
const filteredChoiceCounts = /* @__PURE__ */ new Map();
|
|
811
|
+
for (const opt of filteredResult.optionFilters || []) {
|
|
812
|
+
for (const ch of opt.choices) {
|
|
813
|
+
filteredChoiceCounts.set(ch.choiceName.toLowerCase(), ch.productCount);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
return baseOptionFilters.map((opt) => ({
|
|
817
|
+
optionId: opt.optionId,
|
|
818
|
+
optionName: opt.optionName,
|
|
819
|
+
optionRenderType: opt.optionRenderType === "SWATCH_CHOICES" ? OptionRenderType$2.SWATCH_CHOICES : OptionRenderType$2.TEXT_CHOICES,
|
|
820
|
+
choices: opt.choices.map((ch) => {
|
|
821
|
+
const count = filteredChoiceCounts.get(ch.choiceName.toLowerCase()) ?? 0;
|
|
822
|
+
return {
|
|
823
|
+
choiceId: ch.choiceId,
|
|
824
|
+
choiceName: ch.choiceName,
|
|
825
|
+
colorCode: ch.colorCode,
|
|
826
|
+
productCount: count,
|
|
827
|
+
isSelected: optionSelections.get(opt.optionName)?.has(ch.choiceName) ?? false,
|
|
828
|
+
isDisabled: count === 0
|
|
829
|
+
};
|
|
830
|
+
})
|
|
831
|
+
}));
|
|
832
|
+
}
|
|
699
833
|
const EMPTY_CATEGORY_HEADER = {
|
|
700
834
|
name: "",
|
|
701
835
|
description: "",
|
|
@@ -705,7 +839,7 @@ const EMPTY_CATEGORY_HEADER = {
|
|
|
705
839
|
breadcrumbs: [],
|
|
706
840
|
seoData: { tags: [], settings: { preventAutoRedirect: false, keywords: [] } }
|
|
707
841
|
};
|
|
708
|
-
async function findCategoryBySlug(categoriesClient, slug) {
|
|
842
|
+
async function findCategoryBySlug$1(categoriesClient, slug) {
|
|
709
843
|
const result = await categoriesClient.queryCategories({ treeReference: { appNamespace: "@wix/stores" } }).eq("slug", slug).eq("visible", true).limit(1).find();
|
|
710
844
|
return result.items?.[0] ?? null;
|
|
711
845
|
}
|
|
@@ -719,15 +853,23 @@ async function loadCategoryDetails(categoriesClient, categoryId) {
|
|
|
719
853
|
async function buildCategoryHeader(wixStoreService, category, categoryUrlTemplate) {
|
|
720
854
|
const details = await loadCategoryDetails(wixStoreService.categories, category._id);
|
|
721
855
|
const cat = details || category;
|
|
722
|
-
const imageUrl = cat.image
|
|
856
|
+
const imageUrl = cat.image ? formatWixMediaUrl("", cat.image) : "";
|
|
723
857
|
const description = cat.description || "";
|
|
724
858
|
const categoryTree = await wixStoreService.getCategoryTree();
|
|
725
|
-
const breadcrumbs =
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
859
|
+
const breadcrumbs = [
|
|
860
|
+
...(cat.breadcrumbsInfo?.breadcrumbs || []).map((b) => ({
|
|
861
|
+
categoryId: b.categoryId,
|
|
862
|
+
name: b.categoryName,
|
|
863
|
+
slug: b.categorySlug,
|
|
864
|
+
url: categoryUrlTemplate ? buildCategoryUrl(wixStoreService.urls, categoryTree, b.categorySlug, b.categoryId) : ""
|
|
865
|
+
})),
|
|
866
|
+
{
|
|
867
|
+
categoryId: cat._id || "",
|
|
868
|
+
name: cat.name || "",
|
|
869
|
+
slug: cat.slug || "",
|
|
870
|
+
url: categoryUrlTemplate ? buildCategoryUrl(wixStoreService.urls, categoryTree, cat.slug || "", cat._id || "") : ""
|
|
871
|
+
}
|
|
872
|
+
];
|
|
731
873
|
const seoData = cat.seoData ? {
|
|
732
874
|
tags: (cat.seoData.tags || []).map((tag, index) => ({
|
|
733
875
|
position: index.toString().padStart(2, "0"),
|
|
@@ -767,7 +909,7 @@ async function buildCategoryHeader(wixStoreService, category, categoryUrlTemplat
|
|
|
767
909
|
header = { ...header, description: parent.description };
|
|
768
910
|
}
|
|
769
911
|
if (!header.imageUrl) {
|
|
770
|
-
const parentImage = parent.image
|
|
912
|
+
const parentImage = parent.image ? formatWixMediaUrl("", parent.image) : "";
|
|
771
913
|
if (parentImage) {
|
|
772
914
|
header = { ...header, imageUrl: parentImage, hasImage: true };
|
|
773
915
|
}
|
|
@@ -784,13 +926,13 @@ async function renderSlowlyChanging$2(props, wixStores) {
|
|
|
784
926
|
let activeCategory = null;
|
|
785
927
|
let baseCategoryId = null;
|
|
786
928
|
if (subcategorySlug) {
|
|
787
|
-
activeCategory = await findCategoryBySlug(wixStores.categories, subcategorySlug);
|
|
929
|
+
activeCategory = await findCategoryBySlug$1(wixStores.categories, subcategorySlug);
|
|
788
930
|
baseCategoryId = activeCategory?._id ?? null;
|
|
789
931
|
} else if (categorySlug) {
|
|
790
|
-
activeCategory = await findCategoryBySlug(wixStores.categories, categorySlug);
|
|
932
|
+
activeCategory = await findCategoryBySlug$1(wixStores.categories, categorySlug);
|
|
791
933
|
baseCategoryId = activeCategory?._id ?? null;
|
|
792
934
|
} else if (defaultCategorySlug) {
|
|
793
|
-
activeCategory = await findCategoryBySlug(wixStores.categories, defaultCategorySlug);
|
|
935
|
+
activeCategory = await findCategoryBySlug$1(wixStores.categories, defaultCategorySlug);
|
|
794
936
|
}
|
|
795
937
|
const tree = await wixStores.getCategoryTree();
|
|
796
938
|
const categoryHeader = activeCategory ? await buildCategoryHeader(wixStores, activeCategory, wixStores.urls.category) : EMPTY_CATEGORY_HEADER;
|
|
@@ -801,18 +943,35 @@ async function renderSlowlyChanging$2(props, wixStores) {
|
|
|
801
943
|
if (baseCategoryId) {
|
|
802
944
|
query = query.eq("parentCategory.id", baseCategoryId);
|
|
803
945
|
}
|
|
804
|
-
const
|
|
805
|
-
|
|
946
|
+
const baseCategoryIds = baseCategoryId ? [baseCategoryId] : [];
|
|
947
|
+
const [categoriesResult, productsResult] = await Promise.all([
|
|
948
|
+
query.find(),
|
|
949
|
+
searchProducts({
|
|
950
|
+
query: "",
|
|
951
|
+
filters: {
|
|
952
|
+
categoryIds: baseCategoryIds.length > 0 ? baseCategoryIds : void 0
|
|
953
|
+
},
|
|
954
|
+
pageSize: PAGE_SIZE
|
|
955
|
+
})
|
|
956
|
+
]);
|
|
957
|
+
return {
|
|
958
|
+
categories: categoriesResult.items || [],
|
|
959
|
+
productsResult
|
|
960
|
+
};
|
|
806
961
|
}).recover((error) => {
|
|
807
|
-
console.error("Failed to load categories:", error);
|
|
808
|
-
return Pipeline.ok(
|
|
809
|
-
|
|
962
|
+
console.error("Failed to load categories/products:", error);
|
|
963
|
+
return Pipeline.ok({
|
|
964
|
+
categories: [],
|
|
965
|
+
productsResult: null
|
|
966
|
+
});
|
|
967
|
+
}).toPhaseOutput(({ categories: categories2, productsResult }) => {
|
|
810
968
|
const categoryInfos = categories2.map((cat) => ({
|
|
811
969
|
categoryId: cat._id || "",
|
|
812
970
|
categoryName: cat.name || "",
|
|
813
971
|
categorySlug: cat.slug || "",
|
|
814
972
|
categoryUrl: buildCategoryUrl(wixStores.urls, tree, cat.slug || "", cat._id || "") ?? ""
|
|
815
973
|
}));
|
|
974
|
+
const baseOptionFilters = productsResult?.optionFilters || [];
|
|
816
975
|
return {
|
|
817
976
|
viewState: {
|
|
818
977
|
searchFields: "name,description,sku",
|
|
@@ -829,7 +988,9 @@ async function renderSlowlyChanging$2(props, wixStores) {
|
|
|
829
988
|
searchFields: "name,description,sku",
|
|
830
989
|
fuzzySearch: true,
|
|
831
990
|
categories: categoryInfos,
|
|
832
|
-
baseCategoryId
|
|
991
|
+
baseCategoryId,
|
|
992
|
+
preloadedResult: productsResult,
|
|
993
|
+
baseOptionFilters
|
|
833
994
|
}
|
|
834
995
|
};
|
|
835
996
|
});
|
|
@@ -839,7 +1000,15 @@ async function renderFastChanging$1(props, slowCarryForward, _wixStores) {
|
|
|
839
1000
|
const urlFilters = parseUrlFilters(props.url);
|
|
840
1001
|
const initialSort = parseSortParam(urlFilters.sort);
|
|
841
1002
|
const initialCategoryIds = urlFilters.selectedCategorySlugs.map((slug) => slowCarryForward.categories.find((c) => c.categorySlug === slug)?.categoryId).filter(Boolean);
|
|
1003
|
+
const initialOptionFilters = [];
|
|
1004
|
+
for (const [optionName, choiceNames] of urlFilters.optionSelections) {
|
|
1005
|
+
initialOptionFilters.push({ optionName, choiceNames: [...choiceNames] });
|
|
1006
|
+
}
|
|
1007
|
+
const hasActiveFilters = !!urlFilters.searchTerm || initialCategoryIds.length > 0 || urlFilters.minPrice !== null || urlFilters.maxPrice !== null || urlFilters.inStockOnly || initialSort !== CurrentSort.relevance || initialOptionFilters.length > 0;
|
|
842
1008
|
return Pipeline.try(async () => {
|
|
1009
|
+
if (!hasActiveFilters && slowCarryForward.preloadedResult) {
|
|
1010
|
+
return slowCarryForward.preloadedResult;
|
|
1011
|
+
}
|
|
843
1012
|
const baseCategoryIds = slowCarryForward.baseCategoryId ? [slowCarryForward.baseCategoryId, ...initialCategoryIds] : initialCategoryIds;
|
|
844
1013
|
const result = await searchProducts({
|
|
845
1014
|
query: urlFilters.searchTerm || "",
|
|
@@ -847,7 +1016,8 @@ async function renderFastChanging$1(props, slowCarryForward, _wixStores) {
|
|
|
847
1016
|
categoryIds: baseCategoryIds.length > 0 ? baseCategoryIds : void 0,
|
|
848
1017
|
minPrice: urlFilters.minPrice ?? void 0,
|
|
849
1018
|
maxPrice: urlFilters.maxPrice ?? void 0,
|
|
850
|
-
inStockOnly: urlFilters.inStockOnly || void 0
|
|
1019
|
+
inStockOnly: urlFilters.inStockOnly || void 0,
|
|
1020
|
+
optionFilters: initialOptionFilters.length > 0 ? initialOptionFilters : void 0
|
|
851
1021
|
},
|
|
852
1022
|
sortBy: initialSort !== CurrentSort.relevance ? mapSortToAction(initialSort) : void 0,
|
|
853
1023
|
pageSize: PAGE_SIZE
|
|
@@ -867,13 +1037,14 @@ async function renderFastChanging$1(props, slowCarryForward, _wixStores) {
|
|
|
867
1037
|
{
|
|
868
1038
|
rangeId: "all",
|
|
869
1039
|
label: "Show all",
|
|
870
|
-
minValue:
|
|
871
|
-
maxValue:
|
|
1040
|
+
minValue: 0,
|
|
1041
|
+
maxValue: 1e3,
|
|
872
1042
|
productCount: 0,
|
|
873
1043
|
isSelected: true
|
|
874
1044
|
}
|
|
875
1045
|
]
|
|
876
|
-
}
|
|
1046
|
+
},
|
|
1047
|
+
optionFilters: []
|
|
877
1048
|
});
|
|
878
1049
|
}).toPhaseOutput((result) => {
|
|
879
1050
|
const priceAgg = result.priceAggregation || {
|
|
@@ -883,8 +1054,8 @@ async function renderFastChanging$1(props, slowCarryForward, _wixStores) {
|
|
|
883
1054
|
{
|
|
884
1055
|
rangeId: "all",
|
|
885
1056
|
label: "Show all",
|
|
886
|
-
minValue:
|
|
887
|
-
maxValue:
|
|
1057
|
+
minValue: 0,
|
|
1058
|
+
maxValue: 1e3,
|
|
888
1059
|
productCount: result.totalCount,
|
|
889
1060
|
isSelected: true
|
|
890
1061
|
}
|
|
@@ -907,14 +1078,19 @@ async function renderFastChanging$1(props, slowCarryForward, _wixStores) {
|
|
|
907
1078
|
maxPrice: urlFilters.maxPrice ?? priceAgg.maxBound,
|
|
908
1079
|
minBound: priceAgg.minBound,
|
|
909
1080
|
maxBound: priceAgg.maxBound,
|
|
910
|
-
ranges: priceAgg.ranges
|
|
1081
|
+
ranges: priceAgg.ranges.map((r) => ({
|
|
1082
|
+
...r,
|
|
1083
|
+
minValue: r.minValue ?? 0,
|
|
1084
|
+
maxValue: r.maxValue ?? 0
|
|
1085
|
+
}))
|
|
911
1086
|
},
|
|
912
1087
|
categoryFilter: {
|
|
913
1088
|
categories: slowCarryForward.categories.map((cat) => ({
|
|
914
1089
|
categoryId: cat.categoryId,
|
|
915
1090
|
isSelected: initialCategoryIds.includes(cat.categoryId)
|
|
916
1091
|
}))
|
|
917
|
-
}
|
|
1092
|
+
},
|
|
1093
|
+
optionFilters: buildOptionFiltersViewState(slowCarryForward.baseOptionFilters, result, urlFilters.optionSelections)
|
|
918
1094
|
},
|
|
919
1095
|
sortBy: {
|
|
920
1096
|
currentSort: initialSort
|
|
@@ -927,7 +1103,8 @@ async function renderFastChanging$1(props, slowCarryForward, _wixStores) {
|
|
|
927
1103
|
searchFields: slowCarryForward.searchFields,
|
|
928
1104
|
fuzzySearch: slowCarryForward.fuzzySearch,
|
|
929
1105
|
categories: slowCarryForward.categories,
|
|
930
|
-
baseCategoryId: slowCarryForward.baseCategoryId
|
|
1106
|
+
baseCategoryId: slowCarryForward.baseCategoryId,
|
|
1107
|
+
baseOptionFilters: slowCarryForward.baseOptionFilters
|
|
931
1108
|
}
|
|
932
1109
|
};
|
|
933
1110
|
});
|
|
@@ -1023,24 +1200,25 @@ function mapInfoSections(infoSections) {
|
|
|
1023
1200
|
uniqueName: infoSection.uniqueName || ""
|
|
1024
1201
|
}));
|
|
1025
1202
|
}
|
|
1026
|
-
function
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
})
|
|
1203
|
+
function mapSeoHeadTags(seoData) {
|
|
1204
|
+
if (!seoData)
|
|
1205
|
+
return [];
|
|
1206
|
+
const headTags = (seoData.tags || []).map((tag) => ({
|
|
1207
|
+
tag: tag.type || "meta",
|
|
1208
|
+
attrs: Object.fromEntries(Object.entries(tag.props || {}).map(([key, value]) => [key, value])),
|
|
1209
|
+
children: tag.children || void 0
|
|
1210
|
+
}));
|
|
1211
|
+
const keywords = seoData.settings?.keywords;
|
|
1212
|
+
if (keywords?.length) {
|
|
1213
|
+
const terms = keywords.map((k) => k.term).filter(Boolean);
|
|
1214
|
+
if (terms.length) {
|
|
1215
|
+
headTags.push({
|
|
1216
|
+
tag: "meta",
|
|
1217
|
+
attrs: { name: "keywords", content: terms.join(", ") }
|
|
1218
|
+
});
|
|
1042
1219
|
}
|
|
1043
|
-
}
|
|
1220
|
+
}
|
|
1221
|
+
return headTags;
|
|
1044
1222
|
}
|
|
1045
1223
|
function mapMediaType(mediaType) {
|
|
1046
1224
|
if (mediaType === "VIDEO")
|
|
@@ -1178,9 +1356,9 @@ async function renderSlowlyChanging$1(props, wixStores) {
|
|
|
1178
1356
|
productType: mapProductType(productType),
|
|
1179
1357
|
options: mapOptionsToSlowVS(options),
|
|
1180
1358
|
infoSections: mapInfoSections(infoSections),
|
|
1181
|
-
modifiers: mapModifiersToSlowVS(modifiers)
|
|
1182
|
-
seoData: mapSeoData(seoData)
|
|
1359
|
+
modifiers: mapModifiersToSlowVS(modifiers)
|
|
1183
1360
|
},
|
|
1361
|
+
headTags: mapSeoHeadTags(seoData),
|
|
1184
1362
|
carryForward: {
|
|
1185
1363
|
productId: _id,
|
|
1186
1364
|
mediaGallery: mapMedia(media),
|
|
@@ -1190,7 +1368,7 @@ async function renderSlowlyChanging$1(props, wixStores) {
|
|
|
1190
1368
|
price: actualPriceRange?.minValue?.formattedAmount || "",
|
|
1191
1369
|
strikethroughPrice: actualPriceRange?.minValue?.amount !== product.compareAtPriceRange?.minValue?.amount ? compareAtPriceRange?.minValue?.formattedAmount || "" : "",
|
|
1192
1370
|
pricePerUnit: physicalProperties?.pricePerUnitRange?.minValue?.description,
|
|
1193
|
-
stockStatus: inventory?.availabilityStatus === "IN_STOCK" ? StockStatus.IN_STOCK : StockStatus.OUT_OF_STOCK,
|
|
1371
|
+
stockStatus: inventory?.availabilityStatus === "IN_STOCK" || inventory?.availabilityStatus === "PARTIALLY_OUT_OF_STOCK" ? StockStatus.IN_STOCK : StockStatus.OUT_OF_STOCK,
|
|
1194
1372
|
variants: mapVariants(variantsInfo)
|
|
1195
1373
|
}
|
|
1196
1374
|
};
|
|
@@ -1198,17 +1376,45 @@ async function renderSlowlyChanging$1(props, wixStores) {
|
|
|
1198
1376
|
}
|
|
1199
1377
|
async function renderFastChanging(props, slowCarryForward, wixStores) {
|
|
1200
1378
|
const Pipeline = RenderPipeline.for();
|
|
1379
|
+
const { variants } = slowCarryForward;
|
|
1380
|
+
const defaultVariant = variants.find((v) => v.inventoryStatus === StockStatus.IN_STOCK) || variants[0];
|
|
1381
|
+
const options = slowCarryForward.options.map((option) => {
|
|
1382
|
+
const variantChoice = defaultVariant.choices.find((c) => c.optionChoiceIds.optionId === option._id);
|
|
1383
|
+
if (!variantChoice)
|
|
1384
|
+
return option;
|
|
1385
|
+
return {
|
|
1386
|
+
...option,
|
|
1387
|
+
choices: option.choices.map((choice) => ({
|
|
1388
|
+
...choice,
|
|
1389
|
+
isSelected: choice.choiceId === variantChoice.optionChoiceIds.choiceId
|
|
1390
|
+
}))
|
|
1391
|
+
};
|
|
1392
|
+
});
|
|
1393
|
+
let mediaGallery = slowCarryForward.mediaGallery;
|
|
1394
|
+
if (defaultVariant.mediaId) {
|
|
1395
|
+
const mediaIndex = mediaGallery.availableMedia.findIndex((m) => m.mediaId === defaultVariant.mediaId);
|
|
1396
|
+
if (mediaIndex >= 0) {
|
|
1397
|
+
mediaGallery = {
|
|
1398
|
+
selectedMedia: mediaGallery.availableMedia[mediaIndex].media,
|
|
1399
|
+
availableMedia: mediaGallery.availableMedia.map((m, i) => ({
|
|
1400
|
+
...m,
|
|
1401
|
+
selected: i === mediaIndex ? Selected.selected : Selected.notSelected
|
|
1402
|
+
}))
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1201
1406
|
const isInStock = slowCarryForward.stockStatus === StockStatus.IN_STOCK;
|
|
1202
1407
|
return Pipeline.ok({
|
|
1203
|
-
actionsEnabled: isInStock,
|
|
1204
|
-
options
|
|
1408
|
+
actionsEnabled: isInStock && defaultVariant.inventoryStatus === StockStatus.IN_STOCK,
|
|
1409
|
+
options,
|
|
1205
1410
|
modifiers: slowCarryForward.modifiers,
|
|
1206
|
-
mediaGallery
|
|
1207
|
-
sku:
|
|
1208
|
-
price:
|
|
1411
|
+
mediaGallery,
|
|
1412
|
+
sku: defaultVariant.sku,
|
|
1413
|
+
price: defaultVariant.price,
|
|
1209
1414
|
pricePerUnit: slowCarryForward.pricePerUnit || "",
|
|
1210
|
-
stockStatus:
|
|
1211
|
-
strikethroughPrice:
|
|
1415
|
+
stockStatus: defaultVariant.inventoryStatus,
|
|
1416
|
+
strikethroughPrice: defaultVariant.strikethroughPrice,
|
|
1417
|
+
isAddingToCart: false,
|
|
1212
1418
|
quantity: { quantity: 1 }
|
|
1213
1419
|
}).toPhaseOutput((viewState) => ({
|
|
1214
1420
|
viewState,
|
|
@@ -1219,14 +1425,28 @@ async function renderFastChanging(props, slowCarryForward, wixStores) {
|
|
|
1219
1425
|
}));
|
|
1220
1426
|
}
|
|
1221
1427
|
const productPage = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withLoadParams(loadProductParams).withSlowlyRender(renderSlowlyChanging$1).withFastRender(renderFastChanging);
|
|
1428
|
+
async function findCategoryBySlug(categoriesClient, slug) {
|
|
1429
|
+
const result = await categoriesClient.queryCategories({ treeReference: { appNamespace: "@wix/stores" } }).eq("slug", slug).eq("visible", true).limit(1).find();
|
|
1430
|
+
return result.items?.[0] ?? null;
|
|
1431
|
+
}
|
|
1222
1432
|
async function renderSlowlyChanging(props, wixStores) {
|
|
1223
1433
|
const Pipeline = RenderPipeline.for();
|
|
1434
|
+
const parentCategorySlug = props.parentCategory ?? wixStores.defaultCategory;
|
|
1435
|
+
let parentCategoryId = null;
|
|
1436
|
+
if (parentCategorySlug) {
|
|
1437
|
+
const parentCat = await findCategoryBySlug(wixStores.categories, parentCategorySlug);
|
|
1438
|
+
parentCategoryId = parentCat?._id ?? null;
|
|
1439
|
+
}
|
|
1224
1440
|
return Pipeline.try(async () => {
|
|
1225
|
-
|
|
1441
|
+
let query = wixStores.categories.queryCategories({
|
|
1226
1442
|
treeReference: {
|
|
1227
1443
|
appNamespace: "@wix/stores"
|
|
1228
1444
|
}
|
|
1229
|
-
}).eq("visible", true)
|
|
1445
|
+
}).eq("visible", true);
|
|
1446
|
+
if (parentCategoryId) {
|
|
1447
|
+
query = query.eq("parentCategory.id", parentCategoryId);
|
|
1448
|
+
}
|
|
1449
|
+
const result = await query.find();
|
|
1230
1450
|
return result.items || [];
|
|
1231
1451
|
}).recover((error) => {
|
|
1232
1452
|
console.error("Failed to load categories:", error);
|