@hanzo/commerce 2.1.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/add-to-cart-widget.tsx +3 -3
- package/components/buy-item/buy-item-button.tsx +28 -0
- package/components/buy-item/buy-item-card.tsx +82 -0
- package/components/buy-item/buy-item-popup.tsx +38 -0
- package/components/{select-category-and-item-widget.tsx → buy-item/select-category-and-item-widget.tsx} +4 -4
- package/components/buy-item/select-category-item-card.tsx +111 -0
- package/components/{cart-line-item.tsx → cart-panel/cart-line-item.tsx} +4 -3
- package/components/{cart.tsx → cart-panel/index.tsx} +24 -18
- package/components/category-item-ios-wheel-selector.tsx +60 -0
- package/components/category-item-radio-selector.tsx +55 -0
- package/components/{checkout → checkout-panel}/confirm-order.tsx +3 -2
- package/components/{checkout → checkout-panel}/index.tsx +10 -5
- package/components/{checkout → checkout-panel}/payment/index.tsx +2 -1
- package/components/{checkout → checkout-panel}/payment/pay-with-card.tsx +8 -3
- package/components/{checkout → checkout-panel}/payment/pay-with-crypto.tsx +2 -3
- package/components/{facet-toggles-widget → facet-values-widget}/facet-image.tsx +7 -3
- package/components/{facet-toggles-widget → facet-values-widget}/index.tsx +7 -5
- package/components/index.ts +11 -9
- package/components/{select-item-in-category-view.tsx → select-category-item-panel.tsx} +72 -76
- package/index.ts +2 -2
- package/package.json +8 -3
- package/service/context.tsx +4 -4
- package/service/impls/standalone/index.ts +4 -4
- package/service/impls/standalone/standalone-service.ts +117 -38
- package/types/category.ts +3 -2
- package/types/commerce-service.ts +17 -4
- package/types/facet.ts +1 -3
- package/types/index.ts +3 -1
- package/types/item-selector.ts +14 -0
- package/util/index.ts +29 -0
- package/util/use-sync-sku-param-w-current-item.ts +4 -1
- package/blocks/components/commerce-cat-and-item-block.tsx +0 -13
- package/blocks/def/commerce-cat-and-item-block.ts +0 -9
- package/components/facets-widget.tsx +0 -55
- package/components/product-selection-mobile-picker.tsx +0 -78
- package/components/product-selection-radio-group.tsx +0 -38
- /package/components/{checkout → checkout-panel}/countries.ts +0 -0
- /package/components/{checkout → checkout-panel}/icons/btc.tsx +0 -0
- /package/components/{checkout → checkout-panel}/icons/eth.tsx +0 -0
- /package/components/{checkout → checkout-panel}/icons/usdt.tsx +0 -0
- /package/components/{checkout → checkout-panel}/payment/contact-info.tsx +0 -0
- /package/components/{checkout → checkout-panel}/payment/pay-with-bank-transfer.tsx +0 -0
- /package/components/{checkout → checkout-panel}/payment/payment-methods/amex.tsx +0 -0
- /package/components/{checkout → checkout-panel}/payment/payment-methods/diners-club.tsx +0 -0
- /package/components/{checkout → checkout-panel}/payment/payment-methods/discover.tsx +0 -0
- /package/components/{checkout → checkout-panel}/payment/payment-methods/index.tsx +0 -0
- /package/components/{checkout → checkout-panel}/payment/payment-methods/jcb.tsx +0 -0
- /package/components/{checkout → checkout-panel}/payment/payment-methods/mastercard.tsx +0 -0
- /package/components/{checkout → checkout-panel}/payment/payment-methods/visa.tsx +0 -0
- /package/components/{checkout → checkout-panel}/shipping-info.tsx +0 -0
- /package/components/{checkout → checkout-panel}/thank-you.tsx +0 -0
|
@@ -7,12 +7,14 @@ import {
|
|
|
7
7
|
toJS
|
|
8
8
|
} from 'mobx'
|
|
9
9
|
|
|
10
|
+
import { computedFn } from 'mobx-utils'
|
|
11
|
+
|
|
10
12
|
import type {
|
|
11
13
|
CommerceService,
|
|
12
14
|
Category,
|
|
13
15
|
LineItem,
|
|
14
16
|
FacetsValue,
|
|
15
|
-
|
|
17
|
+
FacetValueDesc
|
|
16
18
|
} from '../../../types'
|
|
17
19
|
|
|
18
20
|
import {
|
|
@@ -23,6 +25,8 @@ import {
|
|
|
23
25
|
|
|
24
26
|
import ActualLineItem, { type ActualLineItemSnapshot } from './actual-line-item'
|
|
25
27
|
|
|
28
|
+
const SEP = '-'
|
|
29
|
+
|
|
26
30
|
type StandaloneServiceOptions = {
|
|
27
31
|
levelZeroPrefix?: string
|
|
28
32
|
dbName: string
|
|
@@ -37,7 +41,7 @@ class StandaloneService
|
|
|
37
41
|
implements CommerceService
|
|
38
42
|
{
|
|
39
43
|
private _categoryMap = new Map<string, Category>()
|
|
40
|
-
private
|
|
44
|
+
private _rootFacet: FacetValueDesc
|
|
41
45
|
private _selectedFacets: FacetsValue = {}
|
|
42
46
|
|
|
43
47
|
private _options : StandaloneServiceOptions
|
|
@@ -45,12 +49,12 @@ class StandaloneService
|
|
|
45
49
|
|
|
46
50
|
constructor(
|
|
47
51
|
categories: Category[],
|
|
48
|
-
|
|
52
|
+
rootFacet: FacetValueDesc,
|
|
49
53
|
options: StandaloneServiceOptions,
|
|
50
54
|
serviceSnapshot?: StandaloneServiceSnapshot,
|
|
51
55
|
) {
|
|
52
56
|
|
|
53
|
-
this.
|
|
57
|
+
this._rootFacet = rootFacet
|
|
54
58
|
this._options = options
|
|
55
59
|
|
|
56
60
|
categories.forEach((c) => {
|
|
@@ -79,6 +83,7 @@ class StandaloneService
|
|
|
79
83
|
cartItems: computed,
|
|
80
84
|
cartQuantity: computed,
|
|
81
85
|
cartTotal: computed,
|
|
86
|
+
cartEmpty: computed,
|
|
82
87
|
specifiedItems: computed,
|
|
83
88
|
specifiedCategories: computed,
|
|
84
89
|
setCurrentItem: action,
|
|
@@ -89,6 +94,54 @@ class StandaloneService
|
|
|
89
94
|
})
|
|
90
95
|
}
|
|
91
96
|
|
|
97
|
+
|
|
98
|
+
getCategory(id: string): Category | undefined {
|
|
99
|
+
return this._categoryMap.get(id)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
getFacetValuesAtSkuPath(skuPath: string): FacetValueDesc[] | undefined {
|
|
103
|
+
const toks = skuPath.split(SEP)
|
|
104
|
+
let level = 1
|
|
105
|
+
let valuesAtLevel: FacetValueDesc[] | undefined = this._rootFacet.sub
|
|
106
|
+
do {
|
|
107
|
+
const fvalue = valuesAtLevel!.find((vf) => (vf.value === toks[level]))
|
|
108
|
+
valuesAtLevel = fvalue ? fvalue.sub : undefined
|
|
109
|
+
level++
|
|
110
|
+
}
|
|
111
|
+
while (valuesAtLevel && (level < toks.length))
|
|
112
|
+
return level === toks.length ? valuesAtLevel : undefined
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
getFacetValuesSpecified = computedFn((level: number): FacetValueDesc[] | undefined => {
|
|
116
|
+
|
|
117
|
+
let lvl = 1
|
|
118
|
+
let valuesAtLevel: FacetValueDesc[] | undefined = this._rootFacet.sub
|
|
119
|
+
|
|
120
|
+
do {
|
|
121
|
+
let selectedAtLevel: FacetValueDesc[] | undefined = undefined
|
|
122
|
+
// If not specified, assume all
|
|
123
|
+
if (lvl in this._selectedFacets) {
|
|
124
|
+
selectedAtLevel = valuesAtLevel!.filter((fv) => (this._selectedFacets[lvl].includes(fv.value)))
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
selectedAtLevel = valuesAtLevel
|
|
128
|
+
}
|
|
129
|
+
let allSubsOfSelected: FacetValueDesc[] = []
|
|
130
|
+
selectedAtLevel?.forEach((fvd: FacetValueDesc) => {
|
|
131
|
+
if (fvd.sub) {
|
|
132
|
+
allSubsOfSelected = [...allSubsOfSelected, ...fvd.sub]
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
valuesAtLevel = allSubsOfSelected
|
|
137
|
+
lvl++
|
|
138
|
+
} while (valuesAtLevel.length > 0 && lvl <= level)
|
|
139
|
+
|
|
140
|
+
return (valuesAtLevel.length > 0 && ((lvl - 1) === level)) ? valuesAtLevel : undefined
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
//async createOrder(email: string, paymentMethod: string): Promise<string | undefined> {
|
|
92
145
|
async createOrder(email: string, name?: string): Promise<string | undefined> {
|
|
93
146
|
const snapshot = this.takeSnapshot()
|
|
94
147
|
const order = await createOrderHelper(email, snapshot.items, this._options, name) // didn't want to have two levels of 'items'
|
|
@@ -117,6 +170,10 @@ class StandaloneService
|
|
|
117
170
|
return result.sort((it1, it2) => ((it1 as ActualLineItem).timeAdded - (it2 as ActualLineItem).timeAdded))
|
|
118
171
|
}
|
|
119
172
|
|
|
173
|
+
get cartEmpty(): boolean {
|
|
174
|
+
return this.cartItems.length === 0
|
|
175
|
+
}
|
|
176
|
+
|
|
120
177
|
get cartTotal(): number {
|
|
121
178
|
return this.cartItems.reduce(
|
|
122
179
|
(total, item) => (total + item.price * item.quantity),
|
|
@@ -163,7 +220,6 @@ class StandaloneService
|
|
|
163
220
|
return !!this._currentItem
|
|
164
221
|
}
|
|
165
222
|
|
|
166
|
-
|
|
167
223
|
/* ObsLineItemRef */
|
|
168
224
|
get item(): LineItem | undefined {
|
|
169
225
|
return this._currentItem
|
|
@@ -175,10 +231,7 @@ class StandaloneService
|
|
|
175
231
|
|
|
176
232
|
setFacets(sel: FacetsValue): Category[] {
|
|
177
233
|
runInAction (() => {
|
|
178
|
-
|
|
179
|
-
if (res) {
|
|
180
|
-
this._selectedFacets = res
|
|
181
|
-
}
|
|
234
|
+
this._selectedFacets = this._processAndValidate(sel)
|
|
182
235
|
})
|
|
183
236
|
return this.specifiedCategories
|
|
184
237
|
}
|
|
@@ -191,46 +244,72 @@ class StandaloneService
|
|
|
191
244
|
return result
|
|
192
245
|
}
|
|
193
246
|
|
|
247
|
+
|
|
194
248
|
get specifiedCategories(): Category[] {
|
|
195
249
|
if (Object.keys(toJS(this._selectedFacets)).length === 0) {
|
|
196
250
|
// FacetsDesc have never been set or unset, so cannot evaluate them
|
|
197
251
|
return []
|
|
198
252
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
253
|
+
|
|
254
|
+
return this._rootFacet.sub!.reduce(
|
|
255
|
+
(acc: Category[], subFacet: FacetValueDesc) => (
|
|
256
|
+
// Pass the root token as a one member array
|
|
257
|
+
this._reduceNode([this._rootFacet.value], acc, subFacet)
|
|
258
|
+
),
|
|
259
|
+
[]
|
|
260
|
+
)
|
|
207
261
|
}
|
|
208
262
|
|
|
209
|
-
private
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
263
|
+
private _reduceNode(parentPath: string[], acc: Category[], node: FacetValueDesc): Category[] {
|
|
264
|
+
const path = [...parentPath, node.value] // Don't mutate original please :)
|
|
265
|
+
const level = path.length - 1
|
|
266
|
+
// If there is no token array supplied for this level,
|
|
267
|
+
// assume all are specified. Otherwise, see if the
|
|
268
|
+
// current node is in the array
|
|
269
|
+
const specified = (
|
|
270
|
+
!this._selectedFacets[level]
|
|
271
|
+
||
|
|
272
|
+
this._selectedFacets[level].includes(node.value)
|
|
273
|
+
)
|
|
274
|
+
if (specified) {
|
|
275
|
+
// Process subnodes
|
|
276
|
+
if (node.sub && node.sub.length > 0) {
|
|
277
|
+
return node.sub.reduce((acc, n) => (
|
|
278
|
+
this._reduceNode(path, acc, n)
|
|
279
|
+
)
|
|
280
|
+
, acc)
|
|
281
|
+
}
|
|
282
|
+
// Process leaf
|
|
283
|
+
const cat = this._categoryMap.get(path.join(SEP))
|
|
284
|
+
if (!cat) {
|
|
285
|
+
throw new Error("specifiedCategories WTF?!" + path.join(SEP))
|
|
286
|
+
}
|
|
287
|
+
acc.push(cat)
|
|
288
|
+
}
|
|
289
|
+
return acc
|
|
217
290
|
}
|
|
218
291
|
|
|
219
|
-
private _processAndValidate(partial: FacetsValue): FacetsValue
|
|
292
|
+
private _processAndValidate(partial: FacetsValue): FacetsValue {
|
|
293
|
+
|
|
220
294
|
const result: FacetsValue = {}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
else {
|
|
231
|
-
result[key] = this._facetsDesc[key].map((fv) => (fv.value))
|
|
295
|
+
|
|
296
|
+
let level = 1
|
|
297
|
+
let currentSet = this._rootFacet.sub!
|
|
298
|
+
|
|
299
|
+
while (true) {
|
|
300
|
+
let possibleCurrent = currentSet.map((el) => (el.value))
|
|
301
|
+
const validTokens = !partial[level] ? undefined : partial[level].filter((tok) => possibleCurrent.includes(tok))
|
|
302
|
+
if (!validTokens) {
|
|
303
|
+
break
|
|
232
304
|
}
|
|
233
|
-
|
|
305
|
+
result[level] = validTokens
|
|
306
|
+
currentSet = validTokens.map((tok) => {
|
|
307
|
+
const fd = currentSet.find((node) => ( node.value === tok ))
|
|
308
|
+
return (fd && fd.sub && fd.sub.length > 0) ? fd.sub : []
|
|
309
|
+
}).flat()
|
|
310
|
+
level++
|
|
311
|
+
}
|
|
312
|
+
|
|
234
313
|
return result
|
|
235
314
|
}
|
|
236
315
|
|
package/types/category.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type Product from './product'
|
|
2
2
|
|
|
3
3
|
interface Category {
|
|
4
|
-
id: string
|
|
5
|
-
title: string
|
|
4
|
+
id: string // LXB-AU-B
|
|
5
|
+
title: string // Minted Bar
|
|
6
|
+
parentTitle?: string // Lux Gold
|
|
6
7
|
desc?: string
|
|
7
8
|
img?: string
|
|
8
9
|
// inbound they're Products and then interally they become LineItems
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import type { LineItem, ObsLineItemRef } from './line-item'
|
|
2
|
-
import type { FacetsValue } from './facet'
|
|
2
|
+
import type { FacetValueDesc, FacetsValue } from './facet'
|
|
3
3
|
import type Category from './category'
|
|
4
4
|
|
|
5
5
|
interface CommerceService extends ObsLineItemRef {
|
|
6
6
|
|
|
7
7
|
/** Items in cart */
|
|
8
8
|
get cartItems(): LineItem[]
|
|
9
|
-
/** Total of all quantities of items in cart */
|
|
9
|
+
/** Total of all quantities of all items in cart */
|
|
10
10
|
get cartQuantity(): number
|
|
11
|
-
/** Total of all prices
|
|
11
|
+
/** Total of all prices * quantities of items in cart */
|
|
12
12
|
get cartTotal(): number
|
|
13
|
+
|
|
14
|
+
get cartEmpty(): boolean
|
|
13
15
|
|
|
14
16
|
getCartCategorySubtotal(categoryId: string): number
|
|
15
17
|
|
|
@@ -31,7 +33,16 @@ interface CommerceService extends ObsLineItemRef {
|
|
|
31
33
|
get specifiedItems(): LineItem[]
|
|
32
34
|
get specifiedCategories(): Category[]
|
|
33
35
|
|
|
34
|
-
/**
|
|
36
|
+
/** Whether this path defines a Category, or if it has further levels */
|
|
37
|
+
getFacetValuesAtSkuPath(skuPath: string): FacetValueDesc[] | undefined
|
|
38
|
+
|
|
39
|
+
/** Based on current value of 'level', what are the available subfacets?
|
|
40
|
+
* If more than one value is specified at 'level' returned FacetValueDesc[]
|
|
41
|
+
* may represent multiple sets.
|
|
42
|
+
* */
|
|
43
|
+
getFacetValuesSpecified(level: number): FacetValueDesc[] | undefined
|
|
44
|
+
|
|
45
|
+
/**
|
|
35
46
|
* For convenience, so widgets can share state.
|
|
36
47
|
* "current" is unrelated to what is "specified",
|
|
37
48
|
* ie, facets' values
|
|
@@ -48,6 +59,8 @@ interface CommerceService extends ObsLineItemRef {
|
|
|
48
59
|
* */
|
|
49
60
|
get currentItem(): LineItem | undefined
|
|
50
61
|
|
|
62
|
+
getCategory(id: string): Category | undefined
|
|
63
|
+
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
export {
|
package/types/facet.ts
CHANGED
|
@@ -5,6 +5,7 @@ interface FacetValueDesc {
|
|
|
5
5
|
label: string
|
|
6
6
|
img? : string | ReactNode // icon is required
|
|
7
7
|
imgAR? : number // helps with svgs
|
|
8
|
+
sub?: FacetValueDesc[]
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
/* *** FOR EXAMPLE **
|
|
@@ -25,13 +26,10 @@ interface FacetValueDesc {
|
|
|
25
26
|
]
|
|
26
27
|
}
|
|
27
28
|
*/
|
|
28
|
-
type FacetsDesc = Record<number, FacetValueDesc[]>
|
|
29
|
-
|
|
30
29
|
// Which facets tokens are on at each level
|
|
31
30
|
type FacetsValue = Record<number, string[]>
|
|
32
31
|
|
|
33
32
|
export type {
|
|
34
33
|
FacetValueDesc,
|
|
35
|
-
FacetsDesc,
|
|
36
34
|
FacetsValue
|
|
37
35
|
}
|
package/types/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
|
|
2
|
+
export type { default as Category } from './category'
|
|
2
3
|
export type { default as CommerceService } from './commerce-service'
|
|
4
|
+
export type { default as ItemSelector } from './item-selector'
|
|
3
5
|
export type { default as Product } from './product'
|
|
4
|
-
|
|
6
|
+
|
|
5
7
|
export type { default as TransactionStatus } from './checkout'
|
|
6
8
|
export * from './line-item'
|
|
7
9
|
export * from './facet'
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type Category from './category'
|
|
2
|
+
import type { ObsLineItemRef } from './line-item'
|
|
3
|
+
|
|
4
|
+
interface ItemSelector {
|
|
5
|
+
category: Category
|
|
6
|
+
selectedItemRef: ObsLineItemRef
|
|
7
|
+
selectSku: (sku: string) => void
|
|
8
|
+
showPrice?: boolean // true by default
|
|
9
|
+
showQuantity?: boolean // true by default (not impl)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
type ItemSelector as default
|
|
14
|
+
}
|
package/util/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { StringMutator, CommerceService } from '../types'
|
|
1
2
|
|
|
2
3
|
export function toTitleCase(str: string) {
|
|
3
4
|
return str.replace(
|
|
@@ -27,6 +28,34 @@ export function formatPrice(price: number): string {
|
|
|
27
28
|
return (str.endsWith('.00')) ? str.replace('.00', '') : str
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
export const getFacetValuesMutator = (level: number, cmmc: CommerceService): StringMutator => {
|
|
32
|
+
|
|
33
|
+
const setLevel = (value: string, level: number ): void => {
|
|
34
|
+
const facets = cmmc.facetsValue
|
|
35
|
+
facets[level] = [value]
|
|
36
|
+
cmmc.setFacets(facets)
|
|
37
|
+
const subFacets = cmmc.getFacetValuesSpecified(level)
|
|
38
|
+
if (subFacets) {
|
|
39
|
+
const facets = cmmc.facetsValue
|
|
40
|
+
facets[level + 1] = [subFacets[0].value]
|
|
41
|
+
cmmc.setFacets(facets)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const getLevelValueSafe = (level: number): string | null => {
|
|
46
|
+
const facets = cmmc.facetsValue
|
|
47
|
+
if (!(level in facets) || facets[level].length === 0 ) {
|
|
48
|
+
return null
|
|
49
|
+
}
|
|
50
|
+
return facets[level][0]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
get: () => (getLevelValueSafe(level)),
|
|
55
|
+
set: (v: string) => {setLevel(v, level)}
|
|
56
|
+
} satisfies StringMutator
|
|
57
|
+
}
|
|
58
|
+
|
|
30
59
|
|
|
31
60
|
export { default as useSyncSkuParamWithCurrentItem } from './use-sync-sku-param-w-current-item'
|
|
32
61
|
export { default as processSquareCardPayment } from './square-payment'
|
|
@@ -56,8 +56,11 @@ const useSyncSkuParamWithCurrentItem = (
|
|
|
56
56
|
const setCurrentCategoryFromSku = (sku: string) => {
|
|
57
57
|
const toks: string[] = sku.split('-')
|
|
58
58
|
const fv: FacetsValue = {}
|
|
59
|
+
// TODO: confirm that extra trailing nonsense tokens won't break setFacets()
|
|
59
60
|
for (let i = 1; i < categoryLevel; i++) {
|
|
60
|
-
|
|
61
|
+
if (i in toks) {
|
|
62
|
+
fv[i] = [toks[i]]
|
|
63
|
+
}
|
|
61
64
|
}
|
|
62
65
|
cmmc.setFacets(fv)
|
|
63
66
|
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import type CommerceCatAndItemBlock from '../def/commerce-cat-and-item-block'
|
|
3
|
-
|
|
4
|
-
/*
|
|
5
|
-
|
|
6
|
-
interface CommerceCatAndItemBlock extends Block {
|
|
7
|
-
blockType: 'commerce-cat-and-item'
|
|
8
|
-
parentPath: string // SKU path of parent of Category ... eg, in Market, LXB-AU or LXB-AG. Next level is Cat.
|
|
9
|
-
defaultCatPath?: string // SKU path of default Category... eg, in Market, LXB-AU-B (Minted Bar)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
*/
|
|
13
|
-
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Block } from '@hanzo/ui/blocks'
|
|
2
|
-
|
|
3
|
-
interface CommerceCatAndItemBlock extends Block {
|
|
4
|
-
blockType: 'commerce-cat-and-item'
|
|
5
|
-
parentPath: string // SKU path of parent of Category ... eg, in Market, LXB-AU or LXB-AG. Next level is Cat.
|
|
6
|
-
defaultCatPath?: string // SKU path of default Category... eg, in Market, LXB-AU-B (Minted Bar)
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export { type CommerceCatAndItemBlock as default }
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
import React, { type PropsWithChildren } from 'react'
|
|
3
|
-
|
|
4
|
-
import { cn } from '@hanzo/ui/util'
|
|
5
|
-
|
|
6
|
-
import type { FacetsDesc, StringMutator, StringArrayMutator } from '../types'
|
|
7
|
-
|
|
8
|
-
import FacetTogglesWidget from './facet-toggles-widget'
|
|
9
|
-
|
|
10
|
-
const FacetsWidget: React.FC<PropsWithChildren & {
|
|
11
|
-
facets: FacetsDesc
|
|
12
|
-
mutators: StringMutator[] | StringArrayMutator[]
|
|
13
|
-
facetClx?: string[]
|
|
14
|
-
facetItemClx?: string
|
|
15
|
-
multiple?: boolean
|
|
16
|
-
isMobile?: boolean
|
|
17
|
-
id?: string
|
|
18
|
-
className?: string
|
|
19
|
-
tabSize?: string
|
|
20
|
-
childrenAfter?: boolean
|
|
21
|
-
}> = ({
|
|
22
|
-
children,
|
|
23
|
-
facets,
|
|
24
|
-
mutators,
|
|
25
|
-
multiple=false,
|
|
26
|
-
facetClx,
|
|
27
|
-
facetItemClx='',
|
|
28
|
-
isMobile=false,
|
|
29
|
-
className='',
|
|
30
|
-
tabSize,
|
|
31
|
-
id='FacetsWidget',
|
|
32
|
-
childrenAfter=true
|
|
33
|
-
}) => {
|
|
34
|
-
const horiz = className.includes('flex-row')
|
|
35
|
-
return (
|
|
36
|
-
<div id={id} className={className} >
|
|
37
|
-
{!childrenAfter && children}
|
|
38
|
-
{Object.keys(facets).map((key, i) => (
|
|
39
|
-
<FacetTogglesWidget
|
|
40
|
-
key={i}
|
|
41
|
-
multiple={multiple}
|
|
42
|
-
mutator={mutators[i]}
|
|
43
|
-
isMobile={isMobile}
|
|
44
|
-
facetValues={facets[parseInt(key)]}
|
|
45
|
-
className={cn((horiz ? '' : 'mb-2'), (i !== 0 && !horiz) ? 'mt-2' : '', (facetClx?.[i]) ?? '')}
|
|
46
|
-
buttonClx={facetItemClx}
|
|
47
|
-
tabSize={tabSize}
|
|
48
|
-
/>
|
|
49
|
-
))}
|
|
50
|
-
{childrenAfter && children}
|
|
51
|
-
</div>
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export default FacetsWidget
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react'
|
|
2
|
-
import Picker from 'react-mobile-picker'
|
|
3
|
-
|
|
4
|
-
import type { Product } from '../types'
|
|
5
|
-
import { formatPrice } from '../util'
|
|
6
|
-
import { cn } from '@hanzo/ui/util'
|
|
7
|
-
|
|
8
|
-
// from source code
|
|
9
|
-
interface PickerItemRenderProps {
|
|
10
|
-
selected: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function renderOptions(options: string[], selectedColor: string) {
|
|
14
|
-
return options.map((option) => (
|
|
15
|
-
<Picker.Item key={option} value={option}>
|
|
16
|
-
{({ selected }: PickerItemRenderProps) => (
|
|
17
|
-
<div className={selected ? `font-semibold ${selectedColor}` : 'text-neutral-400'}>{option}</div>
|
|
18
|
-
)}
|
|
19
|
-
</Picker.Item>
|
|
20
|
-
))
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// const DEFAULT_HEIGHT = 216
|
|
24
|
-
// const DEFAULT_ITEM_HEIGHT = 36
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const ProductSelectionMobilePicker: React.FC<{
|
|
28
|
-
products: Product[]
|
|
29
|
-
selectedSku: string | undefined
|
|
30
|
-
onValueChange: (v: string) => void
|
|
31
|
-
height?: number
|
|
32
|
-
itemHeight?: number
|
|
33
|
-
outerClx?: string
|
|
34
|
-
itemClx?: string
|
|
35
|
-
}> = ({
|
|
36
|
-
products,
|
|
37
|
-
selectedSku,
|
|
38
|
-
onValueChange,
|
|
39
|
-
height,
|
|
40
|
-
itemHeight,
|
|
41
|
-
outerClx='',
|
|
42
|
-
itemClx=''
|
|
43
|
-
}) => {
|
|
44
|
-
|
|
45
|
-
// @ts-ignore
|
|
46
|
-
const onChange = (val, ignore) => {
|
|
47
|
-
console.log("VAL", val)
|
|
48
|
-
console.log("key")
|
|
49
|
-
onValueChange(val.item)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
<div className={cn('border border-muted-4 rounded-lg px-2', outerClx)}>
|
|
54
|
-
<Picker
|
|
55
|
-
className=''
|
|
56
|
-
value={selectedSku ? {item: selectedSku} : {item: undefined}}
|
|
57
|
-
onChange={onChange}
|
|
58
|
-
wheelMode="natural"
|
|
59
|
-
height={height}
|
|
60
|
-
itemHeight={itemHeight}
|
|
61
|
-
>
|
|
62
|
-
<Picker.Column name="item">
|
|
63
|
-
{products.map((prod) => (
|
|
64
|
-
<Picker.Item key={prod.sku} value={prod.sku}>
|
|
65
|
-
{({ selected }: PickerItemRenderProps) => (
|
|
66
|
-
<div className={cn(selected ? 'font-semibold text-accent' : 'text-muted', itemClx)}>
|
|
67
|
-
{prod.titleAsOption + ', ' + formatPrice(prod.price)}
|
|
68
|
-
</div>
|
|
69
|
-
)}
|
|
70
|
-
</Picker.Item>
|
|
71
|
-
))}
|
|
72
|
-
</Picker.Column>
|
|
73
|
-
</Picker>
|
|
74
|
-
</div>
|
|
75
|
-
)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export default ProductSelectionMobilePicker
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { Label, RadioGroup, RadioGroupItem } from '@hanzo/ui/primitives'
|
|
4
|
-
import type { Product } from '../types'
|
|
5
|
-
import { formatPrice } from '../util'
|
|
6
|
-
|
|
7
|
-
const ProductSelectionRadioGroup: React.FC<{
|
|
8
|
-
products: Product[]
|
|
9
|
-
selectedSku: string | undefined
|
|
10
|
-
onValueChange: (v: string) => void
|
|
11
|
-
groupClx?: string
|
|
12
|
-
itemClx?: string
|
|
13
|
-
showPrice?: boolean
|
|
14
|
-
}> = ({
|
|
15
|
-
products,
|
|
16
|
-
selectedSku,
|
|
17
|
-
onValueChange,
|
|
18
|
-
groupClx='',
|
|
19
|
-
itemClx='',
|
|
20
|
-
showPrice=true
|
|
21
|
-
}) => (
|
|
22
|
-
products.length > 1 && (
|
|
23
|
-
<RadioGroup
|
|
24
|
-
className={groupClx}
|
|
25
|
-
onValueChange={onValueChange}
|
|
26
|
-
value={selectedSku}
|
|
27
|
-
>
|
|
28
|
-
{products.map((prod) => (
|
|
29
|
-
<div className={itemClx} key={prod.sku}>
|
|
30
|
-
<RadioGroupItem value={prod.sku} id={prod.sku} />
|
|
31
|
-
<Label htmlFor={prod.sku}>{prod.titleAsOption + (showPrice ? (', ' + formatPrice(prod.price)) : '')}</Label>
|
|
32
|
-
</div>
|
|
33
|
-
))}
|
|
34
|
-
</RadioGroup>
|
|
35
|
-
)
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
export default ProductSelectionRadioGroup
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|