@jay-framework/wix-stores 0.17.0 → 0.17.1
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/contracts/product-page.jay-contract +1 -0
- package/dist/contracts/product-page.jay-contract.d.ts +2 -1
- package/dist/contracts/related-products.jay-contract +31 -0
- package/dist/contracts/related-products.jay-contract.d.ts +36 -0
- package/dist/index.client.js +195 -173
- package/dist/index.d.ts +36 -2
- package/dist/index.js +89 -11
- package/package.json +16 -15
- package/plugin.yaml +4 -0
|
@@ -16,6 +16,7 @@ tags:
|
|
|
16
16
|
- {tag: description, type: data, dataType: string, description: Product description}
|
|
17
17
|
- {tag: brand, type: data, dataType: string, description: Brand name}
|
|
18
18
|
- {tag: ribbon, type: data, dataType: string, description: "Ribbon text (e.g., \"New\", \"Sale\")"}
|
|
19
|
+
- {tag: categorySlug, type: data, dataType: string, description: Slug of the product's main category}
|
|
19
20
|
- {tag: productType, type: variant, dataType: "enum (PHYSICAL | DIGITAL)", description: Product type }
|
|
20
21
|
|
|
21
22
|
- {tag: sku, type: data, dataType: string, phase: fast+interactive, description: Product SKU, or chosen variant SKU}
|
|
@@ -84,6 +84,7 @@ export interface ProductPageViewState {
|
|
|
84
84
|
description: string,
|
|
85
85
|
brand: string,
|
|
86
86
|
ribbon: string,
|
|
87
|
+
categorySlug: string,
|
|
87
88
|
productType: ProductType,
|
|
88
89
|
sku: string,
|
|
89
90
|
price: string,
|
|
@@ -98,7 +99,7 @@ export interface ProductPageViewState {
|
|
|
98
99
|
modifiers: Array<ModifierOfProductPageViewState>
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
export type ProductPageSlowViewState = Pick<ProductPageViewState, '_id' | 'productName' | 'description' | 'brand' | 'ribbon' | 'productType'> & {
|
|
102
|
+
export type ProductPageSlowViewState = Pick<ProductPageViewState, '_id' | 'productName' | 'description' | 'brand' | 'ribbon' | 'categorySlug' | 'productType'> & {
|
|
102
103
|
options: Array<Pick<ProductPageViewState['options'][number], '_id' | 'name' | 'optionRenderType'> & {
|
|
103
104
|
choices: Array<Pick<ProductPageViewState['options'][number]['choices'][number], 'choiceId' | 'choiceType' | 'name' | 'colorCode' | 'inStock'>>;
|
|
104
105
|
}>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: related-products
|
|
2
|
+
description: Related products grid showing products from the same category. Use on product pages alongside the product-page component.
|
|
3
|
+
props:
|
|
4
|
+
- name: productId
|
|
5
|
+
type: string
|
|
6
|
+
description: Product ID to exclude from results
|
|
7
|
+
- name: categorySlug
|
|
8
|
+
type: string
|
|
9
|
+
description: Category slug to filter related products by
|
|
10
|
+
- name: limit
|
|
11
|
+
type: number
|
|
12
|
+
description: Maximum number of related products to show (default 4)
|
|
13
|
+
tags:
|
|
14
|
+
- tag: products
|
|
15
|
+
type: sub-contract
|
|
16
|
+
repeated: true
|
|
17
|
+
trackBy: _id
|
|
18
|
+
phase: fast+interactive
|
|
19
|
+
description: Related product cards
|
|
20
|
+
link: ./product-card
|
|
21
|
+
|
|
22
|
+
- tag: hasProducts
|
|
23
|
+
type: variant
|
|
24
|
+
dataType: boolean
|
|
25
|
+
phase: fast+interactive
|
|
26
|
+
description: Whether there are related products to show
|
|
27
|
+
|
|
28
|
+
- tag: categoryName
|
|
29
|
+
type: data
|
|
30
|
+
dataType: string
|
|
31
|
+
description: Name of the category these products belong to
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {JayContract} from "@jay-framework/runtime";
|
|
2
|
+
import {ProductCardViewState, ProductCardRefs, ProductCardRepeatedRefs} from "./product-card.jay-contract";
|
|
3
|
+
|
|
4
|
+
export interface RelatedProductsViewState {
|
|
5
|
+
products: Array<ProductCardViewState>,
|
|
6
|
+
hasProducts: boolean,
|
|
7
|
+
categoryName: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type RelatedProductsSlowViewState = Pick<RelatedProductsViewState, 'categoryName'>;
|
|
11
|
+
|
|
12
|
+
export type RelatedProductsFastViewState = Pick<RelatedProductsViewState, 'hasProducts'> & {
|
|
13
|
+
products: Array<RelatedProductsViewState['products'][number]>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type RelatedProductsInteractiveViewState = Pick<RelatedProductsViewState, 'hasProducts'> & {
|
|
17
|
+
products: Array<RelatedProductsViewState['products'][number]>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export interface RelatedProductsRefs {
|
|
22
|
+
products: ProductCardRepeatedRefs
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export interface RelatedProductsRepeatedRefs {
|
|
27
|
+
products: ProductCardRepeatedRefs
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface RelatedProductsProps {
|
|
31
|
+
productId?: string;
|
|
32
|
+
categorySlug?: string;
|
|
33
|
+
limit?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type RelatedProductsContract = JayContract<RelatedProductsViewState, RelatedProductsRefs, RelatedProductsSlowViewState, RelatedProductsFastViewState, RelatedProductsInteractiveViewState, RelatedProductsProps>
|
package/dist/index.client.js
CHANGED
|
@@ -339,6 +339,186 @@ var QuickAddType = /* @__PURE__ */ ((QuickAddType2) => {
|
|
|
339
339
|
QuickAddType2[QuickAddType2["NEEDS_CONFIGURATION"] = 3] = "NEEDS_CONFIGURATION";
|
|
340
340
|
return QuickAddType2;
|
|
341
341
|
})(QuickAddType || {});
|
|
342
|
+
function setupCardInteractions(refs, cards, storesContext) {
|
|
343
|
+
const variantStockCache = {};
|
|
344
|
+
let variantStockApplied = /* @__PURE__ */ new Set();
|
|
345
|
+
const variantStockLoading = /* @__PURE__ */ new Set();
|
|
346
|
+
const loadVariantStock = async (productId) => {
|
|
347
|
+
if (variantStockApplied.has(productId) || variantStockLoading.has(productId)) return;
|
|
348
|
+
variantStockLoading.add(productId);
|
|
349
|
+
try {
|
|
350
|
+
const currentResults = cards.get();
|
|
351
|
+
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
352
|
+
if (productIndex === -1) return;
|
|
353
|
+
const product = currentResults[productIndex];
|
|
354
|
+
if (product?.quickAddType !== QuickAddType.COLOR_AND_TEXT_OPTIONS) return;
|
|
355
|
+
const stockMap = variantStockCache[productId] ?? await getVariantStock({ productId });
|
|
356
|
+
variantStockCache[productId] = stockMap;
|
|
357
|
+
variantStockApplied.add(productId);
|
|
358
|
+
const selectedColor = product.quickOption?.choices?.find((c) => c.isSelected);
|
|
359
|
+
const textChoices = product.secondQuickOption?.choices;
|
|
360
|
+
if (!selectedColor || !textChoices) return;
|
|
361
|
+
const colorStock = stockMap[selectedColor.choiceId];
|
|
362
|
+
const updatedTextChoices = textChoices.map((c) => ({
|
|
363
|
+
...c,
|
|
364
|
+
inStock: colorStock?.[c.choiceId] ?? false
|
|
365
|
+
}));
|
|
366
|
+
cards.set(
|
|
367
|
+
patch(cards.get(), [
|
|
368
|
+
{
|
|
369
|
+
op: REPLACE,
|
|
370
|
+
path: [productIndex, "secondQuickOption", "choices"],
|
|
371
|
+
value: updatedTextChoices
|
|
372
|
+
}
|
|
373
|
+
])
|
|
374
|
+
);
|
|
375
|
+
} finally {
|
|
376
|
+
variantStockLoading.delete(productId);
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
refs.addToCartButton.onclick(async ({ coordinate }) => {
|
|
380
|
+
const [productId] = coordinate;
|
|
381
|
+
const currentResults = cards.get();
|
|
382
|
+
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
383
|
+
if (productIndex === -1) return;
|
|
384
|
+
cards.set(
|
|
385
|
+
patch(currentResults, [
|
|
386
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: true }
|
|
387
|
+
])
|
|
388
|
+
);
|
|
389
|
+
try {
|
|
390
|
+
await storesContext.addToCart(productId, 1);
|
|
391
|
+
} catch (error) {
|
|
392
|
+
console.error("Failed to add to cart:", error);
|
|
393
|
+
} finally {
|
|
394
|
+
cards.set(
|
|
395
|
+
patch(cards.get(), [
|
|
396
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: false }
|
|
397
|
+
])
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
refs.cardContainer.onmouseenter(({ coordinate }) => {
|
|
402
|
+
const [productId] = coordinate;
|
|
403
|
+
loadVariantStock(productId);
|
|
404
|
+
});
|
|
405
|
+
refs.quickOption.choices.choiceButton.onclick(async ({ coordinate }) => {
|
|
406
|
+
const [productId, choiceId] = coordinate;
|
|
407
|
+
const currentResults = cards.get();
|
|
408
|
+
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
409
|
+
if (productIndex === -1) return;
|
|
410
|
+
const product = currentResults[productIndex];
|
|
411
|
+
if (product.quickAddType === QuickAddType.COLOR_AND_TEXT_OPTIONS) {
|
|
412
|
+
const choices = product.quickOption?.choices;
|
|
413
|
+
if (!choices) return;
|
|
414
|
+
const updatedChoices = choices.map((c) => ({
|
|
415
|
+
...c,
|
|
416
|
+
isSelected: c.choiceId === choiceId
|
|
417
|
+
}));
|
|
418
|
+
let updated = patch(currentResults, [
|
|
419
|
+
{
|
|
420
|
+
op: REPLACE,
|
|
421
|
+
path: [productIndex, "quickOption", "choices"],
|
|
422
|
+
value: updatedChoices
|
|
423
|
+
}
|
|
424
|
+
]);
|
|
425
|
+
const stockMap = variantStockCache[productId];
|
|
426
|
+
if (stockMap) {
|
|
427
|
+
const colorStock = stockMap[choiceId];
|
|
428
|
+
const textChoices = product.secondQuickOption?.choices;
|
|
429
|
+
if (textChoices) {
|
|
430
|
+
const updatedTextChoices = textChoices.map((c) => ({
|
|
431
|
+
...c,
|
|
432
|
+
inStock: colorStock?.[c.choiceId] ?? false
|
|
433
|
+
}));
|
|
434
|
+
updated = patch(updated, [
|
|
435
|
+
{
|
|
436
|
+
op: REPLACE,
|
|
437
|
+
path: [productIndex, "secondQuickOption", "choices"],
|
|
438
|
+
value: updatedTextChoices
|
|
439
|
+
}
|
|
440
|
+
]);
|
|
441
|
+
}
|
|
442
|
+
} else {
|
|
443
|
+
loadVariantStock(productId);
|
|
444
|
+
}
|
|
445
|
+
cards.set(updated);
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const choice = product.quickOption?.choices?.find((c) => c.choiceId === choiceId);
|
|
449
|
+
if (!choice || !choice.inStock) return;
|
|
450
|
+
cards.set(
|
|
451
|
+
patch(currentResults, [
|
|
452
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: true }
|
|
453
|
+
])
|
|
454
|
+
);
|
|
455
|
+
try {
|
|
456
|
+
const optionId = product.quickOption._id;
|
|
457
|
+
await storesContext.addToCart(productId, 1, {
|
|
458
|
+
options: { [optionId]: choice.choiceId },
|
|
459
|
+
modifiers: {},
|
|
460
|
+
customTextFields: {}
|
|
461
|
+
});
|
|
462
|
+
} catch (error) {
|
|
463
|
+
console.error("Failed to add to cart:", error);
|
|
464
|
+
} finally {
|
|
465
|
+
cards.set(
|
|
466
|
+
patch(cards.get(), [
|
|
467
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: false }
|
|
468
|
+
])
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
refs.secondQuickOption.choices.choiceButton.onclick(async ({ coordinate }) => {
|
|
473
|
+
const [productId, choiceId] = coordinate;
|
|
474
|
+
const currentResults = cards.get();
|
|
475
|
+
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
476
|
+
if (productIndex === -1) return;
|
|
477
|
+
const product = currentResults[productIndex];
|
|
478
|
+
const textChoice = product.secondQuickOption?.choices?.find(
|
|
479
|
+
(c) => c.choiceId === choiceId
|
|
480
|
+
);
|
|
481
|
+
const selectedColor = product.quickOption?.choices?.find((c) => c.isSelected);
|
|
482
|
+
if (!textChoice || !textChoice.inStock) return;
|
|
483
|
+
cards.set(
|
|
484
|
+
patch(currentResults, [
|
|
485
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: true }
|
|
486
|
+
])
|
|
487
|
+
);
|
|
488
|
+
try {
|
|
489
|
+
const colorOptionId = product.quickOption?._id || "";
|
|
490
|
+
const textOptionId = product.secondQuickOption?._id || "";
|
|
491
|
+
await storesContext.addToCart(productId, 1, {
|
|
492
|
+
options: {
|
|
493
|
+
[colorOptionId]: selectedColor?.choiceId || "",
|
|
494
|
+
[textOptionId]: textChoice.choiceId
|
|
495
|
+
},
|
|
496
|
+
modifiers: {},
|
|
497
|
+
customTextFields: {}
|
|
498
|
+
});
|
|
499
|
+
} catch (error) {
|
|
500
|
+
console.error("Failed to add to cart:", error);
|
|
501
|
+
} finally {
|
|
502
|
+
cards.set(
|
|
503
|
+
patch(cards.get(), [
|
|
504
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: false }
|
|
505
|
+
])
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
refs.viewOptionsButton.onclick(({ coordinate }) => {
|
|
510
|
+
const [productId] = coordinate;
|
|
511
|
+
const product = cards.get().find((p) => p._id === productId);
|
|
512
|
+
if (product?.productUrl) {
|
|
513
|
+
window.location.href = product.productUrl;
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
return {
|
|
517
|
+
resetCache() {
|
|
518
|
+
variantStockApplied = /* @__PURE__ */ new Set();
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
342
522
|
const PAGE_SIZE = 12;
|
|
343
523
|
function mapSortToAction(sort) {
|
|
344
524
|
switch (sort) {
|
|
@@ -425,8 +605,6 @@ function buildOptionFiltersViewState(baseOptionFilters, filteredResult, optionSe
|
|
|
425
605
|
}
|
|
426
606
|
function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForward, storesContext) {
|
|
427
607
|
const baseCategoryId = fastCarryForward.baseCategoryId;
|
|
428
|
-
const variantStockCache = {};
|
|
429
|
-
let variantStockApplied = /* @__PURE__ */ new Set();
|
|
430
608
|
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;
|
|
431
609
|
const [submittedSearchTerm, setSubmittedSearchTerm] = createSignal(null);
|
|
432
610
|
let currentCursor = null;
|
|
@@ -477,7 +655,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
477
655
|
if (version !== searchVersion) {
|
|
478
656
|
return;
|
|
479
657
|
}
|
|
480
|
-
|
|
658
|
+
resetCardCache();
|
|
481
659
|
setSearchResults(result.products);
|
|
482
660
|
setResultCount(result.products.length);
|
|
483
661
|
setTotalCount(result.totalCount);
|
|
@@ -690,175 +868,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
690
868
|
setSubmittedSearchTerm(suggestion.suggestionText);
|
|
691
869
|
}
|
|
692
870
|
});
|
|
693
|
-
refs.searchResults
|
|
694
|
-
const [productId] = coordinate;
|
|
695
|
-
const currentResults = searchResults();
|
|
696
|
-
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
697
|
-
if (productIndex === -1)
|
|
698
|
-
return;
|
|
699
|
-
setSearchResults(patch(currentResults, [
|
|
700
|
-
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: true }
|
|
701
|
-
]));
|
|
702
|
-
try {
|
|
703
|
-
await storesContext.addToCart(productId, 1);
|
|
704
|
-
} catch (error) {
|
|
705
|
-
console.error("Failed to add to cart:", error);
|
|
706
|
-
} finally {
|
|
707
|
-
setSearchResults(patch(searchResults(), [
|
|
708
|
-
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: false }
|
|
709
|
-
]));
|
|
710
|
-
}
|
|
711
|
-
});
|
|
712
|
-
const variantStockLoading = /* @__PURE__ */ new Set();
|
|
713
|
-
const loadVariantStock = async (productId) => {
|
|
714
|
-
if (variantStockApplied.has(productId) || variantStockLoading.has(productId))
|
|
715
|
-
return;
|
|
716
|
-
variantStockLoading.add(productId);
|
|
717
|
-
try {
|
|
718
|
-
const currentResults = searchResults();
|
|
719
|
-
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
720
|
-
if (productIndex === -1)
|
|
721
|
-
return;
|
|
722
|
-
const product = currentResults[productIndex];
|
|
723
|
-
if (product?.quickAddType !== QuickAddType.COLOR_AND_TEXT_OPTIONS)
|
|
724
|
-
return;
|
|
725
|
-
const stockMap = variantStockCache[productId] ?? await getVariantStock({ productId });
|
|
726
|
-
variantStockCache[productId] = stockMap;
|
|
727
|
-
variantStockApplied.add(productId);
|
|
728
|
-
const selectedColor = product.quickOption?.choices?.find((c) => c.isSelected);
|
|
729
|
-
const textChoices = product.secondQuickOption?.choices;
|
|
730
|
-
if (!selectedColor || !textChoices)
|
|
731
|
-
return;
|
|
732
|
-
const colorStock = stockMap[selectedColor.choiceId];
|
|
733
|
-
const updatedTextChoices = textChoices.map((c) => ({
|
|
734
|
-
...c,
|
|
735
|
-
inStock: colorStock?.[c.choiceId] ?? false
|
|
736
|
-
}));
|
|
737
|
-
setSearchResults(patch(searchResults(), [
|
|
738
|
-
{
|
|
739
|
-
op: REPLACE,
|
|
740
|
-
path: [productIndex, "secondQuickOption", "choices"],
|
|
741
|
-
value: updatedTextChoices
|
|
742
|
-
}
|
|
743
|
-
]));
|
|
744
|
-
} finally {
|
|
745
|
-
variantStockLoading.delete(productId);
|
|
746
|
-
}
|
|
747
|
-
};
|
|
748
|
-
refs.searchResults.cardContainer.onmouseenter(({ coordinate }) => {
|
|
749
|
-
const [productId] = coordinate;
|
|
750
|
-
loadVariantStock(productId);
|
|
751
|
-
});
|
|
752
|
-
refs.searchResults.quickOption.choices.choiceButton.onclick(async ({ coordinate }) => {
|
|
753
|
-
const [productId, choiceId] = coordinate;
|
|
754
|
-
const currentResults = searchResults();
|
|
755
|
-
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
756
|
-
if (productIndex === -1)
|
|
757
|
-
return;
|
|
758
|
-
const product = currentResults[productIndex];
|
|
759
|
-
if (product.quickAddType === QuickAddType.COLOR_AND_TEXT_OPTIONS) {
|
|
760
|
-
const choices = product.quickOption?.choices;
|
|
761
|
-
if (!choices)
|
|
762
|
-
return;
|
|
763
|
-
const updatedChoices = choices.map((c) => ({
|
|
764
|
-
...c,
|
|
765
|
-
isSelected: c.choiceId === choiceId
|
|
766
|
-
}));
|
|
767
|
-
let updated = patch(currentResults, [
|
|
768
|
-
{
|
|
769
|
-
op: REPLACE,
|
|
770
|
-
path: [productIndex, "quickOption", "choices"],
|
|
771
|
-
value: updatedChoices
|
|
772
|
-
}
|
|
773
|
-
]);
|
|
774
|
-
const stockMap = variantStockCache[productId];
|
|
775
|
-
if (stockMap) {
|
|
776
|
-
const colorStock = stockMap[choiceId];
|
|
777
|
-
const textChoices = product.secondQuickOption?.choices;
|
|
778
|
-
if (textChoices) {
|
|
779
|
-
const updatedTextChoices = textChoices.map((c) => ({
|
|
780
|
-
...c,
|
|
781
|
-
inStock: colorStock?.[c.choiceId] ?? false
|
|
782
|
-
}));
|
|
783
|
-
updated = patch(updated, [
|
|
784
|
-
{
|
|
785
|
-
op: REPLACE,
|
|
786
|
-
path: [productIndex, "secondQuickOption", "choices"],
|
|
787
|
-
value: updatedTextChoices
|
|
788
|
-
}
|
|
789
|
-
]);
|
|
790
|
-
}
|
|
791
|
-
} else {
|
|
792
|
-
loadVariantStock(productId);
|
|
793
|
-
}
|
|
794
|
-
setSearchResults(updated);
|
|
795
|
-
return;
|
|
796
|
-
}
|
|
797
|
-
const choice = product.quickOption?.choices?.find((c) => c.choiceId === choiceId);
|
|
798
|
-
if (!choice || !choice.inStock) {
|
|
799
|
-
console.warn("Choice not available or out of stock");
|
|
800
|
-
return;
|
|
801
|
-
}
|
|
802
|
-
setSearchResults(patch(currentResults, [
|
|
803
|
-
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: true }
|
|
804
|
-
]));
|
|
805
|
-
try {
|
|
806
|
-
const optionId = product.quickOption._id;
|
|
807
|
-
await storesContext.addToCart(productId, 1, {
|
|
808
|
-
options: { [optionId]: choice.choiceId },
|
|
809
|
-
modifiers: {},
|
|
810
|
-
customTextFields: {}
|
|
811
|
-
});
|
|
812
|
-
} catch (error) {
|
|
813
|
-
console.error("Failed to add to cart:", error);
|
|
814
|
-
} finally {
|
|
815
|
-
setSearchResults(patch(searchResults(), [
|
|
816
|
-
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: false }
|
|
817
|
-
]));
|
|
818
|
-
}
|
|
819
|
-
});
|
|
820
|
-
refs.searchResults.secondQuickOption.choices.choiceButton.onclick(async ({ coordinate }) => {
|
|
821
|
-
const [productId, choiceId] = coordinate;
|
|
822
|
-
const currentResults = searchResults();
|
|
823
|
-
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
824
|
-
if (productIndex === -1)
|
|
825
|
-
return;
|
|
826
|
-
const product = currentResults[productIndex];
|
|
827
|
-
const textChoice = product.secondQuickOption?.choices?.find((c) => c.choiceId === choiceId);
|
|
828
|
-
const selectedColor = product.quickOption?.choices?.find((c) => c.isSelected);
|
|
829
|
-
if (!textChoice || !textChoice.inStock) {
|
|
830
|
-
console.warn("Text choice not available or out of stock");
|
|
831
|
-
return;
|
|
832
|
-
}
|
|
833
|
-
setSearchResults(patch(currentResults, [
|
|
834
|
-
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: true }
|
|
835
|
-
]));
|
|
836
|
-
try {
|
|
837
|
-
const colorOptionId = product.quickOption?._id || "";
|
|
838
|
-
const textOptionId = product.secondQuickOption?._id || "";
|
|
839
|
-
await storesContext.addToCart(productId, 1, {
|
|
840
|
-
options: {
|
|
841
|
-
[colorOptionId]: selectedColor?.choiceId || "",
|
|
842
|
-
[textOptionId]: textChoice.choiceId
|
|
843
|
-
},
|
|
844
|
-
modifiers: {},
|
|
845
|
-
customTextFields: {}
|
|
846
|
-
});
|
|
847
|
-
} catch (error) {
|
|
848
|
-
console.error("Failed to add to cart:", error);
|
|
849
|
-
} finally {
|
|
850
|
-
setSearchResults(patch(searchResults(), [
|
|
851
|
-
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: false }
|
|
852
|
-
]));
|
|
853
|
-
}
|
|
854
|
-
});
|
|
855
|
-
refs.searchResults.viewOptionsButton.onclick(({ coordinate }) => {
|
|
856
|
-
const [productId] = coordinate;
|
|
857
|
-
const product = searchResults().find((p) => p._id === productId);
|
|
858
|
-
if (product?.productUrl) {
|
|
859
|
-
window.location.href = product.productUrl;
|
|
860
|
-
}
|
|
861
|
-
});
|
|
871
|
+
const { resetCache: resetCardCache } = setupCardInteractions(refs.searchResults, { get: searchResults, set: setSearchResults }, storesContext);
|
|
862
872
|
return {
|
|
863
873
|
render: () => ({
|
|
864
874
|
searchExpression: searchExpression(),
|
|
@@ -878,6 +888,17 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
878
888
|
};
|
|
879
889
|
}
|
|
880
890
|
const productSearch = makeJayStackComponent().withProps().withContexts(WIX_STORES_CONTEXT).withInteractive(ProductSearchInteractive);
|
|
891
|
+
function RelatedProductsInteractive(_props, refs, viewStateSignals, _fastCarryForward, storesContext) {
|
|
892
|
+
const { products: [products, setProducts], hasProducts: [hasProducts] } = viewStateSignals;
|
|
893
|
+
setupCardInteractions(refs.products, { get: products, set: setProducts }, storesContext);
|
|
894
|
+
return {
|
|
895
|
+
render: () => ({
|
|
896
|
+
products: products(),
|
|
897
|
+
hasProducts: hasProducts()
|
|
898
|
+
})
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
const relatedProducts = makeJayStackComponent().withProps().withContexts(WIX_STORES_CONTEXT).withInteractive(RelatedProductsInteractive);
|
|
881
902
|
const categoryList = makeJayStackComponent().withProps();
|
|
882
903
|
const init = makeJayInit().withClient(async (data) => {
|
|
883
904
|
console.log("[wix-stores] Initializing client-side stores context...");
|
|
@@ -893,5 +914,6 @@ export {
|
|
|
893
914
|
init,
|
|
894
915
|
productPage,
|
|
895
916
|
productSearch,
|
|
896
|
-
provideWixStoresContext
|
|
917
|
+
provideWixStoresContext,
|
|
918
|
+
relatedProducts
|
|
897
919
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -745,6 +745,7 @@ interface ProductPageViewState {
|
|
|
745
745
|
description: string,
|
|
746
746
|
brand: string,
|
|
747
747
|
ribbon: string,
|
|
748
|
+
categorySlug: string,
|
|
748
749
|
productType: ProductType,
|
|
749
750
|
sku: string,
|
|
750
751
|
price: string,
|
|
@@ -759,7 +760,7 @@ interface ProductPageViewState {
|
|
|
759
760
|
modifiers: Array<ModifierOfProductPageViewState>
|
|
760
761
|
}
|
|
761
762
|
|
|
762
|
-
type ProductPageSlowViewState = Pick<ProductPageViewState, '_id' | 'productName' | 'description' | 'brand' | 'ribbon' | 'productType'> & {
|
|
763
|
+
type ProductPageSlowViewState = Pick<ProductPageViewState, '_id' | 'productName' | 'description' | 'brand' | 'ribbon' | 'categorySlug' | 'productType'> & {
|
|
763
764
|
options: Array<Pick<ProductPageViewState['options'][number], '_id' | 'name' | 'optionRenderType'> & {
|
|
764
765
|
choices: Array<Pick<ProductPageViewState['options'][number]['choices'][number], 'choiceId' | 'choiceType' | 'name' | 'colorCode' | 'inStock'>>;
|
|
765
766
|
}>;
|
|
@@ -865,6 +866,39 @@ interface ProductFastCarryForward {
|
|
|
865
866
|
*/
|
|
866
867
|
declare const productPage: _jay_framework_fullstack_component.JayStackComponentDefinition<ProductPageRefs, ProductPageSlowViewState, ProductPageFastViewState, ProductPageInteractiveViewState, [ProductSlowCarryForward, WixStoresService], [Signals<ProductPageFastViewState>, ProductFastCarryForward, WixStoresContext], PageProps & ProductPageParams, ProductPageParams, _jay_framework_component.JayComponentCore<PageProps & ProductPageParams, ProductPageInteractiveViewState>>;
|
|
867
868
|
|
|
869
|
+
interface RelatedProductsViewState {
|
|
870
|
+
products: Array<ProductCardViewState>,
|
|
871
|
+
hasProducts: boolean,
|
|
872
|
+
categoryName: string
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
type RelatedProductsSlowViewState = Pick<RelatedProductsViewState, 'categoryName'>;
|
|
876
|
+
|
|
877
|
+
type RelatedProductsFastViewState = Pick<RelatedProductsViewState, 'hasProducts'> & {
|
|
878
|
+
products: Array<RelatedProductsViewState['products'][number]>;
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
type RelatedProductsInteractiveViewState = Pick<RelatedProductsViewState, 'hasProducts'> & {
|
|
882
|
+
products: Array<RelatedProductsViewState['products'][number]>;
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
interface RelatedProductsRefs {
|
|
887
|
+
products: ProductCardRepeatedRefs
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
interface RelatedProductsProps {
|
|
891
|
+
productId: string;
|
|
892
|
+
categorySlug?: string;
|
|
893
|
+
limit?: number;
|
|
894
|
+
}
|
|
895
|
+
interface RelatedSlowCarryForward {
|
|
896
|
+
categoryId: string;
|
|
897
|
+
productId: string;
|
|
898
|
+
limit: number;
|
|
899
|
+
}
|
|
900
|
+
declare const relatedProducts: _jay_framework_fullstack_component.JayStackComponentDefinition<RelatedProductsRefs, RelatedProductsSlowViewState, RelatedProductsFastViewState, RelatedProductsInteractiveViewState, [RelatedSlowCarryForward, WixStoresService], [Signals<RelatedProductsFastViewState>, Record<string, never>, WixStoresContext], PageProps & RelatedProductsProps, {}, _jay_framework_component.JayComponentCore<PageProps & RelatedProductsProps, RelatedProductsInteractiveViewState>>;
|
|
901
|
+
|
|
868
902
|
interface CategoryOfCategoryListViewState {
|
|
869
903
|
_id: string,
|
|
870
904
|
name: string,
|
|
@@ -1034,4 +1068,4 @@ declare function generateWixStoresReferences(ctx: PluginReferencesContext): Prom
|
|
|
1034
1068
|
*/
|
|
1035
1069
|
declare const generator: _jay_framework_fullstack_component.DynamicContractGenerator<[WixStoresService]>;
|
|
1036
1070
|
|
|
1037
|
-
export { type CategoryListParams, type CategoryTree, type GetProductBySlugInput, type ProductPageParams, type ProductSearchParams, WIX_STORES_CONTEXT, WIX_STORES_SERVICE_MARKER, type WixStoresContext, type WixStoresInitData, type WixStoresService, type WixStoresServiceOptions, buildCategoryUrl, buildProductUrl, categoryList, findCategoryImage, findRootCategoryId, findRootCategorySlug, generateWixStoresReferences, getCategories, getProductBySlug, getVariantStock, init, productPage, generator as productPageContractGenerator, productSearch, provideWixStoresService, searchProducts, setupWixStores };
|
|
1071
|
+
export { type CategoryListParams, type CategoryTree, type GetProductBySlugInput, type ProductPageParams, type ProductSearchParams, type RelatedProductsProps, WIX_STORES_CONTEXT, WIX_STORES_SERVICE_MARKER, type WixStoresContext, type WixStoresInitData, type WixStoresService, type WixStoresServiceOptions, buildCategoryUrl, buildProductUrl, categoryList, findCategoryImage, findRootCategoryId, findRootCategorySlug, generateWixStoresReferences, getCategories, getProductBySlug, getVariantStock, init, productPage, generator as productPageContractGenerator, productSearch, provideWixStoresService, relatedProducts, searchProducts, setupWixStores };
|
package/dist/index.js
CHANGED
|
@@ -954,7 +954,7 @@ async function buildCategoryHeader(wixStoreService, category, categoryUrlTemplat
|
|
|
954
954
|
}
|
|
955
955
|
return header;
|
|
956
956
|
}
|
|
957
|
-
async function renderSlowlyChanging$
|
|
957
|
+
async function renderSlowlyChanging$3(props, wixStores) {
|
|
958
958
|
const Pipeline = RenderPipeline.for();
|
|
959
959
|
const categorySlug = props.category ?? null;
|
|
960
960
|
const prefixSlug = props.prefix ?? null;
|
|
@@ -1027,7 +1027,7 @@ async function renderSlowlyChanging$2(props, wixStores) {
|
|
|
1027
1027
|
};
|
|
1028
1028
|
});
|
|
1029
1029
|
}
|
|
1030
|
-
async function renderFastChanging$
|
|
1030
|
+
async function renderFastChanging$2(props, slowCarryForward, _wixStores) {
|
|
1031
1031
|
const Pipeline = RenderPipeline.for();
|
|
1032
1032
|
const urlFilters = parseUrlFilters(props.url);
|
|
1033
1033
|
const initialSort = parseSortParam(urlFilters.sort);
|
|
@@ -1214,7 +1214,7 @@ async function* loadSearchParams([wixStores]) {
|
|
|
1214
1214
|
yield [];
|
|
1215
1215
|
}
|
|
1216
1216
|
}
|
|
1217
|
-
const productSearch = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withLoadParams(loadSearchParams).withSlowlyRender(renderSlowlyChanging$
|
|
1217
|
+
const productSearch = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withLoadParams(loadSearchParams).withSlowlyRender(renderSlowlyChanging$3).withFastRender(renderFastChanging$2);
|
|
1218
1218
|
var ProductType = /* @__PURE__ */ ((ProductType2) => {
|
|
1219
1219
|
ProductType2[ProductType2["PHYSICAL"] = 0] = "PHYSICAL";
|
|
1220
1220
|
ProductType2[ProductType2["DIGITAL"] = 1] = "DIGITAL";
|
|
@@ -1443,7 +1443,7 @@ function mapVariants(variantsInfo) {
|
|
|
1443
1443
|
strikethroughPrice: variant.price.compareAtPrice?.formattedAmount || ""
|
|
1444
1444
|
})) || [];
|
|
1445
1445
|
}
|
|
1446
|
-
async function renderSlowlyChanging$
|
|
1446
|
+
async function renderSlowlyChanging$2(props, wixStores) {
|
|
1447
1447
|
const Pipeline = RenderPipeline.for();
|
|
1448
1448
|
const template = wixStores.urls.product;
|
|
1449
1449
|
const needsCategories = template.includes("{category}") || template.includes("{prefix}");
|
|
@@ -1456,20 +1456,25 @@ async function renderSlowlyChanging$1(props, wixStores) {
|
|
|
1456
1456
|
"CURRENCY",
|
|
1457
1457
|
...needsCategories ? ["ALL_CATEGORIES_INFO"] : []
|
|
1458
1458
|
];
|
|
1459
|
-
const response = await
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1459
|
+
const [response, tree] = await Promise.all([
|
|
1460
|
+
wixStores.products.getProductBySlug(props.slug, {
|
|
1461
|
+
fields: [...fields]
|
|
1462
|
+
}),
|
|
1463
|
+
wixStores.getCategoryTree()
|
|
1464
|
+
]);
|
|
1465
|
+
return { response, tree };
|
|
1463
1466
|
}).recover((error) => {
|
|
1464
1467
|
return handleError(error);
|
|
1465
|
-
}).toPhaseOutput((getProductResponse) => {
|
|
1468
|
+
}).toPhaseOutput(({ response: getProductResponse, tree }) => {
|
|
1466
1469
|
const product = getProductResponse.product;
|
|
1467
1470
|
const { _id, name, plainDescription, options, modifiers, actualPriceRange, compareAtPriceRange, media, productType, brand, ribbon, infoSections, seoData, physicalProperties, inventory, variantsInfo } = product;
|
|
1471
|
+
const categorySlug = tree.slugMap.get(product.mainCategoryId) || "";
|
|
1468
1472
|
return {
|
|
1469
1473
|
viewState: {
|
|
1470
1474
|
_id,
|
|
1471
1475
|
productName: name || "",
|
|
1472
1476
|
description: plainDescription,
|
|
1477
|
+
categorySlug,
|
|
1473
1478
|
brand: brand?.name || "",
|
|
1474
1479
|
ribbon: ribbon?.name || "",
|
|
1475
1480
|
productType: mapProductType(productType),
|
|
@@ -1494,7 +1499,7 @@ async function renderSlowlyChanging$1(props, wixStores) {
|
|
|
1494
1499
|
};
|
|
1495
1500
|
});
|
|
1496
1501
|
}
|
|
1497
|
-
async function renderFastChanging(props, slowCarryForward, wixStores) {
|
|
1502
|
+
async function renderFastChanging$1(props, slowCarryForward, wixStores) {
|
|
1498
1503
|
const Pipeline = RenderPipeline.for();
|
|
1499
1504
|
const { variants } = slowCarryForward;
|
|
1500
1505
|
const defaultVariant = variants.find((v) => v.inventoryStatus === StockStatus.IN_STOCK) || variants[0];
|
|
@@ -1544,7 +1549,78 @@ async function renderFastChanging(props, slowCarryForward, wixStores) {
|
|
|
1544
1549
|
}
|
|
1545
1550
|
}));
|
|
1546
1551
|
}
|
|
1547
|
-
const productPage = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withLoadParams(loadProductParams).withSlowlyRender(renderSlowlyChanging$
|
|
1552
|
+
const productPage = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withLoadParams(loadProductParams).withSlowlyRender(renderSlowlyChanging$2).withFastRender(renderFastChanging$1);
|
|
1553
|
+
const DEFAULT_LIMIT = 4;
|
|
1554
|
+
async function renderSlowlyChanging$1(props, wixStores) {
|
|
1555
|
+
const Pipeline = RenderPipeline.for();
|
|
1556
|
+
const limit = props.limit ?? DEFAULT_LIMIT;
|
|
1557
|
+
return Pipeline.try(async () => {
|
|
1558
|
+
const categorySlug = props.categorySlug;
|
|
1559
|
+
if (!categorySlug) {
|
|
1560
|
+
return { categoryId: "", categoryName: "" };
|
|
1561
|
+
}
|
|
1562
|
+
const tree = await wixStores.getCategoryTree();
|
|
1563
|
+
let categoryId = "";
|
|
1564
|
+
let categoryName = "";
|
|
1565
|
+
for (const [id, slug] of tree.slugMap) {
|
|
1566
|
+
if (slug === categorySlug) {
|
|
1567
|
+
categoryId = id;
|
|
1568
|
+
categoryName = slug;
|
|
1569
|
+
break;
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
if (categoryId) {
|
|
1573
|
+
try {
|
|
1574
|
+
const result = await wixStores.categories.queryCategories({ treeReference: { appNamespace: "@wix/stores" } }).eq("_id", categoryId).limit(1).find();
|
|
1575
|
+
if (result.items?.[0]?.name) {
|
|
1576
|
+
categoryName = result.items[0].name;
|
|
1577
|
+
}
|
|
1578
|
+
} catch {
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
return { categoryId, categoryName };
|
|
1582
|
+
}).recover((error) => {
|
|
1583
|
+
return handleError(error);
|
|
1584
|
+
}).toPhaseOutput(({ categoryId, categoryName }) => ({
|
|
1585
|
+
viewState: {
|
|
1586
|
+
categoryName
|
|
1587
|
+
},
|
|
1588
|
+
carryForward: {
|
|
1589
|
+
categoryId,
|
|
1590
|
+
productId: props.productId,
|
|
1591
|
+
limit
|
|
1592
|
+
}
|
|
1593
|
+
}));
|
|
1594
|
+
}
|
|
1595
|
+
async function renderFastChanging(_props, slowCarryForward, _wixStores) {
|
|
1596
|
+
const Pipeline = RenderPipeline.for();
|
|
1597
|
+
const { categoryId, productId, limit } = slowCarryForward;
|
|
1598
|
+
if (!categoryId) {
|
|
1599
|
+
return Pipeline.ok({
|
|
1600
|
+
products: [],
|
|
1601
|
+
hasProducts: false
|
|
1602
|
+
}).toPhaseOutput((viewState) => ({ viewState, carryForward: {} }));
|
|
1603
|
+
}
|
|
1604
|
+
return Pipeline.try(async () => {
|
|
1605
|
+
const result = await searchProducts({
|
|
1606
|
+
query: "",
|
|
1607
|
+
filters: { categoryIds: [categoryId] },
|
|
1608
|
+
pageSize: limit + 1
|
|
1609
|
+
});
|
|
1610
|
+
const products = result.products.filter((p) => p._id !== productId).slice(0, limit);
|
|
1611
|
+
return {
|
|
1612
|
+
products,
|
|
1613
|
+
hasProducts: products.length > 0
|
|
1614
|
+
};
|
|
1615
|
+
}).recover((error) => {
|
|
1616
|
+
console.error("Failed to load related products:", error);
|
|
1617
|
+
return Pipeline.ok({
|
|
1618
|
+
products: [],
|
|
1619
|
+
hasProducts: false
|
|
1620
|
+
});
|
|
1621
|
+
}).toPhaseOutput((viewState) => ({ viewState, carryForward: {} }));
|
|
1622
|
+
}
|
|
1623
|
+
const relatedProducts = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withSlowlyRender(renderSlowlyChanging$1).withFastRender(renderFastChanging);
|
|
1548
1624
|
async function findCategoryBySlug(categoriesClient, slug) {
|
|
1549
1625
|
const result = await categoriesClient.queryCategories({ treeReference: { appNamespace: "@wix/stores" } }).eq("slug", slug).eq("visible", true).limit(1).find();
|
|
1550
1626
|
return result.items?.[0] ?? null;
|
|
@@ -1897,6 +1973,7 @@ tags:
|
|
|
1897
1973
|
- {tag: description, type: data, dataType: string, description: Product description}
|
|
1898
1974
|
- {tag: brand, type: data, dataType: string, description: Brand name}
|
|
1899
1975
|
- {tag: ribbon, type: data, dataType: string, description: "Ribbon text (e.g., \\"New\\", \\"Sale\\")"}
|
|
1976
|
+
- {tag: categorySlug, type: data, dataType: string, description: Slug of the product's main category}
|
|
1900
1977
|
- {tag: productType, type: variant, dataType: "enum (PHYSICAL | DIGITAL)", description: Product type }
|
|
1901
1978
|
|
|
1902
1979
|
- {tag: sku, type: data, dataType: string, phase: fast+interactive, description: Product SKU, or chosen variant SKU}
|
|
@@ -2029,6 +2106,7 @@ export {
|
|
|
2029
2106
|
provideWixCartContext,
|
|
2030
2107
|
provideWixCartService,
|
|
2031
2108
|
provideWixStoresService,
|
|
2109
|
+
relatedProducts,
|
|
2032
2110
|
searchProducts,
|
|
2033
2111
|
setupWixStores
|
|
2034
2112
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/wix-stores",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Wix Stores API client for Jay Framework",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"./media.jay-contract": "./dist/contracts/media.jay-contract",
|
|
18
18
|
"./media-gallery.jay-contract": "./dist/contracts/media-gallery.jay-contract",
|
|
19
19
|
"./product-search.jay-contract": "./dist/contracts/product-search.jay-contract",
|
|
20
|
+
"./related-products.jay-contract": "./dist/contracts/related-products.jay-contract",
|
|
20
21
|
"./category-list.jay-contract": "./dist/contracts/category-list.jay-contract",
|
|
21
22
|
"./search-products.jay-action": "./dist/actions/search-products.jay-action",
|
|
22
23
|
"./get-product-by-slug.jay-action": "./dist/actions/get-product-by-slug.jay-action",
|
|
@@ -37,16 +38,16 @@
|
|
|
37
38
|
"test": ":"
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
40
|
-
"@jay-framework/component": "^0.17.
|
|
41
|
-
"@jay-framework/fullstack-component": "^0.17.
|
|
42
|
-
"@jay-framework/reactive": "^0.17.
|
|
43
|
-
"@jay-framework/runtime": "^0.17.
|
|
44
|
-
"@jay-framework/secure": "^0.17.
|
|
45
|
-
"@jay-framework/stack-client-runtime": "^0.17.
|
|
46
|
-
"@jay-framework/stack-server-runtime": "^0.17.
|
|
47
|
-
"@jay-framework/wix-cart": "^0.17.
|
|
48
|
-
"@jay-framework/wix-server-client": "^0.17.
|
|
49
|
-
"@jay-framework/wix-utils": "^0.17.
|
|
41
|
+
"@jay-framework/component": "^0.17.1",
|
|
42
|
+
"@jay-framework/fullstack-component": "^0.17.1",
|
|
43
|
+
"@jay-framework/reactive": "^0.17.1",
|
|
44
|
+
"@jay-framework/runtime": "^0.17.1",
|
|
45
|
+
"@jay-framework/secure": "^0.17.1",
|
|
46
|
+
"@jay-framework/stack-client-runtime": "^0.17.1",
|
|
47
|
+
"@jay-framework/stack-server-runtime": "^0.17.1",
|
|
48
|
+
"@jay-framework/wix-cart": "^0.17.1",
|
|
49
|
+
"@jay-framework/wix-server-client": "^0.17.1",
|
|
50
|
+
"@jay-framework/wix-utils": "^0.17.1",
|
|
50
51
|
"@wix/categories": "^1.0.185",
|
|
51
52
|
"@wix/data-extension-schema": "^1.0.221",
|
|
52
53
|
"@wix/sdk": "^1.21.5",
|
|
@@ -58,10 +59,10 @@
|
|
|
58
59
|
"@babel/core": "^7.23.7",
|
|
59
60
|
"@babel/preset-env": "^7.23.8",
|
|
60
61
|
"@babel/preset-typescript": "^7.23.3",
|
|
61
|
-
"@jay-framework/compiler-jay-stack": "^0.17.
|
|
62
|
-
"@jay-framework/jay-cli": "^0.17.
|
|
63
|
-
"@jay-framework/jay-stack-cli": "^0.17.
|
|
64
|
-
"@jay-framework/vite-plugin": "^0.17.
|
|
62
|
+
"@jay-framework/compiler-jay-stack": "^0.17.1",
|
|
63
|
+
"@jay-framework/jay-cli": "^0.17.1",
|
|
64
|
+
"@jay-framework/jay-stack-cli": "^0.17.1",
|
|
65
|
+
"@jay-framework/vite-plugin": "^0.17.1",
|
|
65
66
|
"nodemon": "^3.0.3",
|
|
66
67
|
"rimraf": "^5.0.5",
|
|
67
68
|
"tslib": "^2.6.2",
|
package/plugin.yaml
CHANGED
|
@@ -7,6 +7,10 @@ contracts:
|
|
|
7
7
|
component: productSearch
|
|
8
8
|
description: Headless product search page
|
|
9
9
|
# category-page removed — use product-search with prefix/category params instead
|
|
10
|
+
- name: related-products
|
|
11
|
+
contract: related-products.jay-contract
|
|
12
|
+
component: relatedProducts
|
|
13
|
+
description: Related products from the same category
|
|
10
14
|
- name: category-list
|
|
11
15
|
contract: category-list.jay-contract
|
|
12
16
|
component: categoryList
|