@hanzo/commerce 4.4.2 → 4.6.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.
@@ -2,11 +2,12 @@
2
2
  import React from 'react'
3
3
  import { observer } from 'mobx-react-lite'
4
4
 
5
- import { Button, type ButtonSizes } from '@hanzo/ui/primitives'
5
+ import { Button, toast, type ButtonSizes } from '@hanzo/ui/primitives'
6
6
  import { cn } from '@hanzo/ui/util'
7
7
 
8
8
  import { Icons } from './Icons'
9
9
  import type { LineItem } from '../types'
10
+ import { sendFBEvent, sendGAEvent } from '../util/analytics'
10
11
 
11
12
  const AddToCartWidget: React.FC<{
12
13
  item: LineItem
@@ -44,6 +45,33 @@ const AddToCartWidget: React.FC<{
44
45
  if (onQuantityChanged) {
45
46
  onQuantityChanged(item.sku, old, old + 1)
46
47
  }
48
+ if (old === 0) {
49
+ toast(`Added ${item.title} to your bag.`)
50
+ }
51
+ else {
52
+ toast(`Changed quantity to ${old + 1} for ${item.title}.`)
53
+ }
54
+ sendGAEvent('add_to_cart', {
55
+ items: [{
56
+ item_id: item.sku,
57
+ item_name: item.title,
58
+ item_category: item.categoryId,
59
+ price: item.price,
60
+ quantity: item.quantity
61
+ }],
62
+ value: item.price,
63
+ currency: 'USD',
64
+ })
65
+ sendFBEvent('AddToCart', {
66
+ content_ids: [item.sku],
67
+ contents: [{
68
+ id: item.sku,
69
+ quantity: item.quantity
70
+ }],
71
+ content_name: item.title,
72
+ value: item.price,
73
+ currency: 'USD',
74
+ })
47
75
  }
48
76
 
49
77
  const dec = () => {
@@ -52,6 +80,23 @@ const AddToCartWidget: React.FC<{
52
80
  if (onQuantityChanged) {
53
81
  onQuantityChanged(item.sku, old, old - 1)
54
82
  }
83
+ if (old === 1) {
84
+ toast(`Removed ${item.title} from your bag.`)
85
+ }
86
+ else {
87
+ toast(`Changed quantity to ${old - 1} for ${item.title}.`)
88
+ }
89
+ sendGAEvent('remove_from_cart', {
90
+ items: [{
91
+ item_id: item.sku,
92
+ item_name: item.title,
93
+ item_category: item.categoryId,
94
+ price: item.price,
95
+ quantity: item.quantity
96
+ }],
97
+ value: item.price,
98
+ currency: 'USD',
99
+ })
55
100
  }
56
101
 
57
102
  return ( item.isInCart ? (
@@ -9,7 +9,7 @@ import type { ItemSelector, LineItem } from '../../types'
9
9
 
10
10
  import AddToCartWidget from '../add-to-cart-widget'
11
11
  import CategoryItemRadioSelector from '../category-item-radio-selector'
12
- import CategoryItemIOSWheelSelector from '../category-item-ios-wheel-selector'
12
+ import CategoryItemScrollSelector from '../category-item-scroll-selector'
13
13
  import { formatPrice } from '../../util'
14
14
 
15
15
  const SelectCategoryItemCard: React.FC<React.HTMLAttributes<HTMLDivElement> & ItemSelector & {
@@ -52,13 +52,12 @@ const SelectCategoryItemCard: React.FC<React.HTMLAttributes<HTMLDivElement> & It
52
52
  )}>
53
53
  {!noTitle && (<div className={'h-[1px] bg-muted-3 ' + (mobilePicker ? 'w-pr-55' : 'w-pr-60') } /> )}
54
54
  {mobilePicker ? (
55
- <CategoryItemIOSWheelSelector
55
+ <CategoryItemScrollSelector
56
56
  category={category}
57
57
  selectedItemRef={selItemRef}
58
58
  selectSku={selectSku}
59
- height={180}
60
- itemHeight={30}
61
- outerClx='w-full'
59
+ itemClx='h-10 border-b px-4'
60
+ outerClx='min-w-pr-80 h-[180px]' // 80% of 65% parent
62
61
  />
63
62
  ) : (
64
63
  <CategoryItemRadioSelector
@@ -9,6 +9,7 @@ import { useCommerce } from '../../service/context'
9
9
  import { formatPrice } from '../../util'
10
10
 
11
11
  import CartLineItem from './cart-line-item'
12
+ import { sendFBEvent, sendGAEvent } from '../../util/analytics'
12
13
 
13
14
  const CartPanel: React.FC<PropsWithChildren & {
14
15
  className?: string
@@ -31,6 +32,31 @@ const CartPanel: React.FC<PropsWithChildren & {
31
32
  return <div />
32
33
  }
33
34
 
35
+ const showCheckout = () => {
36
+ sendGAEvent('begin_checkout', {
37
+ currency: 'USD',
38
+ value: cmmc.cartTotal,
39
+ items: cmmc.cartItems.map((item) => ({
40
+ item_id: item.sku,
41
+ item_name: item.title,
42
+ item_category: item.categoryId,
43
+ price: item.price,
44
+ quantity: item.quantity
45
+ })),
46
+ })
47
+ sendFBEvent('InitiateCheckout', {
48
+ content_ids: cmmc.cartItems.map((item) => item.sku),
49
+ contents: cmmc.cartItems.map(item => ({
50
+ id: item.sku,
51
+ quantity: item.quantity
52
+ })),
53
+ num_items: cmmc.cartItems.length,
54
+ value: cmmc.cartTotal,
55
+ currency: 'USD',
56
+ })
57
+ onCheckoutOpen && onCheckoutOpen()
58
+ }
59
+
34
60
  return (
35
61
  <div className={cn('border p-4 rounded-lg', className)}>
36
62
  {children}
@@ -50,7 +76,7 @@ const CartPanel: React.FC<PropsWithChildren & {
50
76
  variant='primary'
51
77
  rounded='lg'
52
78
  className='mt-12 mx-auto w-full'
53
- onClick={onCheckoutOpen}
79
+ onClick={showCheckout}
54
80
  >
55
81
  Checkout
56
82
  </Button>
@@ -0,0 +1,40 @@
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 { ScrollArea } from '@hanzo/ui/primitives'
7
+
8
+ import type { ItemSelector } from '../types'
9
+ import { formatPrice } from '../util'
10
+
11
+
12
+ const CategoryItemScrollSelector: React.FC<ItemSelector & {
13
+ outerClx?: string
14
+ itemClx?: string
15
+ }> = observer(({
16
+ category,
17
+ selectedItemRef: iRef,
18
+ selectSku,
19
+ outerClx='',
20
+ itemClx=''
21
+ }) => {
22
+
23
+ return (
24
+ <ScrollArea className={cn('border border-muted-4 rounded-lg', outerClx)}>
25
+ {category.products.map((prod) => (
26
+ <div key={prod.sku} onClick={() => {selectSku(prod.sku)}}>
27
+ <div className={cn(
28
+ 'h-10 border-b flex flex-col justify-center px-4',
29
+ (iRef.item?.sku === prod.sku) ? 'font-semibold text-accent' : 'text-muted',
30
+ itemClx
31
+ )}>
32
+ {prod.titleAsOption + ', ' + formatPrice(prod.price)}
33
+ </div>
34
+ </div>
35
+ ))}
36
+ </ScrollArea>
37
+ )
38
+ })
39
+
40
+ export default CategoryItemScrollSelector
@@ -10,7 +10,6 @@ import {
10
10
  AccordionTrigger,
11
11
  Dialog,
12
12
  DialogPortal,
13
- Toaster
14
13
  } from '@hanzo/ui/primitives'
15
14
  import { cn } from '@hanzo/ui/util'
16
15
  import { AuthWidget } from '@hanzo/auth/components'
@@ -33,6 +32,11 @@ const CheckoutPanel: React.FC<{
33
32
  }) => {
34
33
 
35
34
  const cmmc = useCommerce()
35
+
36
+ // For sites that don't initialize cmmc
37
+ if (!cmmc) {
38
+ return <></>
39
+ }
36
40
 
37
41
  const [step, setStep] = useState<number>(1)
38
42
  const [orderId, setOrderId] = useState<string>()
@@ -100,7 +104,6 @@ const CheckoutPanel: React.FC<{
100
104
  </div>
101
105
  <div className='bg-level-1 flex flex-row items-start justify-start md:overflow-y-auto'>
102
106
  <div className='h-full w-full max-w-[750px] relative flex flex-col gap-8 sm:gap-14 px-8 pb-6 pt-6 md:pt-14'>
103
- <Toaster/>
104
107
  <AuthWidget hideLogin className='hidden md:flex absolute top-4 right-4 '/>
105
108
  <StepIndicator steps={steps} currentStep={step} className='flex gap-2 mx-auto items-center text-xxs sm:text-base' />
106
109
  {steps[step].element}
@@ -14,6 +14,7 @@ import PayWithBankTransfer from './pay-with-bank-transfer'
14
14
  import PayWithCard from './pay-with-card'
15
15
  import { useCommerce } from '../../../service/context'
16
16
  import type { TransactionStatus } from '../../../types'
17
+ import { sendFBEvent, sendGAEvent } from '../../../util/analytics'
17
18
 
18
19
  const contactFormSchema = z.object({
19
20
  name: z.string().min(1, 'Enter your full name.'),
@@ -56,6 +57,26 @@ const Payment: React.FC<{
56
57
  setOrderId(id)
57
58
  }
58
59
  if (id) {
60
+ sendGAEvent('add_payment_info', {
61
+ items: cmmc.cartItems.map((item) => ({
62
+ item_id: item.sku,
63
+ item_name: item.title,
64
+ item_category: item.categoryId,
65
+ price: item.price,
66
+ quantity: item.quantity
67
+ })),
68
+ value: cmmc.cartTotal,
69
+ currency: 'USD',
70
+ payment_type: paymentInfo.paymentMethod ?? ''
71
+ })
72
+ sendFBEvent('AddPaymentInfo', {
73
+ contents: cmmc.cartItems.map(item => ({
74
+ id: item.sku,
75
+ quantity: item.quantity
76
+ })),
77
+ value: cmmc.cartTotal,
78
+ currency: 'USD'
79
+ })
59
80
  await cmmc.updateOrderPaymentInfo(id, paymentInfo)
60
81
  }
61
82
  }
@@ -13,6 +13,7 @@ import type { TransactionStatus } from '../../../types'
13
13
 
14
14
  import PaymentMethods from './payment-methods'
15
15
  import ContactInfo from './contact-info'
16
+ import { sendFBEvent, sendGAEvent } from '../../../util/analytics'
16
17
 
17
18
  const PayWithCard: React.FC<{
18
19
  setStep: (currentStep: number) => void
@@ -46,6 +47,28 @@ const PayWithCard: React.FC<{
46
47
  console.log(token)
47
48
  await storePaymentInfo({paymentMethod: token.details.method ?? null, processed: res})
48
49
  setTransactionStatus('confirmed')
50
+ sendGAEvent('purchase', {
51
+ transaction_id: res.payment?.id,
52
+ value: res.payment?.amountMoney?.amount,
53
+ currency: res.payment?.amountMoney?.currency,
54
+ items: cmmc.cartItems.map((item) => ({
55
+ item_id: item.sku,
56
+ item_name: item.title,
57
+ item_category: item.categoryId,
58
+ price: item.price,
59
+ quantity: item.quantity
60
+ })),
61
+ })
62
+ sendFBEvent('Purchase', {
63
+ content_ids: cmmc.cartItems.map((item) => item.sku),
64
+ contents: cmmc.cartItems.map(item => ({
65
+ id: item.sku,
66
+ quantity: item.quantity
67
+ })),
68
+ num_items: cmmc.cartItems.length,
69
+ value: cmmc.cartTotal,
70
+ currency: 'USD',
71
+ })
49
72
  } else {
50
73
  setTransactionStatus('error')
51
74
  }
@@ -19,14 +19,13 @@ import {
19
19
  } from '@hanzo/ui/primitives'
20
20
 
21
21
  import { useAuth } from '@hanzo/auth/service'
22
- import { Ethereum as EthIconFromAuth } from '@hanzo/auth/icons'
23
22
 
24
23
  import Eth from '../icons/eth'
25
24
  import { useCommerce } from '../../../service/context'
26
25
  import type { TransactionStatus } from '../../../types'
27
26
  import ContactInfo from './contact-info'
28
27
  import type { UseFormReturn } from 'react-hook-form'
29
- import { LoginComponent } from '@hanzo/auth/components'
28
+ import { sendFBEvent, sendGAEvent } from '../../../util/analytics'
30
29
 
31
30
  declare global {
32
31
  interface Window{
@@ -53,7 +52,7 @@ const PayWithCrypto: React.FC<{
53
52
  storePaymentInfo,
54
53
  contactForm
55
54
  }) => {
56
- const c = useCommerce()
55
+ const cmmc = useCommerce()
57
56
  const auth = useAuth()
58
57
  const [loadingPrice, setLoadingPrice] = useState(false)
59
58
  //const [selectedToken, setSelectedToken] = useState('eth')
@@ -85,7 +84,7 @@ const PayWithCrypto: React.FC<{
85
84
  .then(res => res.json())
86
85
  .then((exchangeRate) => {
87
86
  const oneUsdInWei = (10**18) / exchangeRate.data.amount
88
- const usdAmountInWei = oneUsdInWei * c.cartTotal
87
+ const usdAmountInWei = oneUsdInWei * cmmc.cartTotal
89
88
  setAmount(usdAmountInWei)
90
89
  setLoadingPrice(false)
91
90
  })
@@ -98,7 +97,7 @@ const PayWithCrypto: React.FC<{
98
97
  const interval = setInterval(fetchPrice, 30000)
99
98
 
100
99
  return () => clearInterval(interval)
101
- }, [c.cartTotal])
100
+ }, [cmmc.cartTotal])
102
101
 
103
102
  const sendPayment = async (ether: number) => {
104
103
  contactForm.handleSubmit(async () => {
@@ -130,9 +129,10 @@ const PayWithCrypto: React.FC<{
130
129
 
131
130
  const signer = await provider.getSigner()
132
131
  ethers.getAddress(process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS ?? '')
132
+ const price = ethers.parseEther(ether.toString())
133
133
  const tx = await signer.sendTransaction({
134
134
  to: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS,
135
- value: ethers.parseEther(ether.toString())
135
+ value: price
136
136
  })
137
137
  console.log({ ether, addr: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS })
138
138
  console.log('tx', tx)
@@ -150,7 +150,30 @@ const PayWithCrypto: React.FC<{
150
150
  await storePaymentInfo({
151
151
  ether,
152
152
  addr: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS,
153
- receipt
153
+ receipt,
154
+ paymentMethod: 'crypto'
155
+ })
156
+ sendGAEvent('purchase', {
157
+ transaction_id: tx.hash,
158
+ value: price,
159
+ currency: 'ETH',
160
+ items: cmmc.cartItems.map((item) => ({
161
+ item_id: item.sku,
162
+ item_name: item.title,
163
+ item_category: item.categoryId,
164
+ price: item.price,
165
+ quantity: item.quantity
166
+ })),
167
+ })
168
+ sendFBEvent('Purchase', {
169
+ content_ids: cmmc.cartItems.map((item) => item.sku),
170
+ contents: cmmc.cartItems.map(item => ({
171
+ id: item.sku,
172
+ quantity: item.quantity
173
+ })),
174
+ num_items: cmmc.cartItems.length,
175
+ value: price,
176
+ currency: 'ETH',
154
177
  })
155
178
  setTransactionStatus('confirmed')
156
179
  })
@@ -21,11 +21,10 @@ import {
21
21
  SelectValue
22
22
  } from '@hanzo/ui/primitives'
23
23
 
24
- import { useAuth } from '@hanzo/auth/service'
25
-
26
24
  import { useCommerce } from '../..'
27
25
 
28
26
  import { countries } from './countries'
27
+ import { sendGAEvent } from '../../util/analytics'
29
28
 
30
29
  const shippingFormSchema = z.object({
31
30
  addressLine1: z.string().min(2, 'Address must be at least 2 characters.'),
@@ -43,7 +42,6 @@ const ShippingInfo: React.FC<{
43
42
  orderId,
44
43
  setStep
45
44
  }) => {
46
- const auth = useAuth()
47
45
  const cmmc = useCommerce()
48
46
 
49
47
  const shippingForm = useForm<z.infer<typeof shippingFormSchema>>({
@@ -62,6 +60,18 @@ const ShippingInfo: React.FC<{
62
60
  if (orderId) {
63
61
  await cmmc.updateOrderShippingInfo(orderId, values)
64
62
  }
63
+ sendGAEvent('add_shipping_info', {
64
+ items: cmmc.cartItems.map((item) => ({
65
+ item_id: item.sku,
66
+ item_name: item.title,
67
+ item_category: item.categoryId,
68
+ price: item.price,
69
+ quantity: item.quantity
70
+ })),
71
+ num_items: cmmc.cartItems.length,
72
+ value: cmmc.cartTotal,
73
+ currency: 'USD',
74
+ })
65
75
  setStep(3)
66
76
  }
67
77
 
@@ -4,25 +4,25 @@ import Image from 'next/image'
4
4
  import type { FacetValueDesc } from '../../types'
5
5
 
6
6
  const ICON_SIZE = 20
7
- const SVG_MULT = 1.5
8
7
 
9
8
  const FacetImage: React.FC<{
10
9
  facetValueDesc: FacetValueDesc
11
10
  }> = ({
12
11
  facetValueDesc
13
12
  }) => {
13
+
14
14
  const {
15
15
  img,
16
16
  imgAR: ar,
17
17
  label
18
18
  } = facetValueDesc
19
19
 
20
-
21
20
  if (!img) {
22
21
  return null
23
22
  }
24
- const isURL = typeof img === 'string'
25
- if (isURL) {
23
+
24
+ // url
25
+ if (typeof img === 'string') {
26
26
  return (
27
27
  <Image
28
28
  src={img as string}
@@ -33,42 +33,8 @@ const FacetImage: React.FC<{
33
33
  />
34
34
  )
35
35
  }
36
-
36
+ // ReactNode
37
37
  return img as React.ReactNode
38
-
39
- // Otherwise, assume it's a ReactNode of an imported SVG
40
-
41
- // If it's not square, center it in the appropriate dimension
42
- /*
43
- const svgStyle: any = { position: 'relative' }
44
- if (ar) {
45
- if (ar < 1) {
46
- const w = ICON_SIZE * SVG_MULT
47
- svgStyle.top = (( 1 / ar - 1) * w) / 2
48
- }
49
- else if (ar > 1) {
50
- const h = ICON_SIZE * SVG_MULT
51
- svgStyle.left = (((1 - ar) * h) / 2)
52
- }
53
- }
54
-
55
- return (
56
- <span
57
- className='flex justify-center items-center overflow-hidden '
58
- style={{
59
- color: 'inherit',
60
- width: ICON_SIZE * SVG_MULT,
61
- height: ICON_SIZE * SVG_MULT,
62
- }}
63
- >
64
- {React.cloneElement(facetValueDesc.img as React.ReactElement<any>, {
65
- width: (facetValueDesc.imgAR ?? 1) * ICON_SIZE * SVG_MULT,
66
- height: SVG_MULT * ICON_SIZE,
67
- style: svgStyle
68
- })}
69
- </span>
70
- )
71
- */
72
38
  }
73
39
 
74
40
  export default FacetImage
@@ -5,7 +5,7 @@ export { default as BuyItemCard } from './buy-item/buy-item-card'
5
5
  export { default as BuyItemPopup } from './buy-item/buy-item-popup'
6
6
  export { default as CartPanel } from './cart-panel'
7
7
  export { default as CheckoutPanel } from './checkout-panel'
8
- export { default as CategoryItemIOSWheelSelector } from './category-item-ios-wheel-selector'
8
+ export { default as CategoryItemIOSWheelSelector } from './category-item-scroll-selector'
9
9
  export { default as CategoryItemRadioSelector } from './category-item-radio-selector'
10
10
  export { default as FacetValuesWidget } from './facet-values-widget'
11
11
  export { default as ProductCard } from './product-card'
@@ -12,7 +12,7 @@ import { Icons } from './Icons'
12
12
 
13
13
  import AddToCartWidget from './add-to-cart-widget'
14
14
  import CategoryItemRadioSelector from './category-item-radio-selector'
15
- import CategoryItemIOSWheelSelector from './category-item-ios-wheel-selector'
15
+ import CategoryItemScrollSelector from './category-item-scroll-selector'
16
16
 
17
17
  const SelectCategoryItemPanel: React.FC<
18
18
  React.HTMLAttributes<HTMLDivElement> & ItemSelector &
@@ -89,14 +89,13 @@ const SelectCategoryItemPanel: React.FC<
89
89
  <div className={'h-[1px] bg-muted-3 ' + (mobilePicker ? 'w-pr-55' : 'w-pr-60') } />
90
90
  </div>
91
91
  {mobilePicker ? (
92
- <CategoryItemIOSWheelSelector
92
+ <CategoryItemScrollSelector
93
93
  category={category}
94
94
  selectedItemRef={selectedItemRef}
95
95
  selectSku={selectSku}
96
96
  showQuantity={showQuantity}
97
- height={180}
98
- itemHeight={30}
99
- outerClx='mb-4'
97
+ itemClx='h-10 border-b px-4'
98
+ outerClx='mb-4 h-[180px]'
100
99
  />
101
100
  ) : (
102
101
  <CategoryItemRadioSelector
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/commerce",
3
- "version": "4.4.2",
3
+ "version": "4.6.0",
4
4
  "description": "Library with shopping cart components.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
@@ -33,13 +33,12 @@
33
33
  "dependencies": {
34
34
  "ethers": "^6.11.1",
35
35
  "next-usequerystate": "^1.17.0",
36
- "react-mobile-picker": "^1.0.0",
37
36
  "react-square-web-payments-sdk": "^3.2.1",
38
37
  "square": "^35.0.0"
39
38
  },
40
39
  "peerDependencies": {
41
- "@hanzo/auth": "^2.2.1",
42
- "@hanzo/ui": "^3.0.6",
40
+ "@hanzo/auth": "^2.3.0",
41
+ "@hanzo/ui": "^3.0.7",
43
42
  "@hookform/resolvers": "^3.3.4",
44
43
  "firebase": "^10.8.0",
45
44
  "lucide-react": "^0.307.0",
@@ -0,0 +1,21 @@
1
+ declare global {
2
+ interface Window {
3
+ fbq: Function;
4
+ gtag: Function;
5
+ }
6
+ }
7
+
8
+ // https://developers.facebook.com/docs/meta-pixel/reference
9
+ const sendFBEvent = (name: string, options = {}) => {
10
+ window.fbq('track', name, options)
11
+ }
12
+
13
+ // https://developers.google.com/analytics/devguides/collection/ga4/ecommerce?client_type=gtag
14
+ const sendGAEvent = (name: string, options = {}) => {
15
+ window.gtag('event', name, options)
16
+ }
17
+
18
+ export {
19
+ sendFBEvent,
20
+ sendGAEvent,
21
+ }
@@ -1,62 +0,0 @@
1
- 'use client'
2
- import React from 'react'
3
- import Picker from 'react-mobile-picker'
4
- import { observer } from 'mobx-react-lite'
5
-
6
- import type { ItemSelector } from '../types'
7
- import { formatPrice } from '../util'
8
- import { cn } from '@hanzo/ui/util'
9
-
10
- // from source code
11
- interface PickerItemRenderProps {
12
- selected: boolean;
13
- }
14
-
15
- const CategoryItemIOSWheelSelector: React.FC<ItemSelector & {
16
- height?: number
17
- itemHeight?: number
18
- outerClx?: string
19
- itemClx?: string
20
- }> = observer(({
21
- category,
22
- selectedItemRef: iRef,
23
- selectSku,
24
- height,
25
- itemHeight,
26
- outerClx='',
27
- itemClx=''
28
- }) => {
29
-
30
- // @ts-ignore
31
- const onChange = (val, ignore) => {
32
- console.log("WHEEL: ", val.item)
33
- selectSku(val.item)
34
- }
35
-
36
- return (
37
- <div className={cn('border border-muted-4 rounded-lg px-2', outerClx)}>
38
- <Picker
39
- className=''
40
- value={iRef.item ? {item: iRef.item.sku} : {item: undefined}}
41
- onChange={onChange}
42
- wheelMode="natural"
43
- height={height}
44
- itemHeight={itemHeight}
45
- >
46
- <Picker.Column name="item">
47
- {category.products.map((prod) => (
48
- <Picker.Item key={prod.sku} value={prod.sku}>
49
- {({ selected }: PickerItemRenderProps) => (
50
- <div className={cn(selected ? 'font-semibold text-accent' : 'text-muted', itemClx)}>
51
- {prod.titleAsOption + ', ' + formatPrice(prod.price)}
52
- </div>
53
- )}
54
- </Picker.Item>
55
- ))}
56
- </Picker.Column>
57
- </Picker>
58
- </div>
59
- )
60
- })
61
-
62
- export default CategoryItemIOSWheelSelector