@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.
Files changed (56) hide show
  1. package/components/add-to-cart-widget.tsx +3 -3
  2. package/components/buy-item/buy-item-button.tsx +28 -0
  3. package/components/buy-item/buy-item-card.tsx +82 -0
  4. package/components/buy-item/buy-item-popup.tsx +38 -0
  5. package/components/{select-category-and-item-widget.tsx → buy-item/select-category-and-item-widget.tsx} +4 -4
  6. package/components/buy-item/select-category-item-card.tsx +111 -0
  7. package/components/{cart-line-item.tsx → cart-panel/cart-line-item.tsx} +4 -3
  8. package/components/{cart.tsx → cart-panel/index.tsx} +24 -17
  9. package/components/category-item-ios-wheel-selector.tsx +60 -0
  10. package/components/category-item-radio-selector.tsx +55 -0
  11. package/components/{checkout → checkout-panel}/confirm-order.tsx +3 -2
  12. package/components/{checkout → checkout-panel}/index.tsx +26 -69
  13. package/components/checkout-panel/payment/contact-info.tsx +59 -0
  14. package/components/checkout-panel/payment/index.tsx +118 -0
  15. package/components/checkout-panel/payment/pay-with-bank-transfer.tsx +106 -0
  16. package/components/checkout-panel/payment/pay-with-card.tsx +198 -0
  17. package/components/{checkout → checkout-panel/payment}/pay-with-crypto.tsx +52 -30
  18. package/components/checkout-panel/payment/payment-methods/amex.tsx +32 -0
  19. package/components/checkout-panel/payment/payment-methods/diners-club.tsx +13 -0
  20. package/components/checkout-panel/payment/payment-methods/discover.tsx +25 -0
  21. package/components/checkout-panel/payment/payment-methods/index.tsx +24 -0
  22. package/components/checkout-panel/payment/payment-methods/jcb.tsx +26 -0
  23. package/components/checkout-panel/payment/payment-methods/mastercard.tsx +27 -0
  24. package/components/checkout-panel/payment/payment-methods/visa.tsx +25 -0
  25. package/components/{checkout → checkout-panel}/shipping-info.tsx +4 -10
  26. package/components/{facet-toggles-widget → facet-values-widget}/facet-image.tsx +7 -3
  27. package/components/{facet-toggles-widget → facet-values-widget}/index.tsx +7 -5
  28. package/components/index.ts +11 -9
  29. package/components/{select-item-in-category-view.tsx → select-category-item-panel.tsx} +72 -76
  30. package/index.ts +2 -2
  31. package/package.json +11 -4
  32. package/service/context.tsx +4 -4
  33. package/service/impls/standalone/index.ts +4 -4
  34. package/service/impls/standalone/orders/index.ts +42 -20
  35. package/service/impls/standalone/standalone-service.ts +128 -44
  36. package/types/category.ts +3 -2
  37. package/types/checkout.ts +6 -0
  38. package/types/commerce-service.ts +20 -7
  39. package/types/facet.ts +1 -3
  40. package/types/index.ts +4 -4
  41. package/types/item-selector.ts +14 -0
  42. package/util/index.ts +31 -1
  43. package/util/square-payment.ts +43 -0
  44. package/util/use-sync-sku-param-w-current-item.ts +4 -1
  45. package/blocks/components/commerce-cat-and-item-block.tsx +0 -13
  46. package/blocks/def/commerce-cat-and-item-block.ts +0 -9
  47. package/components/checkout/contact-info.tsx +0 -83
  48. package/components/checkout/pay-by-bank-transfer.tsx +0 -76
  49. package/components/facets-widget.tsx +0 -55
  50. package/components/product-selection-mobile-picker.tsx +0 -78
  51. package/components/product-selection-radio-group.tsx +0 -38
  52. /package/components/{checkout → checkout-panel}/countries.ts +0 -0
  53. /package/components/{checkout → checkout-panel}/icons/btc.tsx +0 -0
  54. /package/components/{checkout → checkout-panel}/icons/eth.tsx +0 -0
  55. /package/components/{checkout → checkout-panel}/icons/usdt.tsx +0 -0
  56. /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
- FacetsDesc
17
+ FacetValueDesc
16
18
  } from '../../../types'
17
19
 
18
20
  import {
19
21
  createOrder as createOrderHelper,
20
- updateOrder as updateOrderHelper
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 _facetsDesc: FacetsDesc
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
- facets: FacetsDesc,
52
+ rootFacet: FacetValueDesc,
48
53
  options: StandaloneServiceOptions,
49
54
  serviceSnapshot?: StandaloneServiceSnapshot,
50
55
  ) {
51
56
 
52
- this._facetsDesc = facets
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
- async createOrder(email: string, paymentMethod: string): Promise<string | undefined> {
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, paymentMethod, snapshot.items, this._options) // didn't want to have two levels of 'items'
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 updateOrder(orderId: string, email: string, paymentMethod: string, shippingInfo?: any): Promise<void> {
99
- const snapshot = this.takeSnapshot()
100
- updateOrderHelper(orderId, email, paymentMethod, snapshot.items, this._options, shippingInfo) // didn't want to have two levels of 'items'
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
- const res = this._processAndValidate(sel)
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
- const keysStr = Object.keys(this._facetsDesc)
195
- // 1-base, visiting two per iteration
196
- let current: string[] = this._selectedFacets[1]
197
- for (let i = 2; i <= keysStr.length; i++) {
198
- current = StandaloneService._visit(current, this._selectedFacets[i])
199
- }
200
- const prefix = this._options.levelZeroPrefix ?? ''
201
- return current.map((almostTheCatId) => (this._categoryMap.get(prefix + almostTheCatId)!))
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 static _visit(current: string[], next: string[]): string[] {
205
- const result: string[] = []
206
- current.forEach((c) => {
207
- next.forEach((n) => {
208
- result.push(`${c}-${n}`)
209
- })
210
- })
211
- return result
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 | undefined {
292
+ private _processAndValidate(partial: FacetsValue): FacetsValue {
293
+
215
294
  const result: FacetsValue = {}
216
- const keysStr = Object.keys(this._facetsDesc)
217
- const keysNum = keysStr.map((key) => (parseInt(key)))
218
- keysNum.forEach((key) => {
219
- if (partial[key]) {
220
- // If present, filter out the bad values (the one's that don't exist in the Desc)
221
- const filtered = partial[key].filter((fv) => (this._facetsDesc[key].find((fvDesc) => (fvDesc.value === fv))))
222
- result[key] = filtered
223
- }
224
- // if not present, assume the facet is "off" and allow all (include all in the set).
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 // LXB-AU-B
5
- title: string // Lux Gold, Minted Bar
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
@@ -0,0 +1,6 @@
1
+
2
+ type TransactionStatus = 'unpaid' | 'paid' | 'confirmed' | 'error'
3
+
4
+ export {
5
+ type TransactionStatus as default
6
+ }
@@ -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 items in cart */
9
+ /** Total of all quantities of all products in cart */
10
10
  get cartQuantity(): number
11
- /** Total of all prices X quantities of items in cart */
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, paymentMethod: string): Promise<string | undefined>
17
- // TODO: add shippingInfo type
18
- updateOrder(orderId: string, email: string, paymentMethod: string, shippingInfo?: any): Promise<void>
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
- export type { default as Category } from './category'
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
- export { default as useSyncSkuParamWithCurrentItem } from './use-sync-sku-param-w-current-item'
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
- fv[i] = [toks[i]]
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