@hanzo/commerce 4.4.1 → 4.5.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 +14 -1
- package/components/buy-item/select-category-item-card.tsx +4 -5
- package/components/cart-panel/index.tsx +8 -7
- package/components/category-item-scroll-selector.tsx +40 -0
- package/components/checkout-panel/index.tsx +10 -7
- package/components/checkout-panel/payment/pay-with-bank-transfer.tsx +1 -1
- package/components/checkout-panel/payment/pay-with-crypto.tsx +2 -2
- package/components/index.ts +1 -1
- package/components/select-category-item-panel.tsx +4 -5
- package/package.json +4 -5
- package/components/category-item-ios-wheel-selector.tsx +0 -62
|
@@ -2,7 +2,7 @@
|
|
|
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'
|
|
@@ -44,6 +44,13 @@ const AddToCartWidget: React.FC<{
|
|
|
44
44
|
if (onQuantityChanged) {
|
|
45
45
|
onQuantityChanged(item.sku, old, old + 1)
|
|
46
46
|
}
|
|
47
|
+
if (old === 0) {
|
|
48
|
+
toast(`Added ${item.title} to your bag.`)
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
toast(`Changed quantity to ${old + 1} for ${item.title}.`)
|
|
52
|
+
}
|
|
53
|
+
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
const dec = () => {
|
|
@@ -52,6 +59,12 @@ const AddToCartWidget: React.FC<{
|
|
|
52
59
|
if (onQuantityChanged) {
|
|
53
60
|
onQuantityChanged(item.sku, old, old - 1)
|
|
54
61
|
}
|
|
62
|
+
if (old === 1) {
|
|
63
|
+
toast(`Removed ${item.title} from your bag.`)
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
toast(`Changed quantity to ${old - 1} for ${item.title}.`)
|
|
67
|
+
}
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
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
|
|
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
|
-
<
|
|
55
|
+
<CategoryItemScrollSelector
|
|
56
56
|
category={category}
|
|
57
57
|
selectedItemRef={selItemRef}
|
|
58
58
|
selectSku={selectSku}
|
|
59
|
-
|
|
60
|
-
|
|
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
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { type PropsWithChildren } from 'react'
|
|
3
3
|
import { observer } from 'mobx-react-lite'
|
|
4
4
|
|
|
5
5
|
import { Button } from '@hanzo/ui/primitives'
|
|
@@ -9,21 +9,23 @@ import { useCommerce } from '../../service/context'
|
|
|
9
9
|
import { formatPrice } from '../../util'
|
|
10
10
|
|
|
11
11
|
import CartLineItem from './cart-line-item'
|
|
12
|
-
import CheckoutPanel from '../checkout-panel'
|
|
13
12
|
|
|
14
13
|
const CartPanel: React.FC<PropsWithChildren & {
|
|
15
14
|
className?: string
|
|
16
15
|
isMobile?: boolean,
|
|
17
16
|
noCheckout?: boolean
|
|
17
|
+
onCheckoutOpen?: () => void
|
|
18
18
|
}> = observer(({
|
|
19
19
|
/** Children is the heading area. */
|
|
20
20
|
children,
|
|
21
21
|
className='',
|
|
22
22
|
isMobile=false,
|
|
23
|
-
noCheckout=false
|
|
23
|
+
noCheckout=false,
|
|
24
|
+
onCheckoutOpen,
|
|
24
25
|
}) => {
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
/* TODO: onCheckoutOpen is a hackish way fix a bug with multiple dialog opened at the same time.
|
|
27
|
+
* Needs refactor with context or so.
|
|
28
|
+
**/
|
|
27
29
|
const cmmc = useCommerce()
|
|
28
30
|
if (!cmmc) {
|
|
29
31
|
return <div />
|
|
@@ -48,12 +50,11 @@ const CartPanel: React.FC<PropsWithChildren & {
|
|
|
48
50
|
variant='primary'
|
|
49
51
|
rounded='lg'
|
|
50
52
|
className='mt-12 mx-auto w-full'
|
|
51
|
-
onClick={
|
|
53
|
+
onClick={onCheckoutOpen}
|
|
52
54
|
>
|
|
53
55
|
Checkout
|
|
54
56
|
</Button>
|
|
55
57
|
)}
|
|
56
|
-
{checkoutOpen && <CheckoutPanel open={checkoutOpen} setOpen={setCheckoutOpen}/>}
|
|
57
58
|
</>)}
|
|
58
59
|
</div>
|
|
59
60
|
)
|
|
@@ -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'
|
|
@@ -26,13 +25,18 @@ import { formatPrice, useCommerce } from '../..'
|
|
|
26
25
|
|
|
27
26
|
const CheckoutPanel: React.FC<{
|
|
28
27
|
open: boolean
|
|
29
|
-
|
|
28
|
+
onCheckoutClose: () => void
|
|
30
29
|
}> = observer(({
|
|
31
30
|
open,
|
|
32
|
-
|
|
31
|
+
onCheckoutClose
|
|
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>()
|
|
@@ -62,7 +66,7 @@ const CheckoutPanel: React.FC<{
|
|
|
62
66
|
|
|
63
67
|
const onClose = () => {
|
|
64
68
|
setStep(1)
|
|
65
|
-
|
|
69
|
+
onCheckoutClose()
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
return (
|
|
@@ -98,9 +102,8 @@ const CheckoutPanel: React.FC<{
|
|
|
98
102
|
</Accordion>
|
|
99
103
|
</div>
|
|
100
104
|
</div>
|
|
101
|
-
<div className='bg-level-1 flex flex-row items-start justify-start'>
|
|
102
|
-
<div className='h-full w-full max-w-[750px] relative flex flex-col gap-8 sm:gap-14
|
|
103
|
-
<Toaster/>
|
|
105
|
+
<div className='bg-level-1 flex flex-row items-start justify-start md:overflow-y-auto'>
|
|
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'>
|
|
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}
|
|
@@ -116,7 +116,7 @@ const PayWithCrypto: React.FC<{
|
|
|
116
116
|
})
|
|
117
117
|
}
|
|
118
118
|
} catch (err) {
|
|
119
|
-
toast(
|
|
119
|
+
toast('Please switch your wallet to the Ethereum network.')
|
|
120
120
|
return
|
|
121
121
|
}
|
|
122
122
|
|
|
@@ -161,7 +161,7 @@ const PayWithCrypto: React.FC<{
|
|
|
161
161
|
} catch (err) {
|
|
162
162
|
console.log(err)
|
|
163
163
|
// :aa TODO string table
|
|
164
|
-
toast(
|
|
164
|
+
toast('Not enough funds in your wallet')
|
|
165
165
|
}
|
|
166
166
|
})()
|
|
167
167
|
}
|
package/components/index.ts
CHANGED
|
@@ -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-
|
|
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
|
|
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
|
-
<
|
|
92
|
+
<CategoryItemScrollSelector
|
|
93
93
|
category={category}
|
|
94
94
|
selectedItemRef={selectedItemRef}
|
|
95
95
|
selectSku={selectSku}
|
|
96
96
|
showQuantity={showQuantity}
|
|
97
|
-
|
|
98
|
-
|
|
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.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "Library with shopping cart components.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -33,20 +33,19 @@
|
|
|
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.
|
|
42
|
-
"@hanzo/ui": "^3.0.
|
|
40
|
+
"@hanzo/auth": "^2.2.1",
|
|
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",
|
|
46
45
|
"mobx": "^6.12.0",
|
|
47
46
|
"mobx-react-lite": "^4.0.5",
|
|
48
47
|
"mobx-utils": "^6.0.8",
|
|
49
|
-
"next": "
|
|
48
|
+
"next": "14.1.3",
|
|
50
49
|
"react": "^18.2.0",
|
|
51
50
|
"react-dom": "^18.2.0",
|
|
52
51
|
"react-hook-form": "7.50.1",
|
|
@@ -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
|