@jay-framework/wix-stores 0.17.0 → 0.17.2
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 +193 -173
- package/dist/index.d.ts +34 -2
- package/dist/index.js +72 -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,184 @@ 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((c) => c.choiceId === choiceId);
|
|
479
|
+
const selectedColor = product.quickOption?.choices?.find((c) => c.isSelected);
|
|
480
|
+
if (!textChoice || !textChoice.inStock) return;
|
|
481
|
+
cards.set(
|
|
482
|
+
patch(currentResults, [
|
|
483
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: true }
|
|
484
|
+
])
|
|
485
|
+
);
|
|
486
|
+
try {
|
|
487
|
+
const colorOptionId = product.quickOption?._id || "";
|
|
488
|
+
const textOptionId = product.secondQuickOption?._id || "";
|
|
489
|
+
await storesContext.addToCart(productId, 1, {
|
|
490
|
+
options: {
|
|
491
|
+
[colorOptionId]: selectedColor?.choiceId || "",
|
|
492
|
+
[textOptionId]: textChoice.choiceId
|
|
493
|
+
},
|
|
494
|
+
modifiers: {},
|
|
495
|
+
customTextFields: {}
|
|
496
|
+
});
|
|
497
|
+
} catch (error) {
|
|
498
|
+
console.error("Failed to add to cart:", error);
|
|
499
|
+
} finally {
|
|
500
|
+
cards.set(
|
|
501
|
+
patch(cards.get(), [
|
|
502
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: false }
|
|
503
|
+
])
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
refs.viewOptionsButton.onclick(({ coordinate }) => {
|
|
508
|
+
const [productId] = coordinate;
|
|
509
|
+
const product = cards.get().find((p) => p._id === productId);
|
|
510
|
+
if (product?.productUrl) {
|
|
511
|
+
window.location.href = product.productUrl;
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
return {
|
|
515
|
+
resetCache() {
|
|
516
|
+
variantStockApplied = /* @__PURE__ */ new Set();
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
}
|
|
342
520
|
const PAGE_SIZE = 12;
|
|
343
521
|
function mapSortToAction(sort) {
|
|
344
522
|
switch (sort) {
|
|
@@ -425,8 +603,6 @@ function buildOptionFiltersViewState(baseOptionFilters, filteredResult, optionSe
|
|
|
425
603
|
}
|
|
426
604
|
function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForward, storesContext) {
|
|
427
605
|
const baseCategoryId = fastCarryForward.baseCategoryId;
|
|
428
|
-
const variantStockCache = {};
|
|
429
|
-
let variantStockApplied = /* @__PURE__ */ new Set();
|
|
430
606
|
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
607
|
const [submittedSearchTerm, setSubmittedSearchTerm] = createSignal(null);
|
|
432
608
|
let currentCursor = null;
|
|
@@ -477,7 +653,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
477
653
|
if (version !== searchVersion) {
|
|
478
654
|
return;
|
|
479
655
|
}
|
|
480
|
-
|
|
656
|
+
resetCardCache();
|
|
481
657
|
setSearchResults(result.products);
|
|
482
658
|
setResultCount(result.products.length);
|
|
483
659
|
setTotalCount(result.totalCount);
|
|
@@ -690,175 +866,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
690
866
|
setSubmittedSearchTerm(suggestion.suggestionText);
|
|
691
867
|
}
|
|
692
868
|
});
|
|
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
|
-
});
|
|
869
|
+
const { resetCache: resetCardCache } = setupCardInteractions(refs.searchResults, { get: searchResults, set: setSearchResults }, storesContext);
|
|
862
870
|
return {
|
|
863
871
|
render: () => ({
|
|
864
872
|
searchExpression: searchExpression(),
|
|
@@ -878,6 +886,17 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
878
886
|
};
|
|
879
887
|
}
|
|
880
888
|
const productSearch = makeJayStackComponent().withProps().withContexts(WIX_STORES_CONTEXT).withInteractive(ProductSearchInteractive);
|
|
889
|
+
function RelatedProductsInteractive(_props, refs, viewStateSignals, _fastCarryForward, storesContext) {
|
|
890
|
+
const { products: [products, setProducts], hasProducts: [hasProducts] } = viewStateSignals;
|
|
891
|
+
setupCardInteractions(refs.products, { get: products, set: setProducts }, storesContext);
|
|
892
|
+
return {
|
|
893
|
+
render: () => ({
|
|
894
|
+
products: products(),
|
|
895
|
+
hasProducts: hasProducts()
|
|
896
|
+
})
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
const relatedProducts = makeJayStackComponent().withProps().withContexts(WIX_STORES_CONTEXT).withInteractive(RelatedProductsInteractive);
|
|
881
900
|
const categoryList = makeJayStackComponent().withProps();
|
|
882
901
|
const init = makeJayInit().withClient(async (data) => {
|
|
883
902
|
console.log("[wix-stores] Initializing client-side stores context...");
|
|
@@ -893,5 +912,6 @@ export {
|
|
|
893
912
|
init,
|
|
894
913
|
productPage,
|
|
895
914
|
productSearch,
|
|
896
|
-
provideWixStoresContext
|
|
915
|
+
provideWixStoresContext,
|
|
916
|
+
relatedProducts
|
|
897
917
|
};
|
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,37 @@ 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
|
+
products: ProductCardViewState[];
|
|
897
|
+
}
|
|
898
|
+
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>>;
|
|
899
|
+
|
|
868
900
|
interface CategoryOfCategoryListViewState {
|
|
869
901
|
_id: string,
|
|
870
902
|
name: string,
|
|
@@ -1034,4 +1066,4 @@ declare function generateWixStoresReferences(ctx: PluginReferencesContext): Prom
|
|
|
1034
1066
|
*/
|
|
1035
1067
|
declare const generator: _jay_framework_fullstack_component.DynamicContractGenerator<[WixStoresService]>;
|
|
1036
1068
|
|
|
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 };
|
|
1069
|
+
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,61 @@ 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
|
+
const categorySlug = props.categorySlug;
|
|
1558
|
+
if (!categorySlug) {
|
|
1559
|
+
return Pipeline.ok({ categoryName: "" }).toPhaseOutput((viewState) => ({
|
|
1560
|
+
viewState,
|
|
1561
|
+
carryForward: { products: [] }
|
|
1562
|
+
}));
|
|
1563
|
+
}
|
|
1564
|
+
return Pipeline.try(async () => {
|
|
1565
|
+
const tree = await wixStores.getCategoryTree();
|
|
1566
|
+
let categoryId = "";
|
|
1567
|
+
let categoryName = "";
|
|
1568
|
+
for (const [id, slug] of tree.slugMap) {
|
|
1569
|
+
if (slug === categorySlug) {
|
|
1570
|
+
categoryId = id;
|
|
1571
|
+
categoryName = slug;
|
|
1572
|
+
break;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
if (!categoryId) {
|
|
1576
|
+
return { categoryName: "", products: [] };
|
|
1577
|
+
}
|
|
1578
|
+
const [categoryResult, searchResult] = await Promise.all([
|
|
1579
|
+
wixStores.categories.queryCategories({ treeReference: { appNamespace: "@wix/stores" } }).eq("_id", categoryId).limit(1).find().catch(() => null),
|
|
1580
|
+
searchProducts({
|
|
1581
|
+
query: "",
|
|
1582
|
+
filters: { categoryIds: [categoryId] },
|
|
1583
|
+
pageSize: limit + 1
|
|
1584
|
+
})
|
|
1585
|
+
]);
|
|
1586
|
+
if (categoryResult?.items?.[0]?.name) {
|
|
1587
|
+
categoryName = categoryResult.items[0].name;
|
|
1588
|
+
}
|
|
1589
|
+
const products = searchResult.products.filter((p) => p._id !== props.productId).slice(0, limit);
|
|
1590
|
+
return { categoryName, products };
|
|
1591
|
+
}).recover((error) => {
|
|
1592
|
+
return handleError(error);
|
|
1593
|
+
}).toPhaseOutput(({ categoryName, products }) => ({
|
|
1594
|
+
viewState: { categoryName },
|
|
1595
|
+
carryForward: { products }
|
|
1596
|
+
}));
|
|
1597
|
+
}
|
|
1598
|
+
async function renderFastChanging(_props, slowCarryForward, _wixStores) {
|
|
1599
|
+
const Pipeline = RenderPipeline.for();
|
|
1600
|
+
const { products } = slowCarryForward;
|
|
1601
|
+
return Pipeline.ok({
|
|
1602
|
+
products,
|
|
1603
|
+
hasProducts: products.length > 0
|
|
1604
|
+
}).toPhaseOutput((viewState) => ({ viewState, carryForward: {} }));
|
|
1605
|
+
}
|
|
1606
|
+
const relatedProducts = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withSlowlyRender(renderSlowlyChanging$1).withFastRender(renderFastChanging);
|
|
1548
1607
|
async function findCategoryBySlug(categoriesClient, slug) {
|
|
1549
1608
|
const result = await categoriesClient.queryCategories({ treeReference: { appNamespace: "@wix/stores" } }).eq("slug", slug).eq("visible", true).limit(1).find();
|
|
1550
1609
|
return result.items?.[0] ?? null;
|
|
@@ -1897,6 +1956,7 @@ tags:
|
|
|
1897
1956
|
- {tag: description, type: data, dataType: string, description: Product description}
|
|
1898
1957
|
- {tag: brand, type: data, dataType: string, description: Brand name}
|
|
1899
1958
|
- {tag: ribbon, type: data, dataType: string, description: "Ribbon text (e.g., \\"New\\", \\"Sale\\")"}
|
|
1959
|
+
- {tag: categorySlug, type: data, dataType: string, description: Slug of the product's main category}
|
|
1900
1960
|
- {tag: productType, type: variant, dataType: "enum (PHYSICAL | DIGITAL)", description: Product type }
|
|
1901
1961
|
|
|
1902
1962
|
- {tag: sku, type: data, dataType: string, phase: fast+interactive, description: Product SKU, or chosen variant SKU}
|
|
@@ -2029,6 +2089,7 @@ export {
|
|
|
2029
2089
|
provideWixCartContext,
|
|
2030
2090
|
provideWixCartService,
|
|
2031
2091
|
provideWixStoresService,
|
|
2092
|
+
relatedProducts,
|
|
2032
2093
|
searchProducts,
|
|
2033
2094
|
setupWixStores
|
|
2034
2095
|
};
|
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.2",
|
|
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.2",
|
|
42
|
+
"@jay-framework/fullstack-component": "^0.17.2",
|
|
43
|
+
"@jay-framework/reactive": "^0.17.2",
|
|
44
|
+
"@jay-framework/runtime": "^0.17.2",
|
|
45
|
+
"@jay-framework/secure": "^0.17.2",
|
|
46
|
+
"@jay-framework/stack-client-runtime": "^0.17.2",
|
|
47
|
+
"@jay-framework/stack-server-runtime": "^0.17.2",
|
|
48
|
+
"@jay-framework/wix-cart": "^0.17.2",
|
|
49
|
+
"@jay-framework/wix-server-client": "^0.17.2",
|
|
50
|
+
"@jay-framework/wix-utils": "^0.17.2",
|
|
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.2",
|
|
63
|
+
"@jay-framework/jay-cli": "^0.17.2",
|
|
64
|
+
"@jay-framework/jay-stack-cli": "^0.17.2",
|
|
65
|
+
"@jay-framework/vite-plugin": "^0.17.2",
|
|
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
|