@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
@@ -26,7 +26,7 @@ const AddToCartWidget: React.FC<{
26
26
  size='xs'
27
27
  }) => {
28
28
 
29
- const iconClx = ghost ? 'h-4 w-4 md:h-3 md:w-3 text-muted-3 hover:text-foreground' : 'h-5 w-5 mr-1'
29
+ const iconClx = ghost ? 'h-4 w-4 md:h-3 md:w-3 text-muted-3 hover:text-foreground' : 'h-5 w-7 px-1'
30
30
  const digitClx = ghost ? 'px-2 md:px-0.5' : 'sm:px-2 font-bold '
31
31
 
32
32
  if (disabled) {
@@ -44,7 +44,7 @@ const AddToCartWidget: React.FC<{
44
44
  size={size}
45
45
  variant={ghost ? 'ghost' : 'secondary'}
46
46
  rounded={ghost ? 'full' : 'xl'}
47
- className={cn('px-1 lg:min-w-0 lg:px-2 xs:grow xs:justify-end', buttonClx)}
47
+ className={cn('px-1 lg:min-w-0 lg:px-2 xs:justify-end', buttonClx)}
48
48
  key='left'
49
49
  onClick={item.decrement.bind(item)}
50
50
  >
@@ -60,7 +60,7 @@ const AddToCartWidget: React.FC<{
60
60
  size={size}
61
61
  variant={ghost ? 'ghost' : 'secondary'}
62
62
  rounded={ghost ? 'full' : 'xl'}
63
- className={cn('px-1 lg:min-w-0 lg:px-2 xs:grow xs:justify-start', buttonClx)}
63
+ className={cn('px-1 lg:min-w-0 lg:px-2 xs:justify-start', buttonClx)}
64
64
  onClick={item.increment.bind(item)}
65
65
  key='right'
66
66
  >
@@ -0,0 +1,28 @@
1
+ 'use client'
2
+ import React, {type PropsWithChildren} from 'react'
3
+
4
+ import { type ButtonVariants, type ButtonSizes, Button } from '@hanzo/ui/primitives'
5
+
6
+ import BuyItemPopup from './buy-item-popup'
7
+
8
+ const BuyItemButton: React.FC<PropsWithChildren & {
9
+ skuPath: string
10
+ variant? : ButtonVariants
11
+ size?: ButtonSizes
12
+ /* rounded?: ButtonRounded // wait for version bump*/
13
+ className?: string
14
+ popupClx?: string
15
+ }> = ({
16
+ skuPath,
17
+ variant,
18
+ size,
19
+ children,
20
+ className='',
21
+ popupClx=''
22
+ }) => (
23
+ <BuyItemPopup skuPath={skuPath} popupClx={popupClx}>
24
+ <Button size={size} variant={variant} className={className}>{children}</Button>
25
+ </BuyItemPopup>
26
+ )
27
+
28
+ export default BuyItemButton
@@ -0,0 +1,82 @@
1
+ 'use client'
2
+ import React, { useRef, useEffect } from 'react'
3
+ import { autorun } from 'mobx'
4
+ import { observer } from 'mobx-react-lite'
5
+
6
+ import { cn } from '@hanzo/ui/util'
7
+
8
+ import type { FacetsValue } from '../../types'
9
+ import { useCommerce } from '../../service/context'
10
+ import { getFacetValuesMutator } from '../../util'
11
+ import FacetValuesWidget from '../facet-values-widget'
12
+ import SelectCategoryItemCard from './select-category-item-card'
13
+
14
+
15
+ const BuyItemCard: React.FC<{
16
+ skuPath: string
17
+ className?: string
18
+ }> = observer(({
19
+ skuPath,
20
+ className=''
21
+ }) => {
22
+
23
+ const cmmc = useCommerce()
24
+ const levelRef = useRef<number>(-1)
25
+
26
+ const cat = cmmc.getCategory(skuPath)
27
+ const facets = cat ? undefined : cmmc.getFacetValuesAtSkuPath(skuPath)
28
+
29
+ useEffect(() => {
30
+
31
+ if (facets) {
32
+ const toks = skuPath.split('-')
33
+ const levelSpecified = toks.length - 1
34
+ const fsv: FacetsValue = {}
35
+ for (let level = 1; level <= levelSpecified; level++ ) {
36
+ fsv[level] = [toks[level]]
37
+ }
38
+ fsv[levelSpecified + 1] = [facets[0].value]
39
+ levelRef.current = levelSpecified
40
+ cmmc.setFacets(fsv)
41
+ }
42
+ return autorun(() => {
43
+ const cats = cmmc.specifiedCategories
44
+ // Original cat was legit
45
+ if (cat && (cats.length === 0 || cats[0].id !== cat.id)) {
46
+ if (!cmmc.currentItem || cmmc.currentItem.categoryId !== cat.id) {
47
+ cmmc.setCurrentItem(cat.products[0].sku)
48
+ }
49
+ }
50
+ else if (cats.length > 0) {
51
+ if (!cmmc.currentItem || cmmc.currentItem.categoryId !== cats[0].id) {
52
+ cmmc.setCurrentItem(cats[0].products[0].sku)
53
+ }
54
+ }
55
+ })
56
+ }, [cat, facets])
57
+
58
+ return (
59
+ <div className={className} >
60
+ {facets && levelRef.current > 0 && (
61
+ <FacetValuesWidget
62
+ className={cn('grid gap-0 ' + `grid-cols-${facets.length}` + ' self-start ', 'border-b mb-2 -mr-2 -ml-2')}
63
+ isMobile={false}
64
+ mutator={getFacetValuesMutator(levelRef.current + 1, cmmc)}
65
+ itemClx='flex-col h-auto gap-0 pb-1 pt-3 px-3'
66
+ buttonClx='h-auto !rounded-bl-none !rounded-br-none !rounded-tl-lg !rounded-tr-lg '
67
+ facetValues={facets}
68
+ />
69
+ )}
70
+ {cmmc.specifiedCategories[0] && (
71
+ <SelectCategoryItemCard
72
+ noTitle
73
+ category={cmmc.specifiedCategories[0]}
74
+ selectedItemRef={cmmc /* ...conveniently. :) */ }
75
+ selectSku={cmmc.setCurrentItem.bind(cmmc)}
76
+ />
77
+ )}
78
+ </div >
79
+ )
80
+ })
81
+
82
+ export default BuyItemCard
@@ -0,0 +1,38 @@
1
+ 'use client'
2
+ import React, {type PropsWithChildren} from 'react'
3
+
4
+ import { X } from 'lucide-react'
5
+
6
+ import {
7
+ Popover,
8
+ PopoverContent,
9
+ PopoverTrigger,
10
+ PopoverClose
11
+ } from "@hanzo/ui/primitives"
12
+
13
+ import { cn } from '@hanzo/ui/util'
14
+
15
+ import BuyItemCard from './buy-item-card'
16
+
17
+ const BuyItemPopup: React.FC<PropsWithChildren & {
18
+ skuPath: string
19
+ popupClx?: string
20
+ cardClx?: string
21
+ }> = ({
22
+ skuPath,
23
+ children,
24
+ popupClx='',
25
+ cardClx='',
26
+ }) => (
27
+ <Popover>
28
+ <PopoverTrigger asChild>
29
+ {children}
30
+ </PopoverTrigger>
31
+ <PopoverContent className={cn('relative flex flex-col p-0 px-4 pb-4 pt-2', popupClx)}>
32
+ <PopoverClose className='absolute z-20 right-2 top-2 self-end hover:bg-level-3 text-muted hover:text-accent p-1 rounded-full'><X className='w-5 h-5'/></PopoverClose>
33
+ <BuyItemCard skuPath={skuPath} className={cn("w-full relative ", cardClx)}/>
34
+ </PopoverContent>
35
+ </Popover>
36
+ )
37
+
38
+ export default BuyItemPopup
@@ -5,11 +5,11 @@ import { observer } from 'mobx-react-lite'
5
5
  import { ApplyTypography, ListBox } from '@hanzo/ui/primitives'
6
6
  import { cn } from '@hanzo/ui/util'
7
7
 
8
- import type { FacetValueDesc, FacetsValue, LineItem } from '../types'
9
- import { useCommerce } from '../service/context'
10
- import { formatPrice } from '../util'
8
+ import type { FacetValueDesc, FacetsValue, LineItem } from '../../types'
9
+ import { useCommerce } from '../../service/context'
10
+ import { formatPrice } from '../../util'
11
11
 
12
- import FacetTogglesWidget from './facet-toggles-widget'
12
+ import FacetTogglesWidget from '../facet-values-widget'
13
13
 
14
14
  const formatItem = (item: LineItem, withQuantity: boolean = false): string => (
15
15
  `${item.titleAsOption}, ${formatPrice(item.price)}${(withQuantity && item.quantity > 0) ? ` (${item.quantity})` : ''}`
@@ -0,0 +1,111 @@
1
+ 'use client'
2
+ import React from 'react'
3
+ import { observer } from 'mobx-react-lite'
4
+
5
+ import { cn } from '@hanzo/ui/util'
6
+ import { Skeleton } from '@hanzo/ui/primitives'
7
+
8
+ import type { ItemSelector, LineItem } from '../../types'
9
+
10
+ import AddToCartWidget from '../add-to-cart-widget'
11
+ import CategoryItemRadioSelector from '../category-item-radio-selector'
12
+ import CategoryItemIOSWheelSelector from '../category-item-ios-wheel-selector'
13
+ import { formatPrice } from '../../util'
14
+
15
+ const SelectCategoryItemCard: React.FC<React.HTMLAttributes<HTMLDivElement> & ItemSelector & {
16
+ isLoading?: boolean
17
+ mobile?: boolean
18
+ noTitle?: boolean
19
+ }> = /* NOT observer */({
20
+ category,
21
+ selectedItemRef: selItemRef,
22
+ selectSku,
23
+ className,
24
+ isLoading = false,
25
+ mobile = false,
26
+ noTitle = false,
27
+ ...props
28
+ }) => {
29
+
30
+ const soleOption = category.products.length === 1
31
+
32
+ const SelectProductComp: React.FC<{ className?: string }> = ({ className = '' }) => {
33
+
34
+ if (soleOption) {
35
+ const item = category.products[0] as LineItem
36
+ return (
37
+ <p >{item.titleAsOption + ', ' + formatPrice(item.price) + (item.quantity > 0 ? `(${item.quantity})` : '')}</p>
38
+ )
39
+ }
40
+ const mobilePicker = (mobile && category.products.length > 6)
41
+
42
+ return (
43
+ <div /* id='CV_AVAIL_AMOUNTS' */ className={cn(
44
+ 'sm:w-pr-80 sm:mx-auto md:w-full flex flex-col justify-start items-center',
45
+ className
46
+ )}>
47
+ {!noTitle && (<div className={'h-[1px] bg-muted-3 ' + (mobilePicker ? 'w-pr-55' : 'w-pr-60') } /> )}
48
+ {mobilePicker ? (
49
+ <CategoryItemIOSWheelSelector
50
+ category={category}
51
+ selectedItemRef={selItemRef}
52
+ selectSku={selectSku}
53
+ height={180}
54
+ itemHeight={30}
55
+ outerClx='mb-4'
56
+ />
57
+ ) : (
58
+ <CategoryItemRadioSelector
59
+ category={category}
60
+ selectedItemRef={selItemRef}
61
+ selectSku={selectSku}
62
+ groupClx='mt-2'
63
+ itemClx='flex flex-row gap-2.5 items-center'
64
+ />
65
+ )}
66
+ </div>
67
+ )
68
+ }
69
+
70
+ const AddToCartComp: React.FC<{ className?: string }> = observer(({ className = '' }) => (
71
+ // TODO disable if nothing selected
72
+ (selItemRef.item && !isLoading) && (
73
+ <AddToCartWidget size='default' item={selItemRef.item} className={cn('lg:min-w-[160px] lg:mx-auto', className)}/>
74
+ )
75
+ ))
76
+
77
+ const TitleArea: React.FC<{ className?: string }> = observer(({ className = '' }) => (
78
+
79
+ isLoading ? (<Skeleton className={'h-8 w-full ' + className} />) : (
80
+
81
+ <div className={cn('text-center flex flex-col justify-start items-center', className)}>
82
+ <p className='font-nav text-center'>{category.title}</p>
83
+ </div>
84
+
85
+ )))
86
+
87
+ return mobile ? (
88
+ <div /* id='CV_OUTER' */
89
+ className={cn(
90
+ 'w-full h-[calc(100svh-96px)] max-h-[700px] flex flex-col justify-between ' +
91
+ 'items-stretch gap-[4vh] mt-[2vh] pb-[6vh]',
92
+ className
93
+ )}
94
+ {...props}
95
+ >
96
+ {!noTitle && (<TitleArea className='grow pt-3 mb-0' />)}
97
+ <SelectProductComp className='mb-[3vh]' />
98
+ <AddToCartComp className='w-pr-70 mx-auto' />
99
+ </div>
100
+ ) : (
101
+ <div className={cn('', className)} {...props}>
102
+ {!noTitle && (<TitleArea className='' />)}
103
+ <div className='flex flex-col justify-start items-center gap-4'>
104
+ <SelectProductComp />
105
+ <AddToCartComp className='' />
106
+ </div>
107
+ </div>
108
+ )
109
+ }
110
+
111
+ export default SelectCategoryItemCard
@@ -4,9 +4,10 @@ import Image from 'next/image'
4
4
 
5
5
  import { cn } from '@hanzo/ui/util'
6
6
 
7
- import type { LineItem } from '../types'
8
- import AddToCartWidget from './add-to-cart-widget'
9
- import { formatPrice } from '../util'
7
+ import type { LineItem } from '../../types'
8
+ import { formatPrice } from '../../util'
9
+
10
+ import AddToCartWidget from '../add-to-cart-widget'
10
11
 
11
12
  const IMG_SIZE=40
12
13
 
@@ -5,24 +5,25 @@ import { observer } from 'mobx-react-lite'
5
5
  import { Button } from '@hanzo/ui/primitives'
6
6
  import { cn } from '@hanzo/ui/util'
7
7
 
8
- import { useCommerce } from '../service/context'
9
- import { formatPrice } from '../util'
8
+ import { useCommerce } from '../../service/context'
9
+ import { formatPrice } from '../../util'
10
10
 
11
11
  import CartLineItem from './cart-line-item'
12
- import { Checkout } from '.'
12
+ import CheckoutPanel from '../checkout-panel'
13
13
 
14
- const Cart: React.FC<PropsWithChildren & {
14
+ const CartPanel: React.FC<PropsWithChildren & {
15
15
  className?: string
16
16
  isMobile?: boolean,
17
- hideCheckout?: boolean
17
+ noCheckout?: boolean
18
18
  }> = observer(({
19
19
  /** Children is the heading area. */
20
20
  children,
21
21
  className='',
22
22
  isMobile=false,
23
- hideCheckout=false
23
+ noCheckout=false
24
24
  }) => {
25
- const [isCheckoutOpen, setIsCheckoutOpen] = useState(false)
25
+
26
+ const [checkoutOpen, setCheckoutOpen] = useState<boolean>(false)
26
27
  const cmmc = useCommerce()
27
28
 
28
29
  return (
@@ -30,7 +31,7 @@ const Cart: React.FC<PropsWithChildren & {
30
31
  {children}
31
32
  <div className='mt-2 w-full'>
32
33
  {!!children && <div className='h-[1px] w-pr-80 mb-4 mx-auto bg-muted-3'/>}
33
- {cmmc.cartItems.length === 0 ? (
34
+ {cmmc.cartEmpty ? (
34
35
  <p className='text-center mt-4'>No items in cart</p>
35
36
  ) : (<>
36
37
  {cmmc.cartItems.map((item, i) => (
@@ -39,16 +40,22 @@ const Cart: React.FC<PropsWithChildren & {
39
40
  <p className='mt-6 text-right border-t pt-1'>TOTAL: <span className='font-semibold'>{cmmc.cartTotal === 0 ? '0' : formatPrice(cmmc.cartTotal)}</span></p>
40
41
  </>)}
41
42
  </div>
42
- {!hideCheckout && (
43
- <>
44
- {cmmc.cartItems.length > 0 && (
45
- <Button size='lg' variant='secondary' rounded='lg' className='mt-12 mx-auto' onClick={() => setIsCheckoutOpen(!isCheckoutOpen)}>Checkout</Button>
46
- )}
47
- {isCheckoutOpen && <Checkout toggleCheckout={() => setIsCheckoutOpen(!isCheckoutOpen)}/>}
48
- </>
49
- )}
43
+ {!noCheckout && (<>
44
+ {!cmmc.cartEmpty && (
45
+ <Button
46
+ size='lg'
47
+ variant='secondary'
48
+ rounded='lg'
49
+ className='mt-12 mx-auto'
50
+ onClick={() => setCheckoutOpen(!checkoutOpen)}
51
+ >
52
+ Checkout
53
+ </Button>
54
+ )}
55
+ {checkoutOpen && <CheckoutPanel close={() => {setCheckoutOpen(false)}}/>}
56
+ </>)}
50
57
  </div>
51
58
  )
52
59
  })
53
60
 
54
- export default Cart
61
+ export default CartPanel
@@ -0,0 +1,60 @@
1
+ 'use client'
2
+ import React from 'react'
3
+ import Picker from 'react-mobile-picker'
4
+
5
+ import type { ItemSelector } from '../types'
6
+ import { formatPrice } from '../util'
7
+ import { cn } from '@hanzo/ui/util'
8
+
9
+ // from source code
10
+ interface PickerItemRenderProps {
11
+ selected: boolean;
12
+ }
13
+
14
+ const CategoryItemIOSWheelSelector: React.FC<ItemSelector & {
15
+ height?: number
16
+ itemHeight?: number
17
+ outerClx?: string
18
+ itemClx?: string
19
+ }> = ({
20
+ category,
21
+ selectedItemRef: iRef,
22
+ selectSku,
23
+ height,
24
+ itemHeight,
25
+ outerClx='',
26
+ itemClx=''
27
+ }) => {
28
+
29
+ // @ts-ignore
30
+ const onChange = (val, ignore) => {
31
+ selectSku(val.item)
32
+ }
33
+
34
+ return (
35
+ <div className={cn('border border-muted-4 rounded-lg px-2', outerClx)}>
36
+ <Picker
37
+ className=''
38
+ value={iRef.item ? {item: iRef.item.sku} : {item: undefined}}
39
+ onChange={onChange}
40
+ wheelMode="natural"
41
+ height={height}
42
+ itemHeight={itemHeight}
43
+ >
44
+ <Picker.Column name="item">
45
+ {category.products.map((prod) => (
46
+ <Picker.Item key={prod.sku} value={prod.sku}>
47
+ {({ selected }: PickerItemRenderProps) => (
48
+ <div className={cn(selected ? 'font-semibold text-accent' : 'text-muted', itemClx)}>
49
+ {prod.titleAsOption + ', ' + formatPrice(prod.price)}
50
+ </div>
51
+ )}
52
+ </Picker.Item>
53
+ ))}
54
+ </Picker.Column>
55
+ </Picker>
56
+ </div>
57
+ )
58
+ }
59
+
60
+ export default CategoryItemIOSWheelSelector
@@ -0,0 +1,55 @@
1
+ 'use client'
2
+ import React from 'react'
3
+ import { observer } from 'mobx-react-lite'
4
+
5
+ import { Label, RadioGroup, RadioGroupItem } from '@hanzo/ui/primitives'
6
+ import type { ItemSelector, LineItem, Product } from '../types'
7
+ import { formatPrice } from '../util'
8
+ import { cn } from '@hanzo/ui/util'
9
+
10
+ const CategoryItemRadioSelector: React.FC<ItemSelector & {
11
+ groupClx?: string
12
+ itemClx?: string
13
+ }> = observer(({
14
+ category,
15
+ selectedItemRef: itemRef,
16
+ selectSku,
17
+ groupClx='',
18
+ itemClx='',
19
+ showPrice=true,
20
+ showQuantity=true
21
+ }) => {
22
+
23
+ const Choice: React.FC<{
24
+ item: Product
25
+ className?: string
26
+ }> = ({
27
+ item,
28
+ className=''
29
+ }) => (
30
+ <div className={cn(className, itemClx)}>
31
+ <RadioGroupItem value={item.sku} id={item.sku} />
32
+ <Label htmlFor={item.sku}>{item.titleAsOption + (showPrice ? (', ' + formatPrice(item.price)) : '')}</Label>
33
+ </div>
34
+ )
35
+
36
+ return ( category.products.length > 1 ? (
37
+ <RadioGroup
38
+ className={cn(showQuantity ? 'table' : '', groupClx)}
39
+ onValueChange={selectSku}
40
+ value={itemRef.item ? itemRef.item.sku : ''}
41
+ >
42
+ {(category.products as LineItem[]).map((item) => (showQuantity ? (
43
+ <div className='table-row' key={item.sku}>
44
+ <Choice item={item} className='table-cell pr-2 align-text-top pb-2'/>
45
+ <div className='table-cell font-semibold text-sm leading-none align-text-top pb-2'>{ item.quantity > 0 ? `(${item.quantity})` : ' '}</div>
46
+ </div>
47
+ ) : (
48
+ <Choice item={item} className='mb-2' key={item.sku}/>
49
+ )))}
50
+ </RadioGroup>
51
+ ) : (<p>TODO</p>)
52
+ )
53
+ })
54
+
55
+ export default CategoryItemRadioSelector
@@ -1,9 +1,10 @@
1
1
  'use client'
2
+ import React from 'react'
3
+ import type { UseFormReturn } from 'react-hook-form'
4
+ import { BookUser, Lock, User } from 'lucide-react'
2
5
 
3
6
  import { ApplyTypography, Button } from '@hanzo/ui/primitives'
4
- import { BookUser, Lock, User } from 'lucide-react'
5
7
  import { EnhHeadingBlockComponent, type EnhHeadingBlock } from '@hanzo/ui/blocks'
6
- import type { UseFormReturn } from 'react-hook-form'
7
8
 
8
9
  const ConfirmOrder: React.FC<{
9
10
  paymentForm: UseFormReturn<{