@jay-framework/wix-stores 0.15.0 → 0.15.4
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/README.md +157 -96
- package/dist/contracts/category-page.jay-contract.d.ts +10 -1
- package/dist/contracts/product-card.jay-contract +8 -2
- package/dist/contracts/product-card.jay-contract.d.ts +17 -4
- package/dist/contracts/product-options.jay-contract +0 -5
- package/dist/contracts/product-options.jay-contract.d.ts +1 -2
- package/dist/contracts/product-search.jay-contract +71 -0
- package/dist/contracts/product-search.jay-contract.d.ts +57 -3
- package/dist/index.client.js +180 -21
- package/dist/index.d.ts +142 -75
- package/dist/index.js +429 -137
- package/package.json +14 -14
|
@@ -22,7 +22,8 @@ export interface CategoryOfCategoryFilterOfFilterOfProductSearchViewState {
|
|
|
22
22
|
categoryId: string,
|
|
23
23
|
categoryName: string,
|
|
24
24
|
categorySlug: string,
|
|
25
|
-
isSelected: boolean
|
|
25
|
+
isSelected: boolean,
|
|
26
|
+
categoryUrl: string
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export interface CategoryFilterOfFilterOfProductSearchViewState {
|
|
@@ -53,6 +54,57 @@ export interface SuggestionOfProductSearchViewState {
|
|
|
53
54
|
suggestionText: string
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
export interface BreadcrumbOfCategoryHeaderOfProductSearchViewState {
|
|
58
|
+
categoryId: string,
|
|
59
|
+
name: string,
|
|
60
|
+
slug: string,
|
|
61
|
+
url: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface PropOfTagOfSeoDatumOfCategoryHeaderOfProductSearchViewState {
|
|
65
|
+
key: string,
|
|
66
|
+
value: string
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface MetaOfTagOfSeoDatumOfCategoryHeaderOfProductSearchViewState {
|
|
70
|
+
key: string,
|
|
71
|
+
value: string
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface TagOfSeoDatumOfCategoryHeaderOfProductSearchViewState {
|
|
75
|
+
position: string,
|
|
76
|
+
type: string,
|
|
77
|
+
props: Array<PropOfTagOfSeoDatumOfCategoryHeaderOfProductSearchViewState>,
|
|
78
|
+
meta: Array<MetaOfTagOfSeoDatumOfCategoryHeaderOfProductSearchViewState>,
|
|
79
|
+
children: string
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface KeywordOfSettingOfSeoDatumOfCategoryHeaderOfProductSearchViewState {
|
|
83
|
+
term: string,
|
|
84
|
+
isMain: boolean,
|
|
85
|
+
origin: string
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface SettingOfSeoDatumOfCategoryHeaderOfProductSearchViewState {
|
|
89
|
+
preventAutoRedirect: boolean,
|
|
90
|
+
keywords: Array<KeywordOfSettingOfSeoDatumOfCategoryHeaderOfProductSearchViewState>
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface SeoDatumOfCategoryHeaderOfProductSearchViewState {
|
|
94
|
+
tags: Array<TagOfSeoDatumOfCategoryHeaderOfProductSearchViewState>,
|
|
95
|
+
settings: SettingOfSeoDatumOfCategoryHeaderOfProductSearchViewState
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface CategoryHeaderOfProductSearchViewState {
|
|
99
|
+
name: string,
|
|
100
|
+
description: string,
|
|
101
|
+
imageUrl: string,
|
|
102
|
+
hasImage: boolean,
|
|
103
|
+
productCount: number,
|
|
104
|
+
breadcrumbs: Array<BreadcrumbOfCategoryHeaderOfProductSearchViewState>,
|
|
105
|
+
seoData: SeoDatumOfCategoryHeaderOfProductSearchViewState
|
|
106
|
+
}
|
|
107
|
+
|
|
56
108
|
export interface ProductSearchViewState {
|
|
57
109
|
searchExpression: string,
|
|
58
110
|
searchFields: string,
|
|
@@ -69,15 +121,17 @@ export interface ProductSearchViewState {
|
|
|
69
121
|
loadedCount: number,
|
|
70
122
|
totalCount: number,
|
|
71
123
|
hasSuggestions: boolean,
|
|
72
|
-
suggestions: Array<SuggestionOfProductSearchViewState
|
|
124
|
+
suggestions: Array<SuggestionOfProductSearchViewState>,
|
|
125
|
+
categoryHeader: CategoryHeaderOfProductSearchViewState
|
|
73
126
|
}
|
|
74
127
|
|
|
75
128
|
export type ProductSearchSlowViewState = Pick<ProductSearchViewState, 'searchFields' | 'fuzzySearch' | 'emptyStateMessage'> & {
|
|
76
129
|
filters: {
|
|
77
130
|
categoryFilter: {
|
|
78
|
-
categories: Array<Pick<ProductSearchViewState['filters']['categoryFilter']['categories'][number], 'categoryId' | 'categoryName' | 'categorySlug'>>;
|
|
131
|
+
categories: Array<Pick<ProductSearchViewState['filters']['categoryFilter']['categories'][number], 'categoryId' | 'categoryName' | 'categorySlug' | 'categoryUrl'>>;
|
|
79
132
|
};
|
|
80
133
|
};
|
|
134
|
+
categoryHeader: ProductSearchViewState['categoryHeader'];
|
|
81
135
|
};
|
|
82
136
|
|
|
83
137
|
export type ProductSearchFastViewState = Pick<ProductSearchViewState, 'searchExpression' | 'isSearching' | 'hasSearched' | 'resultCount' | 'hasResults' | 'hasMore' | 'loadedCount' | 'totalCount' | 'hasSuggestions'> & {
|
package/dist/index.client.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { WIX_CART_CONTEXT
|
|
1
|
+
import { WIX_CART_CONTEXT } from "@jay-framework/wix-cart/client";
|
|
2
|
+
import { WIX_CART_CONTEXT as WIX_CART_CONTEXT2, cartIndicator, cartPage } from "@jay-framework/wix-cart/client";
|
|
2
3
|
import { makeJayStackComponent, makeJayInit } from "@jay-framework/fullstack-component";
|
|
3
4
|
import { registerReactiveGlobalContext, createSignal, createMemo, createEffect } from "@jay-framework/component";
|
|
4
5
|
import { patch, REPLACE } from "@jay-framework/json-patch";
|
|
5
6
|
import { createJayContext, useGlobalContext } from "@jay-framework/runtime";
|
|
6
7
|
import { WIX_CLIENT_CONTEXT } from "@jay-framework/wix-server-client/client";
|
|
7
|
-
import { WIX_CART_CONTEXT as WIX_CART_CONTEXT2 } from "@jay-framework/wix-cart";
|
|
8
8
|
import { productsV3 } from "@wix/stores";
|
|
9
9
|
import "@wix/categories";
|
|
10
10
|
import { createActionCaller } from "@jay-framework/stack-client-runtime";
|
|
@@ -31,7 +31,7 @@ const WIX_STORES_CONTEXT = createJayContext();
|
|
|
31
31
|
function provideWixStoresContext() {
|
|
32
32
|
const wixClientContext = useGlobalContext(WIX_CLIENT_CONTEXT);
|
|
33
33
|
const wixClient = wixClientContext.client;
|
|
34
|
-
const cartContext = useGlobalContext(
|
|
34
|
+
const cartContext = useGlobalContext(WIX_CART_CONTEXT);
|
|
35
35
|
const catalogClient = getProductsV3Client(wixClient);
|
|
36
36
|
const storesContext = registerReactiveGlobalContext(WIX_STORES_CONTEXT, () => {
|
|
37
37
|
async function addToCart(productId, quantity = 1, selections) {
|
|
@@ -324,10 +324,69 @@ var CurrentSort = /* @__PURE__ */ ((CurrentSort2) => {
|
|
|
324
324
|
})(CurrentSort || {});
|
|
325
325
|
const searchProducts = createActionCaller("wixStores.searchProducts", "GET");
|
|
326
326
|
createActionCaller("wixStores.getProductBySlug", "GET");
|
|
327
|
+
const getVariantStock = createActionCaller("wixStores.getVariantStock", "GET");
|
|
327
328
|
createActionCaller("wixStores.getCategories", "GET");
|
|
329
|
+
var QuickAddType = /* @__PURE__ */ ((QuickAddType2) => {
|
|
330
|
+
QuickAddType2[QuickAddType2["SIMPLE"] = 0] = "SIMPLE";
|
|
331
|
+
QuickAddType2[QuickAddType2["SINGLE_OPTION"] = 1] = "SINGLE_OPTION";
|
|
332
|
+
QuickAddType2[QuickAddType2["COLOR_AND_TEXT_OPTIONS"] = 2] = "COLOR_AND_TEXT_OPTIONS";
|
|
333
|
+
QuickAddType2[QuickAddType2["NEEDS_CONFIGURATION"] = 3] = "NEEDS_CONFIGURATION";
|
|
334
|
+
return QuickAddType2;
|
|
335
|
+
})(QuickAddType || {});
|
|
328
336
|
const PAGE_SIZE = 12;
|
|
337
|
+
function mapSortToAction(sort) {
|
|
338
|
+
switch (sort) {
|
|
339
|
+
case CurrentSort.priceAsc:
|
|
340
|
+
return "price_asc";
|
|
341
|
+
case CurrentSort.priceDesc:
|
|
342
|
+
return "price_desc";
|
|
343
|
+
case CurrentSort.newest:
|
|
344
|
+
return "newest";
|
|
345
|
+
case CurrentSort.nameAsc:
|
|
346
|
+
return "name_asc";
|
|
347
|
+
case CurrentSort.nameDesc:
|
|
348
|
+
return "name_desc";
|
|
349
|
+
default:
|
|
350
|
+
return "relevance";
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function updateUrlFilters(searchTerm, filters, sort, categories) {
|
|
354
|
+
if (typeof window === "undefined")
|
|
355
|
+
return;
|
|
356
|
+
const params = new URLSearchParams();
|
|
357
|
+
if (searchTerm)
|
|
358
|
+
params.set("q", searchTerm);
|
|
359
|
+
const selectedSlugs = filters.categoryFilter.categories.filter((c) => c.isSelected).map((c) => {
|
|
360
|
+
const info = categories.find((cat) => cat.categoryId === c.categoryId);
|
|
361
|
+
return info?.categorySlug;
|
|
362
|
+
}).filter(Boolean);
|
|
363
|
+
if (selectedSlugs.length)
|
|
364
|
+
params.set("cat", selectedSlugs.join(","));
|
|
365
|
+
if (filters.priceRange.minPrice > 0)
|
|
366
|
+
params.set("min", String(filters.priceRange.minPrice));
|
|
367
|
+
if (filters.priceRange.maxPrice > 0 && filters.priceRange.maxPrice < filters.priceRange.maxBound) {
|
|
368
|
+
params.set("max", String(filters.priceRange.maxPrice));
|
|
369
|
+
}
|
|
370
|
+
if (filters.inStockOnly)
|
|
371
|
+
params.set("inStock", "1");
|
|
372
|
+
if (sort !== CurrentSort.relevance) {
|
|
373
|
+
const sortNames = {
|
|
374
|
+
[CurrentSort.priceAsc]: "priceAsc",
|
|
375
|
+
[CurrentSort.priceDesc]: "priceDesc",
|
|
376
|
+
[CurrentSort.newest]: "newest",
|
|
377
|
+
[CurrentSort.nameAsc]: "nameAsc",
|
|
378
|
+
[CurrentSort.nameDesc]: "nameDesc"
|
|
379
|
+
};
|
|
380
|
+
const sortName = sortNames[sort];
|
|
381
|
+
if (sortName)
|
|
382
|
+
params.set("sort", sortName);
|
|
383
|
+
}
|
|
384
|
+
const query = params.toString();
|
|
385
|
+
window.history.replaceState(null, "", query ? `?${query}` : window.location.pathname);
|
|
386
|
+
}
|
|
329
387
|
function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForward, storesContext) {
|
|
330
388
|
const baseCategoryId = fastCarryForward.baseCategoryId;
|
|
389
|
+
const variantStockCache = {};
|
|
331
390
|
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;
|
|
332
391
|
const [submittedSearchTerm, setSubmittedSearchTerm] = createSignal(null);
|
|
333
392
|
let currentCursor = null;
|
|
@@ -335,22 +394,6 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
335
394
|
let debounceTimeout = null;
|
|
336
395
|
let searchVersion = 0;
|
|
337
396
|
const DEBOUNCE_MS = 300;
|
|
338
|
-
const mapSortToAction = (sort) => {
|
|
339
|
-
switch (sort) {
|
|
340
|
-
case CurrentSort.priceAsc:
|
|
341
|
-
return "price_asc";
|
|
342
|
-
case CurrentSort.priceDesc:
|
|
343
|
-
return "price_desc";
|
|
344
|
-
case CurrentSort.newest:
|
|
345
|
-
return "newest";
|
|
346
|
-
case CurrentSort.nameAsc:
|
|
347
|
-
return "name_asc";
|
|
348
|
-
case CurrentSort.nameDesc:
|
|
349
|
-
return "name_desc";
|
|
350
|
-
default:
|
|
351
|
-
return "relevance";
|
|
352
|
-
}
|
|
353
|
-
};
|
|
354
397
|
const performSearch = async (version, searchTerm, currentFilters, currentSort) => {
|
|
355
398
|
setIsSearching(true);
|
|
356
399
|
setHasSearched(true);
|
|
@@ -379,6 +422,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
379
422
|
setHasMore(result.hasMore);
|
|
380
423
|
setHasResults(result.products.length > 0);
|
|
381
424
|
currentCursor = result.nextCursor;
|
|
425
|
+
updateUrlFilters(searchTerm, currentFilters, currentSort, fastCarryForward.categories);
|
|
382
426
|
} catch (error) {
|
|
383
427
|
if (version === searchVersion) {
|
|
384
428
|
console.error("Search failed:", error);
|
|
@@ -573,6 +617,49 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
573
617
|
]));
|
|
574
618
|
}
|
|
575
619
|
});
|
|
620
|
+
const loadVariantStock = async (productId) => {
|
|
621
|
+
if (variantStockCache[productId])
|
|
622
|
+
return;
|
|
623
|
+
const stockMap = await getVariantStock({ productId });
|
|
624
|
+
variantStockCache[productId] = stockMap;
|
|
625
|
+
const currentResults = searchResults();
|
|
626
|
+
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
627
|
+
if (productIndex === -1)
|
|
628
|
+
return;
|
|
629
|
+
const product = currentResults[productIndex];
|
|
630
|
+
if (product.quickAddType !== QuickAddType.COLOR_AND_TEXT_OPTIONS)
|
|
631
|
+
return;
|
|
632
|
+
const selectedColor = product.quickOption?.choices?.find((c) => c.isSelected);
|
|
633
|
+
const textChoices = product.secondQuickOption?.choices;
|
|
634
|
+
if (!selectedColor || !textChoices)
|
|
635
|
+
return;
|
|
636
|
+
const colorStock = stockMap[selectedColor.choiceId];
|
|
637
|
+
const updatedTextChoices = textChoices.map((c) => ({
|
|
638
|
+
...c,
|
|
639
|
+
inStock: colorStock?.[c.choiceId] ?? false
|
|
640
|
+
}));
|
|
641
|
+
setSearchResults(patch(searchResults(), [
|
|
642
|
+
{
|
|
643
|
+
op: REPLACE,
|
|
644
|
+
path: [productIndex, "secondQuickOption", "choices"],
|
|
645
|
+
value: updatedTextChoices
|
|
646
|
+
}
|
|
647
|
+
]));
|
|
648
|
+
};
|
|
649
|
+
refs.searchResults.productLink.onmouseenter(({ coordinate }) => {
|
|
650
|
+
const [productId] = coordinate;
|
|
651
|
+
const product = searchResults().find((p) => p._id === productId);
|
|
652
|
+
if (product?.quickAddType === QuickAddType.COLOR_AND_TEXT_OPTIONS) {
|
|
653
|
+
loadVariantStock(productId);
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
refs.searchResults.quickOption.choices.choiceButton.onmouseenter(({ coordinate }) => {
|
|
657
|
+
const [productId] = coordinate;
|
|
658
|
+
const product = searchResults().find((p) => p._id === productId);
|
|
659
|
+
if (product?.quickAddType === QuickAddType.COLOR_AND_TEXT_OPTIONS) {
|
|
660
|
+
loadVariantStock(productId);
|
|
661
|
+
}
|
|
662
|
+
});
|
|
576
663
|
refs.searchResults.quickOption.choices.choiceButton.onclick(async ({ coordinate }) => {
|
|
577
664
|
const [productId, choiceId] = coordinate;
|
|
578
665
|
const currentResults = searchResults();
|
|
@@ -580,6 +667,44 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
580
667
|
if (productIndex === -1)
|
|
581
668
|
return;
|
|
582
669
|
const product = currentResults[productIndex];
|
|
670
|
+
if (product.quickAddType === QuickAddType.COLOR_AND_TEXT_OPTIONS) {
|
|
671
|
+
const choices = product.quickOption?.choices;
|
|
672
|
+
if (!choices)
|
|
673
|
+
return;
|
|
674
|
+
const updatedChoices = choices.map((c) => ({
|
|
675
|
+
...c,
|
|
676
|
+
isSelected: c.choiceId === choiceId
|
|
677
|
+
}));
|
|
678
|
+
let updated = patch(currentResults, [
|
|
679
|
+
{
|
|
680
|
+
op: REPLACE,
|
|
681
|
+
path: [productIndex, "quickOption", "choices"],
|
|
682
|
+
value: updatedChoices
|
|
683
|
+
}
|
|
684
|
+
]);
|
|
685
|
+
const stockMap = variantStockCache[productId];
|
|
686
|
+
if (stockMap) {
|
|
687
|
+
const colorStock = stockMap[choiceId];
|
|
688
|
+
const textChoices = product.secondQuickOption?.choices;
|
|
689
|
+
if (textChoices) {
|
|
690
|
+
const updatedTextChoices = textChoices.map((c) => ({
|
|
691
|
+
...c,
|
|
692
|
+
inStock: colorStock?.[c.choiceId] ?? false
|
|
693
|
+
}));
|
|
694
|
+
updated = patch(updated, [
|
|
695
|
+
{
|
|
696
|
+
op: REPLACE,
|
|
697
|
+
path: [productIndex, "secondQuickOption", "choices"],
|
|
698
|
+
value: updatedTextChoices
|
|
699
|
+
}
|
|
700
|
+
]);
|
|
701
|
+
}
|
|
702
|
+
} else {
|
|
703
|
+
loadVariantStock(productId);
|
|
704
|
+
}
|
|
705
|
+
setSearchResults(updated);
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
583
708
|
const choice = product.quickOption?.choices?.find((c) => c.choiceId === choiceId);
|
|
584
709
|
if (!choice || !choice.inStock) {
|
|
585
710
|
console.warn("Choice not available or out of stock");
|
|
@@ -603,6 +728,41 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
|
|
|
603
728
|
]));
|
|
604
729
|
}
|
|
605
730
|
});
|
|
731
|
+
refs.searchResults.secondQuickOption.choices.choiceButton.onclick(async ({ coordinate }) => {
|
|
732
|
+
const [productId, choiceId] = coordinate;
|
|
733
|
+
const currentResults = searchResults();
|
|
734
|
+
const productIndex = currentResults.findIndex((p) => p._id === productId);
|
|
735
|
+
if (productIndex === -1)
|
|
736
|
+
return;
|
|
737
|
+
const product = currentResults[productIndex];
|
|
738
|
+
const textChoice = product.secondQuickOption?.choices?.find((c) => c.choiceId === choiceId);
|
|
739
|
+
const selectedColor = product.quickOption?.choices?.find((c) => c.isSelected);
|
|
740
|
+
if (!textChoice || !textChoice.inStock) {
|
|
741
|
+
console.warn("Text choice not available or out of stock");
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
setSearchResults(patch(currentResults, [
|
|
745
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: true }
|
|
746
|
+
]));
|
|
747
|
+
try {
|
|
748
|
+
const colorOptionId = product.quickOption?._id || "";
|
|
749
|
+
const textOptionId = product.secondQuickOption?._id || "";
|
|
750
|
+
await storesContext.addToCart(productId, 1, {
|
|
751
|
+
options: {
|
|
752
|
+
[colorOptionId]: selectedColor?.choiceId || "",
|
|
753
|
+
[textOptionId]: textChoice.choiceId
|
|
754
|
+
},
|
|
755
|
+
modifiers: {},
|
|
756
|
+
customTextFields: {}
|
|
757
|
+
});
|
|
758
|
+
} catch (error) {
|
|
759
|
+
console.error("Failed to add to cart:", error);
|
|
760
|
+
} finally {
|
|
761
|
+
setSearchResults(patch(searchResults(), [
|
|
762
|
+
{ op: REPLACE, path: [productIndex, "isAddingToCart"], value: false }
|
|
763
|
+
]));
|
|
764
|
+
}
|
|
765
|
+
});
|
|
606
766
|
refs.searchResults.viewOptionsButton.onclick(({ coordinate }) => {
|
|
607
767
|
const [productId] = coordinate;
|
|
608
768
|
const product = searchResults().find((p) => p._id === productId);
|
|
@@ -634,10 +794,9 @@ const init = makeJayInit().withClient(async (data) => {
|
|
|
634
794
|
console.log("[wix-stores] Initializing client-side stores context...");
|
|
635
795
|
provideWixStoresContext();
|
|
636
796
|
console.log("[wix-stores] Client initialization complete");
|
|
637
|
-
console.log(`[wix-stores] Search enabled: ${data.enableClientSearch}`);
|
|
638
797
|
});
|
|
639
798
|
export {
|
|
640
|
-
WIX_CART_CONTEXT,
|
|
799
|
+
WIX_CART_CONTEXT2 as WIX_CART_CONTEXT,
|
|
641
800
|
WIX_STORES_CONTEXT,
|
|
642
801
|
cartIndicator,
|
|
643
802
|
cartPage,
|