@jay-framework/wix-stores 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -40,6 +40,12 @@ Supports three roles depending on route params:
40
40
 
41
41
  Lists all store categories for navigation.
42
42
 
43
+ ### Category Products (`category-products`)
44
+
45
+ Product grid from a specific category. Props: `categorySlug`, optional `productId` (exclude one product), optional `limit` (default 4).
46
+
47
+ **Related products on a product page:** bind `productId="{p._id}"` and `categorySlug="{p.categorySlug}"` from an existing `product-page` key. Same-category siblings — not machine-learning recommendations. See `agent-kit/designer/related-products.md` (copied to the project on `jay-stack agent-kit`) and Add Menu item `wix-stores:related-products`.
48
+
43
49
  ## Configuration
44
50
 
45
51
  ### Setup
@@ -50,12 +56,13 @@ The plugin requires `@jay-framework/wix-server-client` to be configured with Wix
50
56
  jay-stack setup wix-stores
51
57
  ```
52
58
 
53
- This creates `config/.wix-stores.yaml` and writes static AIditor Add Menu component items to `agent-kit/aiditor/add-menu/wix-stores.yaml`.
59
+ This creates `config/.wix-stores.yaml` and writes static AIditor Add Menu component items to `agent-kit/aiditor/add-menu/wix-stores.yaml` (includes **Related products** — `wix-stores:related-products`).
54
60
 
55
61
  Run `jay-stack agent-kit` (or `yarn agent-kit`) to index the live category tree and refresh:
56
62
 
57
63
  - `agent-kit/references/wix-stores/categories.yaml` — full hierarchy for agent discovery
58
64
  - `agent-kit/aiditor/add-menu/wix-stores.generated.yaml` — one Add Menu item per category (Store → Categories)
65
+ - `agent-kit/designer/related-products.md` — recipe for related products on product pages (from this package)
59
66
 
60
67
  ### Config File (`config/.wix-stores.yaml`)
61
68
 
@@ -0,0 +1,109 @@
1
+ items:
2
+ - id: wix-stores:product-search
3
+ title: Product search
4
+ category: Store
5
+ subCategory: Components
6
+ pluginName: wix-stores
7
+ packageName: "@jay-framework/wix-stores"
8
+ thumbnail: thumbnails/wix-stores/product-search.svg
9
+ interaction:
10
+ mode: stage-place
11
+ stagePromptTemplate: |
12
+ Add a product search component at this marker location on the page.
13
+ prompt: |
14
+ Use headless component @jay-framework/wix-stores / contract product-search.
15
+ Read node_modules/@jay-framework/wix-stores/dist/contracts/product-search.jay-contract.
16
+ Script key: search
17
+ Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
18
+
19
+ - id: wix-stores:product-page
20
+ title: Product page
21
+ category: Store
22
+ subCategory: Components
23
+ pluginName: wix-stores
24
+ packageName: "@jay-framework/wix-stores"
25
+ thumbnail: thumbnails/wix-stores/product-page.svg
26
+ interaction:
27
+ mode: stage-place
28
+ stagePromptTemplate: |
29
+ Add a product page component at this marker location on the page.
30
+ prompt: |
31
+ Use headless component @jay-framework/wix-stores / contract product-page.
32
+ Read agent-kit/materialized-contracts/wix-stores/product-page.jay-contract.
33
+ Script key: p
34
+ Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
35
+
36
+ - id: wix-stores:related-products
37
+ title: Related products
38
+ category: Store
39
+ subCategory: Components
40
+ pluginName: wix-stores
41
+ packageName: "@jay-framework/wix-stores"
42
+ thumbnail: thumbnails/wix-stores/related-products.svg
43
+ interaction:
44
+ mode: stage-place
45
+ stagePromptTemplate: |
46
+ Add a related products section at this marker location on the page.
47
+ prompt: |
48
+ "Related products" uses contract category-products (no separate related-products contract).
49
+ Read agent-kit/designer/related-products.md for the full recipe.
50
+ Read node_modules/@jay-framework/wix-stores/dist/contracts/category-products.jay-contract.
51
+ On a product page that already has product-page (key "p"):
52
+ 1. Add headless import for category-products in <head> (no key attribute).
53
+ 2. Place <jay:category-products productId="{p._id}" categorySlug="{p.categorySlug}" limit="4"> at the marker.
54
+ 3. Inside the wrapper: forEach="products" with product-card fields; refs use products.* prefix.
55
+ Same-category siblings excluding the current product — not ML recommendations.
56
+
57
+ - id: wix-stores:category-products
58
+ title: Category products
59
+ category: Store
60
+ subCategory: Components
61
+ pluginName: wix-stores
62
+ packageName: "@jay-framework/wix-stores"
63
+ thumbnail: thumbnails/wix-stores/category-products.svg
64
+ interaction:
65
+ mode: stage-place
66
+ stagePromptTemplate: |
67
+ Add a category products grid at this marker location on the page.
68
+ prompt: |
69
+ Use headless component @jay-framework/wix-stores / contract category-products.
70
+ Read node_modules/@jay-framework/wix-stores/dist/contracts/category-products.jay-contract.
71
+ Instance pattern: declare import in <head> without key, then <jay:category-products categorySlug="...">.
72
+ Pass categorySlug to show products from a category. Pass productId to exclude a product.
73
+ On product pages for "related products", see agent-kit/designer/related-products.md instead.
74
+ Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
75
+
76
+ - id: wix-stores:product-spotlight
77
+ title: Product spotlight
78
+ category: Store
79
+ subCategory: Components
80
+ pluginName: wix-stores
81
+ packageName: "@jay-framework/wix-stores"
82
+ thumbnail: thumbnails/wix-stores/product-spotlight.png
83
+ interaction:
84
+ mode: stage-place
85
+ stagePromptTemplate: |
86
+ Add a product spotlight at this marker location on the page.
87
+ prompt: |
88
+ Use headless component @jay-framework/wix-stores / contract product-spotlight.
89
+ Read node_modules/@jay-framework/wix-stores/dist/contracts/product-spotlight.jay-contract.
90
+ Instance pattern: declare import in <head> without key, then <jay:product-spotlight slug="...">.
91
+ Pass slug as a prop to specify which product to display.
92
+ Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
93
+
94
+ - id: wix-stores:category-list
95
+ title: Category list
96
+ category: Store
97
+ subCategory: Components
98
+ pluginName: wix-stores
99
+ packageName: "@jay-framework/wix-stores"
100
+ thumbnail: thumbnails/wix-stores/category-list.svg
101
+ interaction:
102
+ mode: stage-place
103
+ stagePromptTemplate: |
104
+ Add a category list at this marker location on the page.
105
+ prompt: |
106
+ Use headless component @jay-framework/wix-stores / contract category-list.
107
+ Read node_modules/@jay-framework/wix-stores/dist/contracts/category-list.jay-contract.
108
+ Script key: categories
109
+ Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
@@ -0,0 +1,12 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="240" viewBox="0 0 320 240" fill="none">
2
+ <rect width="320" height="240" fill="#f8fafc"/>
3
+ <rect x="16" y="20" width="288" height="36" rx="8" fill="#fff" stroke="#e2e8f0"/>
4
+ <rect x="28" y="32" width="120" height="12" rx="3" fill="#cbd5e1"/>
5
+ <rect x="16" y="72" width="136" height="14" rx="4" fill="#e2e8f0"/>
6
+ <rect x="16" y="98" width="288" height="1" fill="#e2e8f0"/>
7
+ <rect x="16" y="112" width="200" height="12" rx="3" fill="#cbd5e1"/>
8
+ <rect x="16" y="136" width="160" height="10" rx="3" fill="#e2e8f0"/>
9
+ <rect x="16" y="168" width="288" height="1" fill="#e2e8f0"/>
10
+ <rect x="16" y="182" width="184" height="12" rx="3" fill="#cbd5e1"/>
11
+ <rect x="16" y="206" width="128" height="10" rx="3" fill="#e2e8f0"/>
12
+ </svg>
@@ -0,0 +1,15 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="240" viewBox="0 0 320 240" fill="none">
2
+ <rect width="320" height="240" fill="#f8fafc"/>
3
+ <rect x="16" y="24" width="120" height="12" rx="3" fill="#cbd5e1"/>
4
+ <rect x="16" y="56" width="72" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
5
+ <rect x="24" y="64" width="56" height="48" rx="4" fill="#dbeafe"/>
6
+ <rect x="24" y="120" width="48" height="8" rx="2" fill="#cbd5e1"/>
7
+ <rect x="96" y="56" width="72" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
8
+ <rect x="104" y="64" width="56" height="48" rx="4" fill="#fce7f3"/>
9
+ <rect x="104" y="120" width="48" height="8" rx="2" fill="#cbd5e1"/>
10
+ <rect x="176" y="56" width="72" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
11
+ <rect x="184" y="64" width="56" height="48" rx="4" fill="#dcfce7"/>
12
+ <rect x="184" y="120" width="48" height="8" rx="2" fill="#cbd5e1"/>
13
+ <rect x="248" y="56" width="56" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
14
+ <rect x="256" y="64" width="40" height="48" rx="4" fill="#fef3c7"/>
15
+ </svg>
@@ -0,0 +1,12 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="240" viewBox="0 0 320 240" fill="none">
2
+ <rect width="320" height="240" fill="#f4f7fb"/>
3
+ <rect x="16" y="16" width="288" height="28" rx="6" fill="#e2e8f0"/>
4
+ <rect x="16" y="56" width="120" height="12" rx="3" fill="#cbd5e1"/>
5
+ <rect x="16" y="76" width="88" height="10" rx="3" fill="#e2e8f0"/>
6
+ <rect x="16" y="104" width="136" height="120" rx="8" fill="#dbeafe" stroke="#93c5fd"/>
7
+ <rect x="168" y="104" width="136" height="16" rx="4" fill="#cbd5e1"/>
8
+ <rect x="168" y="128" width="96" height="10" rx="3" fill="#e2e8f0"/>
9
+ <rect x="168" y="148" width="72" height="10" rx="3" fill="#e2e8f0"/>
10
+ <rect x="168" y="180" width="88" height="28" rx="6" fill="#2563eb"/>
11
+ <text x="188" y="198" fill="#fff" font-family="system-ui,sans-serif" font-size="11">Add to cart</text>
12
+ </svg>
@@ -0,0 +1,17 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="240" viewBox="0 0 320 240" fill="none">
2
+ <rect width="320" height="240" fill="#f8fafc"/>
3
+ <rect x="16" y="16" width="200" height="24" rx="6" fill="#fff" stroke="#cbd5e1"/>
4
+ <rect x="24" y="24" width="64" height="8" rx="2" fill="#e2e8f0"/>
5
+ <g>
6
+ <rect x="16" y="56" width="88" height="88" rx="8" fill="#fff" stroke="#e2e8f0"/>
7
+ <rect x="24" y="64" width="72" height="48" rx="4" fill="#dbeafe"/>
8
+ <rect x="24" y="120" width="56" height="8" rx="2" fill="#cbd5e1"/>
9
+ <rect x="112" y="56" width="88" height="88" rx="8" fill="#fff" stroke="#e2e8f0"/>
10
+ <rect x="120" y="64" width="72" height="48" rx="4" fill="#fce7f3"/>
11
+ <rect x="120" y="120" width="56" height="8" rx="2" fill="#cbd5e1"/>
12
+ <rect x="208" y="56" width="88" height="88" rx="8" fill="#fff" stroke="#e2e8f0"/>
13
+ <rect x="216" y="64" width="72" height="48" rx="4" fill="#dcfce7"/>
14
+ <rect x="216" y="120" width="56" height="8" rx="2" fill="#cbd5e1"/>
15
+ </g>
16
+ <rect x="16" y="160" width="288" height="64" rx="8" fill="#fff" stroke="#e2e8f0"/>
17
+ </svg>
@@ -0,0 +1,15 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="240" viewBox="0 0 320 240" fill="none">
2
+ <rect width="320" height="240" fill="#f8fafc"/>
3
+ <rect x="16" y="24" width="120" height="12" rx="3" fill="#cbd5e1"/>
4
+ <rect x="16" y="56" width="72" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
5
+ <rect x="24" y="64" width="56" height="48" rx="4" fill="#dbeafe"/>
6
+ <rect x="24" y="120" width="48" height="8" rx="2" fill="#cbd5e1"/>
7
+ <rect x="96" y="56" width="72" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
8
+ <rect x="104" y="64" width="56" height="48" rx="4" fill="#fce7f3"/>
9
+ <rect x="104" y="120" width="48" height="8" rx="2" fill="#cbd5e1"/>
10
+ <rect x="176" y="56" width="72" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
11
+ <rect x="184" y="64" width="56" height="48" rx="4" fill="#dcfce7"/>
12
+ <rect x="184" y="120" width="48" height="8" rx="2" fill="#cbd5e1"/>
13
+ <rect x="248" y="56" width="56" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
14
+ <rect x="256" y="64" width="40" height="48" rx="4" fill="#fef3c7"/>
15
+ </svg>
@@ -0,0 +1,123 @@
1
+ # Related Products (Product Page)
2
+
3
+ Show a row of product cards at the bottom of a product detail page — same-category siblings, excluding the product being viewed.
4
+
5
+ **Synonym:** user requests for "Related Products", "You may also like", or "More from this category" on a product page all map to the **`category-products`** contract. There is no separate `related-products` contract.
6
+
7
+ **Data model:** products from the displayed product's category (`product-page.categorySlug`), excluding the current product (`product-page._id`). This is **not** machine-learning recommendations — it is same-category catalog browsing.
8
+
9
+ ## Prerequisites
10
+
11
+ The page already imports **`product-page`** with a script key (convention: `p`):
12
+
13
+ ```html
14
+ <script
15
+ type="application/jay-headless"
16
+ plugin="@jay-framework/wix-stores"
17
+ contract="product-page"
18
+ key="p"
19
+ ></script>
20
+ ```
21
+
22
+ `p.categorySlug` and `p._id` must be available from the product-page contract.
23
+
24
+ ## Import
25
+
26
+ Add a **second** headless import — **no `key`** (instance-based pattern):
27
+
28
+ ```html
29
+ <script
30
+ type="application/jay-headless"
31
+ plugin="@jay-framework/wix-stores"
32
+ contract="category-products"
33
+ ></script>
34
+ ```
35
+
36
+ ## Template
37
+
38
+ Place after the main product layout, typically before the footer:
39
+
40
+ ```html
41
+ <jay:category-products productId="{p._id}" categorySlug="{p.categorySlug}" limit="4">
42
+ <section class="related-section" if="hasProducts">
43
+ <h2>Related products</h2>
44
+ <div class="related-grid">
45
+ <article class="related-card" forEach="products" trackBy="_id" ref="products.cardContainer">
46
+ <a href="{productUrl}" class="related-card-image">
47
+ <img src="{thumbnail.url}" alt="{thumbnail.altText}" loading="lazy" />
48
+ <span class="related-ribbon" if="hasRibbon">{ribbon.name}</span>
49
+ </a>
50
+ <div class="related-card-body">
51
+ <h3 class="related-card-name">
52
+ <a href="{productUrl}" ref="products.productLink">{name}</a>
53
+ </h3>
54
+ <div class="related-card-price">
55
+ <span class="original" if="hasDiscount">{strikethroughPrice}</span>
56
+ <span>{price}</span>
57
+ </div>
58
+ <button
59
+ class="btn-add"
60
+ ref="products.addToCartButton"
61
+ if="quickAddType===SIMPLE && inventory.availabilityStatus===IN_STOCK"
62
+ disabled="isAddingToCart"
63
+ >
64
+ <span if="!isAddingToCart">Add to Cart</span>
65
+ <span if="isAddingToCart">Adding...</span>
66
+ </button>
67
+ <a
68
+ href="{productUrl}"
69
+ class="btn-add btn-options"
70
+ ref="products.viewOptionsButton"
71
+ if="quickAddType!==SIMPLE && inventory.availabilityStatus!==OUT_OF_STOCK"
72
+ >View Options</a>
73
+ </div>
74
+ </article>
75
+ </div>
76
+ </section>
77
+ </jay:category-products>
78
+ ```
79
+
80
+ Inside `<jay:category-products>`, bindings resolve to **that instance's** contract tags (`products`, `hasProducts`, `categoryName`) — not the parent `p` key.
81
+
82
+ ## Props
83
+
84
+ | Prop | Value on product page | Purpose |
85
+ | --- | --- | --- |
86
+ | `productId` | `{p._id}` | Exclude the current product from results |
87
+ | `categorySlug` | `{p.categorySlug}` | Load siblings from the same category |
88
+ | `limit` | `4` (optional) | Max cards to show (default 4) |
89
+
90
+ ## Refs
91
+
92
+ Product cards use the `product-card` sub-contract. Prefix refs with `products.`:
93
+
94
+ | Ref | Element |
95
+ | --- | --- |
96
+ | `products.productLink` | Product name link |
97
+ | `products.addToCartButton` | Quick add (SIMPLE products) |
98
+ | `products.viewOptionsButton` | Link to product page (configured products) |
99
+ | `products.cardContainer` | Card root (variant stock preload on hover) |
100
+
101
+ See [product-card example](../contracts/examples/product-card.md) for all available fields.
102
+
103
+ ## Contract paths
104
+
105
+ | Contract | Path |
106
+ | --- | --- |
107
+ | `category-products` | `node_modules/@jay-framework/wix-stores/dist/contracts/category-products.jay-contract` |
108
+ | `product-page` | `agent-kit/materialized-contracts/wix-stores/product-page.jay-contract` (dynamic — materialized on setup) |
109
+ | `product-card` | Linked sub-contract inside `category-products` |
110
+
111
+ Or read paths from `agent-kit/plugins-index.yaml`.
112
+
113
+ ## Category showcases (not product page)
114
+
115
+ To show products from a **specific** category on any page (homepage, landing page), use the same `category-products` contract with a static or param-driven `categorySlug`. Omit `productId` when there is no product to exclude. See Add Menu item **Category products** (`wix-stores:category-products`).
116
+
117
+ ## Reference implementation
118
+
119
+ `examples/store-light/src/pages/products/[slug]/page.jay-html` in the wix-stores package repo — Related Products section at page bottom.
120
+
121
+ ## AIditor Add Menu
122
+
123
+ Attach **Related products** (`wix-stores:related-products`) when marking an area on a product page. The item prompt includes this recipe; `jay-stack agent-kit` writes the catalog to `agent-kit/aiditor/add-menu/wix-stores.yaml`.
@@ -12,7 +12,7 @@ items:
12
12
  Add a product search component at this marker location on the page.
13
13
  prompt: |
14
14
  Use headless component @jay-framework/wix-stores / contract product-search.
15
- Read agent-kit/materialized-contracts/wix-stores/product-search.jay-contract.
15
+ Read node_modules/@jay-framework/wix-stores/dist/contracts/product-search.jay-contract.
16
16
  Script key: search
17
17
  Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
18
18
 
@@ -33,6 +33,27 @@ items:
33
33
  Script key: p
34
34
  Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
35
35
 
36
+ - id: wix-stores:related-products
37
+ title: Related products
38
+ category: Store
39
+ subCategory: Components
40
+ pluginName: wix-stores
41
+ packageName: "@jay-framework/wix-stores"
42
+ thumbnail: thumbnails/wix-stores/related-products.svg
43
+ interaction:
44
+ mode: stage-place
45
+ stagePromptTemplate: |
46
+ Add a related products section at this marker location on the page.
47
+ prompt: |
48
+ "Related products" uses contract category-products (no separate related-products contract).
49
+ Read agent-kit/designer/related-products.md for the full recipe.
50
+ Read node_modules/@jay-framework/wix-stores/dist/contracts/category-products.jay-contract.
51
+ On a product page that already has product-page (key "p"):
52
+ 1. Add headless import for category-products in <head> (no key attribute).
53
+ 2. Place <jay:category-products productId="{p._id}" categorySlug="{p.categorySlug}" limit="4"> at the marker.
54
+ 3. Inside the wrapper: forEach="products" with product-card fields; refs use products.* prefix.
55
+ Same-category siblings excluding the current product — not ML recommendations.
56
+
36
57
  - id: wix-stores:category-products
37
58
  title: Category products
38
59
  category: Store
@@ -46,10 +67,11 @@ items:
46
67
  Add a category products grid at this marker location on the page.
47
68
  prompt: |
48
69
  Use headless component @jay-framework/wix-stores / contract category-products.
49
- Read agent-kit/materialized-contracts/wix-stores/category-products.jay-contract.
50
- Script key: r
70
+ Read node_modules/@jay-framework/wix-stores/dist/contracts/category-products.jay-contract.
71
+ Instance pattern: declare import in <head> without key, then <jay:category-products categorySlug="...">.
72
+ Pass categorySlug to show products from a category. Pass productId to exclude a product.
73
+ On product pages for "related products", see agent-kit/designer/related-products.md instead.
51
74
  Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
52
- Pass categorySlug to show products from a category. Pass productId to exclude a product (e.g. on a product page).
53
75
 
54
76
  - id: wix-stores:product-spotlight
55
77
  title: Product spotlight
@@ -64,10 +86,10 @@ items:
64
86
  Add a product spotlight at this marker location on the page.
65
87
  prompt: |
66
88
  Use headless component @jay-framework/wix-stores / contract product-spotlight.
67
- Read agent-kit/materialized-contracts/wix-stores/product-spotlight.jay-contract.
68
- Script key: spotlight
69
- Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
89
+ Read node_modules/@jay-framework/wix-stores/dist/contracts/product-spotlight.jay-contract.
90
+ Instance pattern: declare import in <head> without key, then <jay:product-spotlight slug="...">.
70
91
  Pass slug as a prop to specify which product to display.
92
+ Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
71
93
 
72
94
  - id: wix-stores:category-list
73
95
  title: Category list
@@ -82,6 +104,6 @@ items:
82
104
  Add a category list at this marker location on the page.
83
105
  prompt: |
84
106
  Use headless component @jay-framework/wix-stores / contract category-list.
85
- Read agent-kit/materialized-contracts/wix-stores/category-list.jay-contract.
107
+ Read node_modules/@jay-framework/wix-stores/dist/contracts/category-list.jay-contract.
86
108
  Script key: categories
87
109
  Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
@@ -0,0 +1,15 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="320" height="240" viewBox="0 0 320 240" fill="none">
2
+ <rect width="320" height="240" fill="#f8fafc"/>
3
+ <rect x="16" y="24" width="120" height="12" rx="3" fill="#cbd5e1"/>
4
+ <rect x="16" y="56" width="72" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
5
+ <rect x="24" y="64" width="56" height="48" rx="4" fill="#dbeafe"/>
6
+ <rect x="24" y="120" width="48" height="8" rx="2" fill="#cbd5e1"/>
7
+ <rect x="96" y="56" width="72" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
8
+ <rect x="104" y="64" width="56" height="48" rx="4" fill="#fce7f3"/>
9
+ <rect x="104" y="120" width="48" height="8" rx="2" fill="#cbd5e1"/>
10
+ <rect x="176" y="56" width="72" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
11
+ <rect x="184" y="64" width="56" height="48" rx="4" fill="#dcfce7"/>
12
+ <rect x="184" y="120" width="48" height="8" rx="2" fill="#cbd5e1"/>
13
+ <rect x="248" y="56" width="56" height="96" rx="8" fill="#fff" stroke="#e2e8f0"/>
14
+ <rect x="256" y="64" width="40" height="48" rx="4" fill="#fef3c7"/>
15
+ </svg>
@@ -4,9 +4,7 @@ import { makeJayStackComponent, makeJayInit } from "@jay-framework/fullstack-com
4
4
  import { registerReactiveGlobalContext, createSignal, createMemo, createEffect } from "@jay-framework/component";
5
5
  import { patch, REPLACE } from "@jay-framework/json-patch";
6
6
  import { createJayContext, useGlobalContext } from "@jay-framework/runtime";
7
- import { WIX_CLIENT_CONTEXT } from "@jay-framework/wix-server-client/client";
8
- import { productsV3 } from "@wix/stores";
9
- import "@wix/categories";
7
+ import { wixFetch, WIX_CLIENT_CONTEXT } from "@jay-framework/wix-server-client/client";
10
8
  import { createActionCaller } from "@jay-framework/stack-client-runtime";
11
9
  var StockStatus = /* @__PURE__ */ ((StockStatus2) => {
12
10
  StockStatus2[StockStatus2["OUT_OF_STOCK"] = 0] = "OUT_OF_STOCK";
@@ -18,27 +16,145 @@ var Selected = /* @__PURE__ */ ((Selected2) => {
18
16
  Selected2[Selected2["notSelected"] = 1] = "notSelected";
19
17
  return Selected2;
20
18
  })(Selected || {});
21
- const instances = {
22
- productsV3ClientInstance: void 0
23
- };
24
- function getProductsV3Client(wixClient) {
25
- if (!instances.productsV3ClientInstance) {
26
- instances.productsV3ClientInstance = wixClient.use(productsV3);
19
+ function raw(value) {
20
+ return value;
21
+ }
22
+ function rawArray(value) {
23
+ return value;
24
+ }
25
+ function str(value) {
26
+ return value;
27
+ }
28
+ function normalizeProduct(product) {
29
+ if (!product) return product;
30
+ const normalized = { ...product };
31
+ if (normalized.id && !normalized._id) {
32
+ normalized._id = normalized.id;
33
+ }
34
+ const media = raw(normalized.media);
35
+ if (media?.main) {
36
+ const main = raw(media.main);
37
+ const mainImage = raw(main.image);
38
+ normalized.media = {
39
+ ...media,
40
+ main: {
41
+ _id: main.id || main._id,
42
+ url: mainImage?.url || main.url,
43
+ altText: mainImage?.altText || main.altText,
44
+ mediaType: main.mediaType,
45
+ width: mainImage?.width,
46
+ height: mainImage?.height
47
+ }
48
+ };
49
+ }
50
+ const updatedMedia = raw(normalized.media);
51
+ const itemsInfo = raw(updatedMedia?.itemsInfo);
52
+ if (itemsInfo?.items) {
53
+ itemsInfo.items = rawArray(itemsInfo.items).map((item) => {
54
+ const image = raw(item.image);
55
+ return {
56
+ _id: item.id || item._id,
57
+ url: image?.url || item.url,
58
+ altText: image?.altText || item.altText,
59
+ mediaType: item.mediaType,
60
+ width: image?.width,
61
+ height: image?.height
62
+ };
63
+ });
64
+ }
65
+ if (normalized.options) {
66
+ normalized.options = rawArray(normalized.options).map((opt) => {
67
+ const choicesSettings = raw(opt.choicesSettings);
68
+ return {
69
+ ...opt,
70
+ _id: opt.id || opt._id,
71
+ choices: choicesSettings?.choices ? rawArray(choicesSettings.choices).map((c) => {
72
+ const linkedMedia = c.linkedMedia;
73
+ const firstMedia = linkedMedia?.[0];
74
+ const firstMediaImage = firstMedia ? raw(firstMedia.image) : void 0;
75
+ return {
76
+ ...c,
77
+ _id: c.choiceId || c._id,
78
+ value: c.name || c.value,
79
+ media: firstMedia ? {
80
+ _id: firstMedia.id,
81
+ url: str(firstMediaImage?.url) || firstMedia.url,
82
+ mediaType: firstMedia.mediaType
83
+ } : void 0
84
+ };
85
+ }) : void 0
86
+ };
87
+ });
88
+ }
89
+ if (normalized.modifiers) {
90
+ normalized.modifiers = rawArray(normalized.modifiers).map((mod) => {
91
+ const choicesSettings = raw(mod.choicesSettings);
92
+ return {
93
+ ...mod,
94
+ _id: mod.id || mod._id,
95
+ choices: choicesSettings?.choices ? rawArray(choicesSettings.choices).map((c) => ({
96
+ ...c,
97
+ _id: c.choiceId || c._id,
98
+ value: c.name || c.value
99
+ })) : void 0
100
+ };
101
+ });
102
+ }
103
+ if (normalized.infoSections) {
104
+ normalized.infoSections = rawArray(normalized.infoSections).map((s) => ({
105
+ ...s,
106
+ _id: s.id || s._id
107
+ }));
108
+ }
109
+ const variantsInfo = raw(normalized.variantsInfo);
110
+ if (variantsInfo?.variants) {
111
+ variantsInfo.variants = rawArray(variantsInfo.variants).map((v) => ({
112
+ ...v,
113
+ _id: v.id || v._id
114
+ }));
115
+ }
116
+ if (normalized.ribbon) {
117
+ const ribbon = raw(normalized.ribbon);
118
+ normalized.ribbon = {
119
+ ...ribbon,
120
+ _id: ribbon.id || ribbon._id
121
+ };
27
122
  }
28
- return instances.productsV3ClientInstance;
123
+ return normalized;
124
+ }
125
+ async function getProduct(client, productId, options) {
126
+ const params = new URLSearchParams();
127
+ {
128
+ params.set("includeMerchantSpecificData", "true");
129
+ }
130
+ if (options?.fields) {
131
+ for (const f of options.fields) {
132
+ params.append("fields", f);
133
+ }
134
+ }
135
+ const qs = params.toString();
136
+ const result = await wixFetch(
137
+ client,
138
+ `/stores/v3/products/${productId}${qs ? "?" + qs : ""}`,
139
+ {
140
+ method: "GET"
141
+ }
142
+ );
143
+ if (result.product) {
144
+ result.product = normalizeProduct(result.product);
145
+ }
146
+ return result;
29
147
  }
30
148
  const WIX_STORES_CONTEXT = createJayContext("wix:stores");
31
149
  function provideWixStoresContext() {
32
150
  const wixClientContext = useGlobalContext(WIX_CLIENT_CONTEXT);
33
151
  const wixClient = wixClientContext.client;
34
152
  const cartContext = useGlobalContext(WIX_CART_CONTEXT);
35
- const catalogClient = getProductsV3Client(wixClient);
36
153
  const storesContext = registerReactiveGlobalContext(WIX_STORES_CONTEXT, () => {
37
154
  async function addToCart(productId, quantity = 1, selections) {
38
155
  console.log(`[WixStores] Adding to cart: ${productId} x ${quantity}`, selections);
39
- const product = await catalogClient.getProduct(productId, {
40
- fields: ["VARIANT_OPTION_CHOICE_NAMES"]
41
- });
156
+ const result = await getProduct(wixClient, productId, {});
157
+ const product = result.product;
42
158
  let variant = product.variantsInfo?.variants?.find(
43
159
  (v) => v.choices?.every(
44
160
  (choice) => selections?.options?.[choice.optionChoiceIds?.optionId] === choice.optionChoiceIds?.choiceId