@jay-framework/wix-stores 0.16.5 → 0.17.0

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.
@@ -183,6 +183,11 @@ tags:
183
183
  description: Secondary option for quick selection (text choices for COLOR_AND_TEXT_OPTIONS). Rendered as buttons or dropdown. Selection adds to cart.
184
184
  link: ./product-options
185
185
 
186
+ - tag: cardContainer
187
+ type: interactive
188
+ elementType: HTMLElement
189
+ description: The product card root element. Must be placed on the outermost card wrapper so that mouseenter preloads variant stock for quick-add options.
190
+
186
191
  - tag: viewOptionsButton
187
192
  type: interactive
188
193
  elementType: HTMLButtonElement
@@ -116,6 +116,7 @@ export type ProductCardInteractiveViewState = Pick<ProductCardViewState, 'price'
116
116
  export interface ProductCardRefs {
117
117
  productLink: HTMLElementProxy<ProductCardViewState, HTMLAnchorElement>,
118
118
  addToCartButton: HTMLElementProxy<ProductCardViewState, HTMLButtonElement>,
119
+ cardContainer: HTMLElementProxy<ProductCardViewState, HTMLElement>,
119
120
  viewOptionsButton: HTMLElementProxy<ProductCardViewState, HTMLButtonElement>,
120
121
  quickOption: ProductOptionsRefs,
121
122
  secondQuickOption: ProductOptionsRefs
@@ -125,6 +126,7 @@ export interface ProductCardRefs {
125
126
  export interface ProductCardRepeatedRefs {
126
127
  productLink: HTMLElementCollectionProxy<ProductCardViewState, HTMLAnchorElement>,
127
128
  addToCartButton: HTMLElementCollectionProxy<ProductCardViewState, HTMLButtonElement>,
129
+ cardContainer: HTMLElementCollectionProxy<ProductCardViewState, HTMLElement>,
128
130
  viewOptionsButton: HTMLElementCollectionProxy<ProductCardViewState, HTMLButtonElement>,
129
131
  quickOption: ProductOptionsRepeatedRefs,
130
132
  secondQuickOption: ProductOptionsRepeatedRefs
@@ -426,6 +426,7 @@ function buildOptionFiltersViewState(baseOptionFilters, filteredResult, optionSe
426
426
  function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForward, storesContext) {
427
427
  const baseCategoryId = fastCarryForward.baseCategoryId;
428
428
  const variantStockCache = {};
429
+ let variantStockApplied = /* @__PURE__ */ new Set();
429
430
  const { searchExpression: [searchExpression, setSearchExpression], isSearching: [isSearching, setIsSearching], hasSearched: [hasSearched, setHasSearched], searchResults: [searchResults, setSearchResults], resultCount: [resultCount, setResultCount], hasResults: [hasResults, setHasResults], hasSuggestions: [hasSuggestions, setHasSuggestions], suggestions: [suggestions, setSuggestions], filters: [filters, setFilters], sortBy: [sortBy, setSortBy], hasMore: [hasMore, setHasMore], loadedCount: [loadedCount, setLoadedCount], totalCount: [totalCount, setTotalCount] } = viewStateSignals;
430
431
  const [submittedSearchTerm, setSubmittedSearchTerm] = createSignal(null);
431
432
  let currentCursor = null;
@@ -476,6 +477,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
476
477
  if (version !== searchVersion) {
477
478
  return;
478
479
  }
480
+ variantStockApplied = /* @__PURE__ */ new Set();
479
481
  setSearchResults(result.products);
480
482
  setResultCount(result.products.length);
481
483
  setTotalCount(result.totalCount);
@@ -709,7 +711,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
709
711
  });
710
712
  const variantStockLoading = /* @__PURE__ */ new Set();
711
713
  const loadVariantStock = async (productId) => {
712
- if (variantStockCache[productId] || variantStockLoading.has(productId))
714
+ if (variantStockApplied.has(productId) || variantStockLoading.has(productId))
713
715
  return;
714
716
  variantStockLoading.add(productId);
715
717
  try {
@@ -720,8 +722,9 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
720
722
  const product = currentResults[productIndex];
721
723
  if (product?.quickAddType !== QuickAddType.COLOR_AND_TEXT_OPTIONS)
722
724
  return;
723
- const stockMap = await getVariantStock({ productId });
725
+ const stockMap = variantStockCache[productId] ?? await getVariantStock({ productId });
724
726
  variantStockCache[productId] = stockMap;
727
+ variantStockApplied.add(productId);
725
728
  const selectedColor = product.quickOption?.choices?.find((c) => c.isSelected);
726
729
  const textChoices = product.secondQuickOption?.choices;
727
730
  if (!selectedColor || !textChoices)
@@ -742,11 +745,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
742
745
  variantStockLoading.delete(productId);
743
746
  }
744
747
  };
745
- refs.searchResults.productLink.onmouseenter(({ coordinate }) => {
746
- const [productId] = coordinate;
747
- loadVariantStock(productId);
748
- });
749
- refs.searchResults.quickOption.choices.choiceButton.onmouseenter(({ coordinate }) => {
748
+ refs.searchResults.cardContainer.onmouseenter(({ coordinate }) => {
750
749
  const [productId] = coordinate;
751
750
  loadVariantStock(productId);
752
751
  });
@@ -853,10 +852,6 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
853
852
  ]));
854
853
  }
