@hanzo/commerce 2.0.0 → 3.0.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/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 -17
- 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 +26 -69
- package/components/checkout-panel/payment/contact-info.tsx +59 -0
- package/components/checkout-panel/payment/index.tsx +118 -0
- package/components/checkout-panel/payment/pay-with-bank-transfer.tsx +106 -0
- package/components/checkout-panel/payment/pay-with-card.tsx +198 -0
- package/components/{checkout → checkout-panel/payment}/pay-with-crypto.tsx +52 -30
- package/components/checkout-panel/payment/payment-methods/amex.tsx +32 -0
- package/components/checkout-panel/payment/payment-methods/diners-club.tsx +13 -0
- package/components/checkout-panel/payment/payment-methods/discover.tsx +25 -0
- package/components/checkout-panel/payment/payment-methods/index.tsx +24 -0
- package/components/checkout-panel/payment/payment-methods/jcb.tsx +26 -0
- package/components/checkout-panel/payment/payment-methods/mastercard.tsx +27 -0
- package/components/checkout-panel/payment/payment-methods/visa.tsx +25 -0
- package/components/{checkout → checkout-panel}/shipping-info.tsx +4 -10
- 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 +11 -4
- package/service/context.tsx +4 -4
- package/service/impls/standalone/index.ts +4 -4
- package/service/impls/standalone/orders/index.ts +42 -20
- package/service/impls/standalone/standalone-service.ts +128 -44
- package/types/category.ts +3 -2
- package/types/checkout.ts +6 -0
- package/types/commerce-service.ts +20 -7
- package/types/facet.ts +1 -3
- package/types/index.ts +4 -4
- package/types/item-selector.ts +14 -0
- package/util/index.ts +31 -1
- package/util/square-payment.ts +43 -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/checkout/contact-info.tsx +0 -83
- package/components/checkout/pay-by-bank-transfer.tsx +0 -76
- 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}/thank-you.tsx +0 -0
|
@@ -7,21 +7,26 @@ 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 {
|
|
19
21
|
createOrder as createOrderHelper,
|
|
20
|
-
|
|
22
|
+
updateOrderShippingInfo as updateOrderShippingInfoHelper,
|
|
23
|
+
updateOrderPaymentInfo as updateOrderPaymentInfoHelper
|
|
21
24
|
} from './orders'
|
|
22
25
|
|
|
23
26
|
import ActualLineItem, { type ActualLineItemSnapshot } from './actual-line-item'
|
|
24
27
|
|
|
28
|
+
const SEP = '-'
|
|
29
|
+
|
|
25
30
|
type StandaloneServiceOptions = {
|
|
26
31
|
levelZeroPrefix?: string
|
|
27
32
|
dbName: string
|
|
@@ -36,7 +41,7 @@ class StandaloneService
|
|
|
36
41
|
implements CommerceService
|
|
37
42
|
{
|
|
38
43
|
private _categoryMap = new Map<string, Category>()
|
|
39
|
-
private
|
|
44
|
+
private _rootFacet: FacetValueDesc
|
|
40
45
|
private _selectedFacets: FacetsValue = {}
|
|
41
46
|
|
|
42
47
|
private _options : StandaloneServiceOptions
|
|
@@ -44,12 +49,12 @@ class StandaloneService
|
|
|
44
49
|
|
|
45
50
|
constructor(
|
|
46
51
|
categories: Category[],
|
|
47
|
-
|
|
52
|
+
rootFacet: FacetValueDesc,
|
|
48
53
|
options: StandaloneServiceOptions,
|
|
49
54
|
serviceSnapshot?: StandaloneServiceSnapshot,
|
|
50
55
|
) {
|
|
51
56
|
|
|
52
|
-
this.
|
|
57
|
+
this._rootFacet = rootFacet
|
|
53
58
|
this._options = options
|
|
54
59
|
|
|
55
60
|
categories.forEach((c) => {
|
|
@@ -78,6 +83,7 @@ class StandaloneService
|
|
|
78
83
|
cartItems: computed,
|
|
79
84
|
cartQuantity: computed,
|
|
80
85
|
cartTotal: computed,
|
|
86
|
+
cartEmpty: computed,
|
|
81
87
|
specifiedItems: computed,
|
|
82
88
|
specifiedCategories: computed,
|
|
83
89
|
setCurrentItem: action,
|
|
@@ -88,16 +94,68 @@ class StandaloneService
|
|
|
88
94
|
})
|
|
89
95
|
}
|
|
90
96
|
|
|
91
|
-
|
|
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> {
|
|
145
|
+
async createOrder(email: string, name?: string): Promise<string | undefined> {
|
|
92
146
|
const snapshot = this.takeSnapshot()
|
|
93
|
-
const order = await createOrderHelper(email,
|
|
147
|
+
const order = await createOrderHelper(email, snapshot.items, this._options, name) // didn't want to have two levels of 'items'
|
|
94
148
|
return order.id
|
|
95
149
|
}
|
|
96
150
|
|
|
97
151
|
// TODO: add shippingInfo type
|
|
98
|
-
async
|
|
99
|
-
|
|
100
|
-
|
|
152
|
+
async updateOrderShippingInfo(orderId: string, shippingInfo: any): Promise<void> {
|
|
153
|
+
updateOrderShippingInfoHelper(orderId, shippingInfo, this._options)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// TODO: add paymentInfo type
|
|
157
|
+
async updateOrderPaymentInfo(orderId: string, paymentInfo: any): Promise<void> {
|
|
158
|
+
updateOrderPaymentInfoHelper(orderId, paymentInfo, this._options)
|
|
101
159
|
}
|
|
102
160
|
|
|
103
161
|
takeSnapshot = (): StandaloneServiceSnapshot => ({
|
|
@@ -112,6 +170,10 @@ class StandaloneService
|
|
|
112
170
|
return result.sort((it1, it2) => ((it1 as ActualLineItem).timeAdded - (it2 as ActualLineItem).timeAdded))
|
|
113
171
|
}
|
|
114
172
|
|
|
173
|
+
get cartEmpty(): boolean {
|
|
174
|
+
return this.cartItems.length === 0
|
|
175
|
+
}
|
|
176
|
+
|
|
115
177
|
get cartTotal(): number {
|
|
116
178
|
return this.cartItems.reduce(
|
|
117
179
|
(total, item) => (total + item.price * item.quantity),
|
|
@@ -158,7 +220,6 @@ class StandaloneService
|
|
|
158
220
|
return !!this._currentItem
|
|
159
221
|
}
|
|
160
222
|
|
|
161
|
-
|
|
162
223
|
/* ObsLineItemRef */
|
|
163
224
|
get item(): LineItem | undefined {
|
|
164
225
|
return this._currentItem
|
|
@@ -170,10 +231,7 @@ class StandaloneService
|
|
|
170
231
|
|
|
171
232
|
setFacets(sel: FacetsValue): Category[] {
|
|
172
233
|
runInAction (() => {
|
|
173
|
-
|
|
174
|
-
if (res) {
|
|
175
|
-
this._selectedFacets = res
|
|
176
|
-
}
|
|
234
|
+
this._selectedFacets = this._processAndValidate(sel)
|
|
177
235
|
})
|
|
178
236
|
return this.specifiedCategories
|
|
179
237
|
}
|
|
@@ -186,46 +244,72 @@ class StandaloneService
|
|
|
186
244
|
return result
|
|
187
245
|
}
|
|
188
246
|
|
|
247
|
+
|
|
189
248
|
get specifiedCategories(): Category[] {
|
|
190
249
|
if (Object.keys(toJS(this._selectedFacets)).length === 0) {
|
|
191
250
|
// FacetsDesc have never been set or unset, so cannot evaluate them
|
|
192
251
|
return []
|
|
193
252
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
+
)
|
|
202
261
|
}
|
|
203
262
|
|
|
204
|
-
private
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
|
212
290
|
}
|
|
213
291
|
|
|
214
|
-
private _processAndValidate(partial: FacetsValue): FacetsValue
|
|
292
|
+
private _processAndValidate(partial: FacetsValue): FacetsValue {
|
|
293
|
+
|
|
215
294
|
const result: FacetsValue = {}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
else {
|
|
226
|
-
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
|
|
227
304
|
}
|
|
228
|
-
|
|
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
|
+
|
|
229
313
|
return result
|
|
230
314
|
}
|
|
231
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,21 +1,23 @@
|
|
|
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
|
|
9
|
+
/** Total of all quantities of all products in cart */
|
|
10
10
|
get cartQuantity(): number
|
|
11
|
-
/** Total of all prices
|
|
11
|
+
/** Total of all prices * quantities of products in cart */
|
|
12
12
|
get cartTotal(): number
|
|
13
|
+
|
|
14
|
+
get cartEmpty(): boolean
|
|
13
15
|
|
|
14
16
|
getCartCategorySubtotal(categoryId: string): number
|
|
15
17
|
|
|
16
|
-
createOrder(email: string,
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
createOrder(email: string, name?: string): Promise<string | undefined>
|
|
19
|
+
updateOrderShippingInfo(orderId: string, shippingInfo: any): Promise<void>
|
|
20
|
+
updateOrderPaymentInfo(orderId: string, paymentInfo: any): Promise<void>
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* Sets the tokens at each level supplied.
|
|
@@ -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,10 +1,10 @@
|
|
|
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
|
+
|
|
7
|
+
export type { default as TransactionStatus } from './checkout'
|
|
5
8
|
export * from './line-item'
|
|
6
9
|
export * from './facet'
|
|
7
10
|
export * from './string-mutator'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
@@ -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,5 +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 => {
|
|
30
32
|
|
|
31
|
-
|
|
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
|
+
|
|
59
|
+
|
|
60
|
+
export { default as useSyncSkuParamWithCurrentItem } from './use-sync-sku-param-w-current-item'
|
|
61
|
+
export { default as processSquareCardPayment } from './square-payment'
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
|
|
3
|
+
import { Client, Environment } from 'square'
|
|
4
|
+
import { randomUUID } from 'crypto'
|
|
5
|
+
|
|
6
|
+
// https://developer.squareup.com/blog/online-payments-with-square-and-react/
|
|
7
|
+
declare global {
|
|
8
|
+
interface BigInt {
|
|
9
|
+
toJSON(): string;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
BigInt.prototype.toJSON = function() { return this.toString(); }
|
|
14
|
+
|
|
15
|
+
const { paymentsApi } = new Client({
|
|
16
|
+
accessToken: process.env.SQUARE_ACCESS_TOKEN,
|
|
17
|
+
environment: process.env.SQUARE_ENVIRONMENT as Environment
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const processPayment = async (sourceId: string, amount: number, verificationToken: string) => {
|
|
21
|
+
// Square API accepts amount in cents
|
|
22
|
+
const amountInCents = amount * 100
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const { result } = await paymentsApi.createPayment({
|
|
26
|
+
idempotencyKey: randomUUID(),
|
|
27
|
+
sourceId: sourceId,
|
|
28
|
+
amountMoney: {
|
|
29
|
+
currency: 'USD',
|
|
30
|
+
amount: BigInt(amountInCents)
|
|
31
|
+
},
|
|
32
|
+
verificationToken
|
|
33
|
+
})
|
|
34
|
+
return result
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error('Error processing payment:', error)
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
processPayment as default
|
|
43
|
+
}
|
|
@@ -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,83 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
Form,
|
|
5
|
-
FormControl,
|
|
6
|
-
FormField,
|
|
7
|
-
FormItem,
|
|
8
|
-
FormLabel,
|
|
9
|
-
FormMessage,
|
|
10
|
-
} from '@hanzo/ui/primitives/form'
|
|
11
|
-
import { Input, Button } from '@hanzo/ui/primitives'
|
|
12
|
-
import { User } from 'lucide-react'
|
|
13
|
-
import { EnhHeadingBlockComponent, type EnhHeadingBlock } from '@hanzo/ui/blocks'
|
|
14
|
-
import type { UseFormReturn } from 'react-hook-form'
|
|
15
|
-
|
|
16
|
-
const ContactInfo: React.FC<{
|
|
17
|
-
form: UseFormReturn<{
|
|
18
|
-
name: string;
|
|
19
|
-
email: string;
|
|
20
|
-
}, any, {
|
|
21
|
-
name: string;
|
|
22
|
-
email: string;
|
|
23
|
-
}>,
|
|
24
|
-
selectPaymentMethod: (method: 'crypto' | 'bank') => Promise<void>,
|
|
25
|
-
}> = ({
|
|
26
|
-
form,
|
|
27
|
-
selectPaymentMethod,
|
|
28
|
-
}) => {
|
|
29
|
-
return (
|
|
30
|
-
<Form {...form}>
|
|
31
|
-
<form className='text-left'>
|
|
32
|
-
<div className='flex flex-col gap-4'>
|
|
33
|
-
<div className='flex flex-col sm:flex-row gap-4'>
|
|
34
|
-
<FormField
|
|
35
|
-
control={form.control}
|
|
36
|
-
name='name'
|
|
37
|
-
render={({ field }) => (
|
|
38
|
-
<FormItem className='space-y-1 w-full'>
|
|
39
|
-
<FormLabel>Name</FormLabel>
|
|
40
|
-
<FormControl>
|
|
41
|
-
<Input {...field} />
|
|
42
|
-
</FormControl>
|
|
43
|
-
<FormMessage />
|
|
44
|
-
</FormItem>
|
|
45
|
-
)}
|
|
46
|
-
/>
|
|
47
|
-
<FormField
|
|
48
|
-
control={form.control}
|
|
49
|
-
name='email'
|
|
50
|
-
render={({ field }) => (
|
|
51
|
-
<FormItem className='space-y-1 w-full'>
|
|
52
|
-
<FormLabel>Email</FormLabel>
|
|
53
|
-
<FormControl>
|
|
54
|
-
<Input {...field} />
|
|
55
|
-
</FormControl>
|
|
56
|
-
<FormMessage />
|
|
57
|
-
</FormItem>
|
|
58
|
-
)}
|
|
59
|
-
/>
|
|
60
|
-
</div>
|
|
61
|
-
<div className='flex flex-col sm:flex-row gap-4 items-center'>
|
|
62
|
-
<Button
|
|
63
|
-
type='button'
|
|
64
|
-
onClick={() => selectPaymentMethod('crypto')}
|
|
65
|
-
className='mx-auto w-full'
|
|
66
|
-
>
|
|
67
|
-
Pay with crypto
|
|
68
|
-
</Button>
|
|
69
|
-
<Button
|
|
70
|
-
type='button'
|
|
71
|
-
onClick={() => selectPaymentMethod('bank')}
|
|
72
|
-
className='mx-auto w-full'
|
|
73
|
-
>
|
|
74
|
-
Bank transfer
|
|
75
|
-
</Button>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
</form>
|
|
79
|
-
</Form>
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export default ContactInfo
|