@jay-framework/wix-stores 0.15.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 +184 -0
- package/dist/actions/get-categories.jay-action +8 -0
- package/dist/actions/get-product-by-slug.jay-action +10 -0
- package/dist/actions/search-products.jay-action +33 -0
- package/dist/contracts/category-list.jay-contract +50 -0
- package/dist/contracts/category-list.jay-contract.d.ts +40 -0
- package/dist/contracts/category-page.jay-contract +193 -0
- package/dist/contracts/category-page.jay-contract.d.ts +124 -0
- package/dist/contracts/media-gallery.jay-contract +22 -0
- package/dist/contracts/media-gallery.jay-contract.d.ts +53 -0
- package/dist/contracts/media.jay-contract +5 -0
- package/dist/contracts/media.jay-contract.d.ts +25 -0
- package/dist/contracts/product-card.jay-contract +182 -0
- package/dist/contracts/product-card.jay-contract.d.ts +120 -0
- package/dist/contracts/product-options.jay-contract +66 -0
- package/dist/contracts/product-options.jay-contract.d.ts +57 -0
- package/dist/contracts/product-page.jay-contract +151 -0
- package/dist/contracts/product-page.jay-contract.d.ts +218 -0
- package/dist/contracts/product-search.jay-contract +252 -0
- package/dist/contracts/product-search.jay-contract.d.ts +169 -0
- package/dist/index.client.js +649 -0
- package/dist/index.d.ts +943 -0
- package/dist/index.js +1140 -0
- package/package.json +66 -0
- package/plugin.yaml +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# @jay-framework/wix-stores
|
|
2
|
+
|
|
3
|
+
Wix Stores integration for Jay Framework using the Catalog V3 API. Provides headless full-stack components for product pages, search/listing, and category navigation with server-side rendering.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Catalog V3 API** - Uses `productsV3` and `@wix/categories` for product and category data
|
|
8
|
+
- **Three-phase rendering** - Slow (build/SSG), Fast (request/SSR), Interactive (client)
|
|
9
|
+
- **Category-prefixed routes** - Optional URL prefixes per product line (e.g., `/products/polgat/shirt-name`)
|
|
10
|
+
- **Unified search + category** - Single `product-search` component handles both search pages and category listings
|
|
11
|
+
- **Shared cart** - Delegates cart operations to `@jay-framework/wix-cart`
|
|
12
|
+
|
|
13
|
+
## Headless Components
|
|
14
|
+
|
|
15
|
+
### Product Page (`product-page`)
|
|
16
|
+
|
|
17
|
+
Complete product detail page with variant selection and add-to-cart.
|
|
18
|
+
|
|
19
|
+
- **Slow phase**: Product details, media gallery, options, SEO data
|
|
20
|
+
- **Fast phase**: Inventory status, pricing, variant availability
|
|
21
|
+
- **Interactive**: Option/modifier selection, quantity, add to cart
|
|
22
|
+
|
|
23
|
+
Route: `/products/[slug]` or `/products/[category]/[slug]` (when category prefixes are configured)
|
|
24
|
+
|
|
25
|
+
### Product Search (`product-search`)
|
|
26
|
+
|
|
27
|
+
Unified search and category listing component. Replaces the previous separate `category-page` component.
|
|
28
|
+
|
|
29
|
+
- **Slow phase**: Available categories for filtering
|
|
30
|
+
- **Fast phase**: Initial product results with price aggregations
|
|
31
|
+
- **Interactive**: Search input, category/price/stock filters, sorting, load more
|
|
32
|
+
|
|
33
|
+
When a `category` URL parameter is provided (e.g., from a route like `/products/polgat/`):
|
|
34
|
+
|
|
35
|
+
- Scopes all searches to products within that category hierarchy
|
|
36
|
+
- Shows only child categories of the root as filter options (root category is hidden)
|
|
37
|
+
- Enables per-category template designs via separate jay-html files
|
|
38
|
+
|
|
39
|
+
### Category List (`category-list`)
|
|
40
|
+
|
|
41
|
+
Lists all store categories for navigation.
|
|
42
|
+
|
|
43
|
+
## Configuration
|
|
44
|
+
|
|
45
|
+
### Basic Setup
|
|
46
|
+
|
|
47
|
+
The plugin requires `@jay-framework/wix-server-client` to be configured with Wix API credentials.
|
|
48
|
+
|
|
49
|
+
Run setup to create the config template:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
jay-stack setup wix-stores
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Category Prefixes (Optional)
|
|
56
|
+
|
|
57
|
+
To enable category-prefixed product routes, create `config/.wix-stores.yaml`:
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
categoryPrefixes:
|
|
61
|
+
- categoryId: '024a9fff-77de-4508-b82c-5fce24f74757'
|
|
62
|
+
prefix: 'polgat'
|
|
63
|
+
name: 'פולגת'
|
|
64
|
+
- categoryId: 'eac4db24-04cc-4f36-86cf-c9da6e873421'
|
|
65
|
+
prefix: 'kitan'
|
|
66
|
+
name: 'כיתן'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Each entry maps a root Wix category to a URL prefix. Products belonging to any child of the root category get URLs like `/products/{prefix}/{product-slug}`.
|
|
70
|
+
|
|
71
|
+
To find category IDs, run setup to generate the category tree reference:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
jay-stack setup wix-stores
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
This creates `agent-kit/references/wix-stores/categories.yaml` with all category IDs, names, product counts, and parent-child relationships as a tree.
|
|
78
|
+
|
|
79
|
+
### Route Structure with Category Prefixes
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
src/pages/products/
|
|
83
|
+
├── page.jay-html # /products (default search, optional)
|
|
84
|
+
├── [slug]/page.jay-html # /products/:slug (default product page, optional)
|
|
85
|
+
├── polgat/
|
|
86
|
+
│ ├── page.jay-html # /products/polgat (polgat-design search)
|
|
87
|
+
│ └── [slug]/page.jay-html # /products/polgat/:slug (polgat product page)
|
|
88
|
+
└── kitan/
|
|
89
|
+
├── page.jay-html # /products/kitan (kitan-design search)
|
|
90
|
+
└── [slug]/page.jay-html # /products/kitan/:slug (kitan product page)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Each prefix directory gets its own jay-html templates, enabling different visual designs per product line. Jay's routing precedence ensures static segments (`polgat`, `kitan`) take priority over the dynamic `[slug]` parameter.
|
|
94
|
+
|
|
95
|
+
Products without a matching category prefix fall back to `/products/[slug]` if that route exists, or return 404 if it doesn't.
|
|
96
|
+
|
|
97
|
+
## Server Actions
|
|
98
|
+
|
|
99
|
+
### `searchProducts`
|
|
100
|
+
|
|
101
|
+
Search products with filtering, sorting, and price aggregations.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
const results = await searchProducts({
|
|
105
|
+
query: 'shoes',
|
|
106
|
+
filters: { inStockOnly: true, categoryIds: ['cat-123'] },
|
|
107
|
+
sortBy: 'price_asc',
|
|
108
|
+
pageSize: 12,
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
CLI:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
jay-stack action wix-stores/searchProducts
|
|
116
|
+
jay-stack action wix-stores/searchProducts --input '{"query": "shoes", "pageSize": 5}'
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### `getProductBySlug`
|
|
120
|
+
|
|
121
|
+
Fetch a single product by its URL slug.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const product = await getProductBySlug({ slug: 'blue-sneakers' });
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
CLI:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
jay-stack action wix-stores/getProductBySlug --input '{"slug": "blue-sneakers"}'
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### `getCategories`
|
|
134
|
+
|
|
135
|
+
Get all visible categories for filtering.
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const categories = await getCategories();
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
CLI:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
jay-stack action wix-stores/getCategories
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Agent Kit References
|
|
148
|
+
|
|
149
|
+
Running `jay-stack setup wix-stores` or `jay-stack agent-kit` generates a category tree reference at `agent-kit/references/wix-stores/categories.yaml`. This file contains:
|
|
150
|
+
|
|
151
|
+
- All visible categories with IDs, names, slugs, and product counts
|
|
152
|
+
- Full parent-child hierarchy as a nested tree
|
|
153
|
+
- Configured category prefixes (if any) with their mapped category names
|
|
154
|
+
|
|
155
|
+
## Architecture
|
|
156
|
+
|
|
157
|
+
### Plugin Initialization
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
wix-server-client (init first)
|
|
161
|
+
└── Registers WIX_CLIENT_SERVICE (API key auth)
|
|
162
|
+
|
|
163
|
+
wix-stores (init second)
|
|
164
|
+
├── Loads config/.wix-stores.yaml (category prefixes)
|
|
165
|
+
├── Registers WIX_STORES_SERVICE_MARKER (products, categories, inventory)
|
|
166
|
+
└── Client: Registers WIX_STORES_CONTEXT (delegates cart to wix-cart)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Category Prefix Resolution
|
|
170
|
+
|
|
171
|
+
When category prefixes are configured:
|
|
172
|
+
|
|
173
|
+
1. **`loadProductParams`** fetches all products with `ALL_CATEGORIES_INFO` and resolves each product's prefix
|
|
174
|
+
2. **`searchProducts`** includes `ALL_CATEGORIES_INFO` to generate correct prefixed URLs in results
|
|
175
|
+
3. **`mapProductToCard`** generates URLs like `/products/polgat/shirt-name` based on the product's category ancestry
|
|
176
|
+
4. **Product page** validates that the URL's category prefix matches the product's actual category
|
|
177
|
+
|
|
178
|
+
## Design Log
|
|
179
|
+
|
|
180
|
+
See [Design Log 10 - Category-Prefixed Product Routes](../../design-log/10%20-%20category-prefixed-product-routes.md) for the full design rationale.
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
Apache-2.0
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: searchProducts
|
|
2
|
+
description: Search products in the Wix Store catalog using Catalog V3. Supports text search, price/stock/category filtering, sorting, and cursor-based pagination. Returns matching products with price aggregation data.
|
|
3
|
+
|
|
4
|
+
import:
|
|
5
|
+
productCard: product-card.jay-contract
|
|
6
|
+
|
|
7
|
+
inputSchema:
|
|
8
|
+
query: string
|
|
9
|
+
filters?:
|
|
10
|
+
inStockOnly?: boolean
|
|
11
|
+
minPrice?: number
|
|
12
|
+
maxPrice?: number
|
|
13
|
+
categoryIds?: string[]
|
|
14
|
+
sortBy?: enum(relevance | price_asc | price_desc | name_asc | name_desc | newest)
|
|
15
|
+
cursor?: string
|
|
16
|
+
pageSize?: number
|
|
17
|
+
|
|
18
|
+
outputSchema:
|
|
19
|
+
products:
|
|
20
|
+
- productCard
|
|
21
|
+
totalCount: number
|
|
22
|
+
nextCursor?: string
|
|
23
|
+
hasMore: boolean
|
|
24
|
+
priceAggregation?:
|
|
25
|
+
minBound: number
|
|
26
|
+
maxBound: number
|
|
27
|
+
ranges:
|
|
28
|
+
- rangeId: string
|
|
29
|
+
label: string
|
|
30
|
+
minValue?: number
|
|
31
|
+
maxValue?: number
|
|
32
|
+
productCount: number
|
|
33
|
+
isSelected: boolean
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: category-list
|
|
2
|
+
tags:
|
|
3
|
+
# List of visible categories
|
|
4
|
+
- tag: categories
|
|
5
|
+
type: sub-contract
|
|
6
|
+
repeated: true
|
|
7
|
+
trackBy: _id
|
|
8
|
+
description: List of visible store categories
|
|
9
|
+
tags:
|
|
10
|
+
- tag: _id
|
|
11
|
+
type: data
|
|
12
|
+
dataType: string
|
|
13
|
+
description: Category GUID
|
|
14
|
+
|
|
15
|
+
- tag: name
|
|
16
|
+
type: data
|
|
17
|
+
dataType: string
|
|
18
|
+
required: true
|
|
19
|
+
description: Category name
|
|
20
|
+
|
|
21
|
+
- tag: slug
|
|
22
|
+
type: data
|
|
23
|
+
dataType: string
|
|
24
|
+
description: Category slug for URL
|
|
25
|
+
|
|
26
|
+
- tag: description
|
|
27
|
+
type: data
|
|
28
|
+
dataType: string
|
|
29
|
+
description: Category description
|
|
30
|
+
|
|
31
|
+
- tag: productCount
|
|
32
|
+
type: data
|
|
33
|
+
dataType: number
|
|
34
|
+
description: Number of products in category
|
|
35
|
+
|
|
36
|
+
- tag: imageUrl
|
|
37
|
+
type: data
|
|
38
|
+
dataType: string
|
|
39
|
+
description: Category image URL
|
|
40
|
+
|
|
41
|
+
- tag: categoryLink
|
|
42
|
+
type: interactive
|
|
43
|
+
elementType: HTMLAnchorElement
|
|
44
|
+
description: Link to category page
|
|
45
|
+
|
|
46
|
+
# Empty state
|
|
47
|
+
- tag: hasCategories
|
|
48
|
+
type: variant
|
|
49
|
+
dataType: boolean
|
|
50
|
+
description: Whether there are any categories
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {HTMLElementCollectionProxy, JayContract} from "@jay-framework/runtime";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export interface CategoryOfCategoryListViewState {
|
|
5
|
+
_id: string,
|
|
6
|
+
name: string,
|
|
7
|
+
slug: string,
|
|
8
|
+
description: string,
|
|
9
|
+
productCount: number,
|
|
10
|
+
imageUrl: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface CategoryListViewState {
|
|
14
|
+
categories: Array<CategoryOfCategoryListViewState>,
|
|
15
|
+
hasCategories: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type CategoryListSlowViewState = Pick<CategoryListViewState, 'hasCategories'> & {
|
|
19
|
+
categories: Array<CategoryListViewState['categories'][number]>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type CategoryListFastViewState = {};
|
|
23
|
+
|
|
24
|
+
export type CategoryListInteractiveViewState = {};
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
export interface CategoryListRefs {
|
|
28
|
+
categories: {
|
|
29
|
+
categoryLink: HTMLElementCollectionProxy<CategoryOfCategoryListViewState, HTMLAnchorElement>
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
export interface CategoryListRepeatedRefs {
|
|
35
|
+
categories: {
|
|
36
|
+
categoryLink: HTMLElementCollectionProxy<CategoryOfCategoryListViewState, HTMLAnchorElement>
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type CategoryListContract = JayContract<CategoryListViewState, CategoryListRefs, CategoryListSlowViewState, CategoryListFastViewState, CategoryListInteractiveViewState>
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
name: category-page
|
|
2
|
+
tags:
|
|
3
|
+
# Category/Collection information (from Wix Stores Collection API)
|
|
4
|
+
- tag: _id
|
|
5
|
+
type: data
|
|
6
|
+
dataType: string
|
|
7
|
+
description: Collection GUID
|
|
8
|
+
|
|
9
|
+
- tag: name
|
|
10
|
+
type: data
|
|
11
|
+
dataType: string
|
|
12
|
+
required: true
|
|
13
|
+
description: Collection name
|
|
14
|
+
|
|
15
|
+
- tag: description
|
|
16
|
+
type: data
|
|
17
|
+
dataType: string
|
|
18
|
+
description: Collection description
|
|
19
|
+
|
|
20
|
+
- tag: slug
|
|
21
|
+
type: data
|
|
22
|
+
dataType: string
|
|
23
|
+
description: Collection slug
|
|
24
|
+
|
|
25
|
+
- tag: visible
|
|
26
|
+
type: data
|
|
27
|
+
dataType: boolean
|
|
28
|
+
description: Collection visibility (impacts dynamic pages only)
|
|
29
|
+
|
|
30
|
+
- tag: numberOfProducts
|
|
31
|
+
type: data
|
|
32
|
+
dataType: number
|
|
33
|
+
description: Number of products in the collection
|
|
34
|
+
|
|
35
|
+
# Media (from Wix Stores Collection API)
|
|
36
|
+
- tag: media
|
|
37
|
+
type: sub-contract
|
|
38
|
+
description: Media items associated with this collection
|
|
39
|
+
tags:
|
|
40
|
+
- tag: mainMedia
|
|
41
|
+
type: sub-contract
|
|
42
|
+
description: Primary media for the collection
|
|
43
|
+
tags:
|
|
44
|
+
- tag: _id
|
|
45
|
+
type: data
|
|
46
|
+
dataType: string
|
|
47
|
+
description: Media GUID
|
|
48
|
+
|
|
49
|
+
- tag: url
|
|
50
|
+
type: data
|
|
51
|
+
dataType: string
|
|
52
|
+
description: Media URL
|
|
53
|
+
|
|
54
|
+
- tag: altText
|
|
55
|
+
type: data
|
|
56
|
+
dataType: string
|
|
57
|
+
description: Media alt text
|
|
58
|
+
|
|
59
|
+
- tag: mediaType
|
|
60
|
+
type: data
|
|
61
|
+
dataType: enum (IMAGE | VIDEO | AUDIO | DOCUMENT | ZIP)
|
|
62
|
+
description: Media item type
|
|
63
|
+
|
|
64
|
+
- tag: items
|
|
65
|
+
type: sub-contract
|
|
66
|
+
repeated: true
|
|
67
|
+
trackBy: _id
|
|
68
|
+
description: All media items
|
|
69
|
+
tags:
|
|
70
|
+
- tag: _id
|
|
71
|
+
type: data
|
|
72
|
+
dataType: string
|
|
73
|
+
description: Media GUID
|
|
74
|
+
|
|
75
|
+
- tag: url
|
|
76
|
+
type: data
|
|
77
|
+
dataType: string
|
|
78
|
+
description: Media URL
|
|
79
|
+
|
|
80
|
+
- tag: altText
|
|
81
|
+
type: data
|
|
82
|
+
dataType: string
|
|
83
|
+
description: Media alt text
|
|
84
|
+
|
|
85
|
+
- tag: title
|
|
86
|
+
type: data
|
|
87
|
+
dataType: string
|
|
88
|
+
description: Media item title
|
|
89
|
+
|
|
90
|
+
- tag: mediaType
|
|
91
|
+
type: data
|
|
92
|
+
dataType: enum (IMAGE | VIDEO | AUDIO | DOCUMENT | ZIP)
|
|
93
|
+
description: Media item type
|
|
94
|
+
|
|
95
|
+
- tag: thumbnail
|
|
96
|
+
type: sub-contract
|
|
97
|
+
description: Media thumbnail
|
|
98
|
+
tags:
|
|
99
|
+
- tag: url
|
|
100
|
+
type: data
|
|
101
|
+
dataType: string
|
|
102
|
+
description: Thumbnail URL
|
|
103
|
+
|
|
104
|
+
- tag: width
|
|
105
|
+
type: data
|
|
106
|
+
dataType: number
|
|
107
|
+
description: Thumbnail width in pixels
|
|
108
|
+
|
|
109
|
+
- tag: height
|
|
110
|
+
type: data
|
|
111
|
+
dataType: number
|
|
112
|
+
description: Thumbnail height in pixels
|
|
113
|
+
|
|
114
|
+
- tag: format
|
|
115
|
+
type: data
|
|
116
|
+
dataType: string
|
|
117
|
+
description: Media format (mp4, png, etc.)
|
|
118
|
+
|
|
119
|
+
# Breadcrumbs navigation
|
|
120
|
+
- tag: breadcrumbs
|
|
121
|
+
type: sub-contract
|
|
122
|
+
repeated: true
|
|
123
|
+
trackBy: categoryId
|
|
124
|
+
description: Breadcrumb navigation path
|
|
125
|
+
tags:
|
|
126
|
+
- tag: categoryId
|
|
127
|
+
type: data
|
|
128
|
+
dataType: string
|
|
129
|
+
description: Category GUID
|
|
130
|
+
|
|
131
|
+
- tag: categoryName
|
|
132
|
+
type: data
|
|
133
|
+
dataType: string
|
|
134
|
+
description: Category name in breadcrumb
|
|
135
|
+
|
|
136
|
+
- tag: categorySlug
|
|
137
|
+
type: data
|
|
138
|
+
dataType: string
|
|
139
|
+
description: Category slug for link
|
|
140
|
+
|
|
141
|
+
- tag: categoryLink
|
|
142
|
+
type: interactive
|
|
143
|
+
elementType: HTMLAnchorElement
|
|
144
|
+
description: Link to category
|
|
145
|
+
|
|
146
|
+
# Initial products (SSR - loaded in slow phase)
|
|
147
|
+
- tag: products
|
|
148
|
+
type: sub-contract
|
|
149
|
+
repeated: true
|
|
150
|
+
trackBy: _id
|
|
151
|
+
description: Initial products in this category (rendered server-side)
|
|
152
|
+
link: ./product-card
|
|
153
|
+
|
|
154
|
+
# Additional products (loaded on client via "load more")
|
|
155
|
+
- tag: loadedProducts
|
|
156
|
+
type: sub-contract
|
|
157
|
+
repeated: true
|
|
158
|
+
trackBy: _id
|
|
159
|
+
phase: fast+interactive
|
|
160
|
+
description: Additional products loaded on the client
|
|
161
|
+
link: ./product-card
|
|
162
|
+
|
|
163
|
+
# Load more functionality
|
|
164
|
+
- tag: hasMore
|
|
165
|
+
type: variant
|
|
166
|
+
dataType: boolean
|
|
167
|
+
phase: fast+interactive
|
|
168
|
+
description: Whether there are more products to load
|
|
169
|
+
|
|
170
|
+
- tag: loadMoreButton
|
|
171
|
+
type: interactive
|
|
172
|
+
elementType: HTMLButtonElement
|
|
173
|
+
description: Button to load more products
|
|
174
|
+
|
|
175
|
+
- tag: loadedCount
|
|
176
|
+
type: data
|
|
177
|
+
dataType: number
|
|
178
|
+
phase: fast+interactive
|
|
179
|
+
description: Number of products currently loaded
|
|
180
|
+
|
|
181
|
+
# Loading state
|
|
182
|
+
- tag: isLoading
|
|
183
|
+
type: variant
|
|
184
|
+
dataType: boolean
|
|
185
|
+
phase: fast+interactive
|
|
186
|
+
description: Whether products are currently loading
|
|
187
|
+
|
|
188
|
+
# Empty state
|
|
189
|
+
- tag: hasProducts
|
|
190
|
+
type: variant
|
|
191
|
+
dataType: boolean
|
|
192
|
+
phase: fast+interactive
|
|
193
|
+
description: Whether category has any products
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import {HTMLElementCollectionProxy, HTMLElementProxy, JayContract} from "@jay-framework/runtime";
|
|
2
|
+
import {ProductCardViewState, ProductCardRefs, ProductCardRepeatedRefs} from "./product-card.jay-contract";
|
|
3
|
+
|
|
4
|
+
export enum MediaType {
|
|
5
|
+
IMAGE,
|
|
6
|
+
VIDEO,
|
|
7
|
+
AUDIO,
|
|
8
|
+
DOCUMENT,
|
|
9
|
+
ZIP
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface MainMediaOfMediaOfCategoryPageViewState {
|
|
13
|
+
_id: string,
|
|
14
|
+
url: string,
|
|
15
|
+
altText: string,
|
|
16
|
+
mediaType: MediaType
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export enum MediaType {
|
|
20
|
+
IMAGE,
|
|
21
|
+
VIDEO,
|
|
22
|
+
AUDIO,
|
|
23
|
+
DOCUMENT,
|
|
24
|
+
ZIP
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ThumbnailOfItemOfMediaOfCategoryPageViewState {
|
|
28
|
+
url: string,
|
|
29
|
+
width: number,
|
|
30
|
+
height: number,
|
|
31
|
+
format: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ItemOfMediaOfCategoryPageViewState {
|
|
35
|
+
_id: string,
|
|
36
|
+
url: string,
|
|
37
|
+
altText: string,
|
|
38
|
+
title: string,
|
|
39
|
+
mediaType: MediaType,
|
|
40
|
+
thumbnail: ThumbnailOfItemOfMediaOfCategoryPageViewState
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface MediaOfCategoryPageViewState {
|
|
44
|
+
mainMedia: MainMediaOfMediaOfCategoryPageViewState,
|
|
45
|
+
items: Array<ItemOfMediaOfCategoryPageViewState>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface BreadcrumbOfCategoryPageViewState {
|
|
49
|
+
categoryId: string,
|
|
50
|
+
categoryName: string,
|
|
51
|
+
categorySlug: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface CategoryPageViewState {
|
|
55
|
+
_id: string,
|
|
56
|
+
name: string,
|
|
57
|
+
description: string,
|
|
58
|
+
slug: string,
|
|
59
|
+
visible: boolean,
|
|
60
|
+
numberOfProducts: number,
|
|
61
|
+
media: MediaOfCategoryPageViewState,
|
|
62
|
+
breadcrumbs: Array<BreadcrumbOfCategoryPageViewState>,
|
|
63
|
+
products: Array<ProductCardViewState>,
|
|
64
|
+
loadedProducts: Array<ProductCardViewState>,
|
|
65
|
+
hasMore: boolean,
|
|
66
|
+
loadedCount: number,
|
|
67
|
+
isLoading: boolean,
|
|
68
|
+
hasProducts: boolean
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type CategoryPageSlowViewState = Pick<CategoryPageViewState, '_id' | 'name' | 'description' | 'slug' | 'visible' | 'numberOfProducts'> & {
|
|
72
|
+
media: CategoryPageViewState['media'];
|
|
73
|
+
breadcrumbs: Array<CategoryPageViewState['breadcrumbs'][number]>;
|
|
74
|
+
products: Array<Pick<CategoryPageViewState['products'][number], '_id' | 'name' | 'slug' | 'productUrl' | 'categoryPrefix' | 'hasDiscount' | 'hasRibbon' | 'productType' | 'quickAddType'> & {
|
|
75
|
+
mainMedia: CategoryPageViewState['products'][number]['mainMedia'];
|
|
76
|
+
thumbnail: CategoryPageViewState['products'][number]['thumbnail'];
|
|
77
|
+
inventory: CategoryPageViewState['products'][number]['inventory'];
|
|
78
|
+
ribbon: CategoryPageViewState['products'][number]['ribbon'];
|
|
79
|
+
brand: CategoryPageViewState['products'][number]['brand'];
|
|
80
|
+
quickOption: Pick<CategoryPageViewState['products'][number]['quickOption'], '_id' | 'name' | 'optionRenderType'> & {
|
|
81
|
+
choices: Array<Pick<CategoryPageViewState['products'][number]['quickOption']['choices'][number], 'choiceId' | 'name' | 'choiceType' | 'colorCode' | 'variantId'>>;
|
|
82
|
+
};
|
|
83
|
+
}>;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export type CategoryPageFastViewState = Pick<CategoryPageViewState, 'hasMore' | 'loadedCount' | 'isLoading' | 'hasProducts'> & {
|
|
87
|
+
products: Array<Pick<CategoryPageViewState['products'][number], '_id' | 'price' | 'strikethroughPrice' | 'isAddingToCart'> & {
|
|
88
|
+
quickOption: {
|
|
89
|
+
choices: Array<Pick<CategoryPageViewState['products'][number]['quickOption']['choices'][number], 'choiceId' | 'inStock' | 'isSelected'>>;
|
|
90
|
+
};
|
|
91
|
+
}>;
|
|
92
|
+
loadedProducts: Array<CategoryPageViewState['loadedProducts'][number]>;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export type CategoryPageInteractiveViewState = Pick<CategoryPageViewState, 'hasMore' | 'loadedCount' | 'isLoading' | 'hasProducts'> & {
|
|
96
|
+
products: Array<Pick<CategoryPageViewState['products'][number], '_id' | 'price' | 'strikethroughPrice' | 'isAddingToCart'> & {
|
|
97
|
+
quickOption: {
|
|
98
|
+
choices: Array<Pick<CategoryPageViewState['products'][number]['quickOption']['choices'][number], 'choiceId' | 'inStock' | 'isSelected'>>;
|
|
99
|
+
};
|
|
100
|
+
}>;
|
|
101
|
+
loadedProducts: Array<CategoryPageViewState['loadedProducts'][number]>;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
export interface CategoryPageRefs {
|
|
106
|
+
loadMoreButton: HTMLElementProxy<CategoryPageViewState, HTMLButtonElement>,
|
|
107
|
+
breadcrumbs: {
|
|
108
|
+
categoryLink: HTMLElementCollectionProxy<BreadcrumbOfCategoryPageViewState, HTMLAnchorElement>
|
|
109
|
+
},
|
|
110
|
+
products: ProductCardRepeatedRefs,
|
|
111
|
+
loadedProducts: ProductCardRepeatedRefs
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
export interface CategoryPageRepeatedRefs {
|
|
116
|
+
loadMoreButton: HTMLElementCollectionProxy<CategoryPageViewState, HTMLButtonElement>,
|
|
117
|
+
breadcrumbs: {
|
|
118
|
+
categoryLink: HTMLElementCollectionProxy<BreadcrumbOfCategoryPageViewState, HTMLAnchorElement>
|
|
119
|
+
},
|
|
120
|
+
products: ProductCardRepeatedRefs,
|
|
121
|
+
loadedProducts: ProductCardRepeatedRefs
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export type CategoryPageContract = JayContract<CategoryPageViewState, CategoryPageRefs, CategoryPageSlowViewState, CategoryPageFastViewState, CategoryPageInteractiveViewState>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: mediaGallery
|
|
2
|
+
tags:
|
|
3
|
+
- tag: selectedMedia
|
|
4
|
+
type: sub-contract
|
|
5
|
+
description: Selected Media (image, video) to display with selection based galleries
|
|
6
|
+
link: ./media
|
|
7
|
+
|
|
8
|
+
- tag: availableMedia
|
|
9
|
+
type: sub-contract
|
|
10
|
+
repeated: true
|
|
11
|
+
trackBy: mediaId
|
|
12
|
+
description: Available media for display or use as thumbnails
|
|
13
|
+
tags:
|
|
14
|
+
- tag: mediaId
|
|
15
|
+
type: data
|
|
16
|
+
- tag: media
|
|
17
|
+
type: sub-contract
|
|
18
|
+
link: ./media
|
|
19
|
+
- tag: selected
|
|
20
|
+
type: [variant, interactive]
|
|
21
|
+
dataType: enum(selected | notSelected)
|
|
22
|
+
elementType: HTMLImageElement | HTMLDivElement
|