855
854
  });
856
- refs.searchResults.secondQuickOption.choices.choiceButton.onmouseenter(({ coordinate }) => {
857
- const [productId] = coordinate;
858
- loadVariantStock(productId);
859
- });
860
855
  refs.searchResults.viewOptionsButton.onclick(({ coordinate }) => {
861
856
  const [productId] = coordinate;
862
857
  const product = searchResults().find((p) => p._id === productId);
package/dist/index.d.ts CHANGED
@@ -130,6 +130,7 @@ interface ProductCardViewState {
130
130
  interface ProductCardRepeatedRefs {
131
131
  productLink: HTMLElementCollectionProxy<ProductCardViewState, HTMLAnchorElement>,
132
132
  addToCartButton: HTMLElementCollectionProxy<ProductCardViewState, HTMLButtonElement>,
133
+ cardContainer: HTMLElementCollectionProxy<ProductCardViewState, HTMLElement>,
133
134
  viewOptionsButton: HTMLElementCollectionProxy<ProductCardViewState, HTMLButtonElement>,
134
135
  quickOption: ProductOptionsRepeatedRefs,
135
136
  secondQuickOption: ProductOptionsRepeatedRefs
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { WIX_CART_CONTEXT, WIX_CART_SERVICE, cartIndicator, cartPage, provideWixCartContext, provideWixCartService } from "@jay-framework/wix-cart";
2
- import { createJayService, makeJayQuery, ActionError, makeJayStackComponent, RenderPipeline, makeJayInit, makeContractGenerator } from "@jay-framework/fullstack-component";
2
+ import { createJayService, makeJayQuery, ActionError, RenderPipeline, makeJayStackComponent, makeJayInit, makeContractGenerator } from "@jay-framework/fullstack-component";
3
3
  import { customizationsV3, inventoryItemsV3, productsV3 } from "@wix/stores";
4
4
  import { categories } from "@wix/categories";
5
5
  import { registerService, getService } from "@jay-framework/stack-server-runtime";
@@ -763,6 +763,19 @@ const getCategories = makeJayQuery("wixStores.getCategories").withServices(WIX_S
763
763
  }
764
764
  }
765
765
  );
766
+ function handleError(error) {
767
+ const errorCode = error["details"]?.applicationError?.code;
768
+ if (!!errorCode) {
769
+ error["details"]?.requestId;
770
+ if (errorCode === "NOT_FOUND") {
771
+ return RenderPipeline.for().clientError(404, "not found");
772
+ }
773
+ return RenderPipeline.for().serverError(
774
+ 500,
775
+ "Wix SDK Error: " + error.message
776
+ );
777
+ } else return RenderPipeline.for().serverError(500, "unknown server error");
778
+ }
766
779
  const PAGE_SIZE = 12;
767
780
  function mapSortToAction(sort) {
768
781
  switch (sort) {
@@ -982,11 +995,7 @@ async function renderSlowlyChanging$2(props, wixStores) {
982
995
  productsResult
983
996
  };
984
997
  }).recover((error) => {
985
- console.error("Failed to load categories/products:", error);
986
- return Pipeline.ok({
987
- categories: [],
988
- productsResult: null
989
- });
998
+ return handleError(error);
990
999
  }).toPhaseOutput(({ categories: categories2, productsResult }) => {
991
1000
  const categoryInfos = categories2.map((cat) => ({
992
1001
  categoryId: cat._id || "",
@@ -1134,15 +1143,22 @@ async function renderFastChanging$1(props, slowCarryForward, _wixStores) {
1134
1143
  }
1135
1144
  async function* loadSearchParams([wixStores]) {
1136
1145
  try {
1137
- let findRootParent = function(cat) {
1138
- let current = cat;
1139
- while (current.parentCategory?._id) {
1140
- const parent = categoryById.get(current.parentCategory._id);
1141
- if (!parent)
1142
- break;
1143
- current = parent;
1146
+ let sumItems = function(node) {
1147
+ for (const child of node.children) {
1148
+ node.itemCount += sumItems(child);
1149
+ }
1150
+ return node.itemCount;
1151
+ }, collectParams = function(node, rootSlug) {
1152
+ if (!node.slug || node.itemCount === 0)
1153
+ return;
1154
+ if (rootSlug) {
1155
+ params.push({ prefix: rootSlug, category: node.slug });
1156
+ } else {
1157
+ params.push({ prefix: node.slug });
1158
+ }
1159
+ for (const child of node.children) {
1160
+ collectParams(child, rootSlug ?? node.slug);
1144
1161
  }
1145
- return current._id !== cat._id ? current : null;
1146
1162
  };
1147
1163
  const allCategories = [];
1148
1164
  let result = await wixStores.categories.queryCategories({
@@ -1153,22 +1169,45 @@ async function* loadSearchParams([wixStores]) {
1153
1169
  result = await result.next();
1154
1170
  allCategories.push(...result.items || []);
1155
1171
  }
1156
- const categoryById = /* @__PURE__ */ new Map();
1172
+ const nodeById = /* @__PURE__ */ new Map();
1173
+ const roots = [];
1174
+ const childPendingParent = /* @__PURE__ */ new Map();
1157
1175
  for (const cat of allCategories) {
1158
- if (cat._id)
1159
- categoryById.set(cat._id, cat);
1160
- }
1161
- const params = [];
1162
- for (const cat of allCategories) {
1163
- if (!cat.slug || (cat.itemCounter ?? 0) === 0)
1176
+ if (!cat._id)
1164
1177
  continue;
1165
- const rootParent = findRootParent(cat);
1166
- if (rootParent?.slug) {
1167
- params.push({ prefix: rootParent.slug, category: cat.slug });
1178
+ const node = {
1179
+ slug: cat.slug || "",
1180
+ itemCount: cat.itemCounter ?? 0,
1181
+ children: []
1182
+ };
1183
+ nodeById.set(cat._id, node);
1184
+ const pending = childPendingParent.get(cat._id);
1185
+ if (pending) {
1186
+ node.children.push(...pending);
1187
+ childPendingParent.delete(cat._id);
1188
+ }
1189
+ if (cat.parentCategory?._id) {
1190
+ const parent = nodeById.get(cat.parentCategory._id);
1191
+ if (parent) {
1192
+ parent.children.push(node);
1193
+ } else {
1194
+ const siblings = childPendingParent.get(cat.parentCategory._id);
1195
+ if (siblings)
1196
+ siblings.push(node);
1197
+ else
1198
+ childPendingParent.set(cat.parentCategory._id, [node]);
1199
+ }
1168
1200
  } else {
1169
- params.push({ prefix: cat.slug });
1201
+ roots.push(node);
1170
1202
  }
1171
1203
  }
1204
+ for (const root of roots) {
1205
+ sumItems(root);
1206
+ }
1207
+ const params = [];
1208
+ for (const root of roots) {
1209
+ collectParams(root, null);
1210
+ }
1172
1211
  yield params;
1173
1212
  } catch (error) {
1174
1213
  console.error("Failed to load category params:", error);
@@ -1422,8 +1461,7 @@ async function renderSlowlyChanging$1(props, wixStores) {
1422
1461
  });
1423
1462
  return response;
1424
1463
  }).recover((error) => {
1425
- console.log("product page error", error);
1426
- return Pipeline.clientError(404, "not found");
1464
+ return handleError(error);
1427
1465
  }).toPhaseOutput((getProductResponse) => {
1428
1466
  const product = getProductResponse.product;
1429
1467
  const { _id, name, plainDescription, options, modifiers, actualPriceRange, compareAtPriceRange, media, productType, brand, ribbon, infoSections, seoData, physicalProperties, inventory, variantsInfo } = product;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/wix-stores",
3
- "version": "0.16.5",
3
+ "version": "0.17.0",
4
4
  "type": "module",
5
5
  "description": "Wix Stores API client for Jay Framework",
6
6
  "license": "Apache-2.0",
@@ -37,16 +37,16 @@
37
37
  "test": ":"
38
38
  },
39
39
  "dependencies": {
40
- "@jay-framework/component": "^0.16.5",
41
- "@jay-framework/fullstack-component": "^0.16.5",
42
- "@jay-framework/reactive": "^0.16.5",
43
- "@jay-framework/runtime": "^0.16.5",
44
- "@jay-framework/secure": "^0.16.5",
45
- "@jay-framework/stack-client-runtime": "^0.16.5",
46
- "@jay-framework/stack-server-runtime": "^0.16.5",
47
- "@jay-framework/wix-cart": "^0.16.5",
48
- "@jay-framework/wix-server-client": "^0.16.5",
49
- "@jay-framework/wix-utils": "^0.16.5",
40
+ "@jay-framework/component": "^0.17.0",
41
+ "@jay-framework/fullstack-component": "^0.17.0",
42
+ "@jay-framework/reactive": "^0.17.0",
43
+ "@jay-framework/runtime": "^0.17.0",
44
+ "@jay-framework/secure": "^0.17.0",
45
+ "@jay-framework/stack-client-runtime": "^0.17.0",
46
+ "@jay-framework/stack-server-runtime": "^0.17.0",
47
+ "@jay-framework/wix-cart": "^0.17.0",
48
+ "@jay-framework/wix-server-client": "^0.17.0",
49
+ "@jay-framework/wix-utils": "^0.17.0",
50
50
  "@wix/categories": "^1.0.185",
51
51
  "@wix/data-extension-schema": "^1.0.221",
52
52
  "@wix/sdk": "^1.21.5",
@@ -58,10 +58,10 @@
58
58
  "@babel/core": "^7.23.7",
59
59
  "@babel/preset-env": "^7.23.8",
60
60
  "@babel/preset-typescript": "^7.23.3",
61
- "@jay-framework/compiler-jay-stack": "^0.16.5",
62
- "@jay-framework/jay-cli": "^0.16.5",
63
- "@jay-framework/jay-stack-cli": "^0.16.5",
64
- "@jay-framework/vite-plugin": "^0.16.5",
61
+ "@jay-framework/compiler-jay-stack": "^0.17.0",
62
+ "@jay-framework/jay-cli": "^0.17.0",
63
+ "@jay-framework/jay-stack-cli": "^0.17.0",
64
+ "@jay-framework/vite-plugin": "^0.17.0",
65
65
  "nodemon": "^3.0.3",
66
66
  "rimraf": "^5.0.5",
67
67
  "tslib": "^2.6.2",