@hanzo/commerce 4.1.1 → 4.2.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/checkout-panel/close-button.tsx +24 -0
- package/components/checkout-panel/index.tsx +55 -59
- package/components/checkout-panel/payment/index.tsx +5 -5
- package/components/checkout-panel/payment/pay-with-bank-transfer.tsx +3 -3
- package/components/checkout-panel/payment/pay-with-card.tsx +3 -3
- package/components/checkout-panel/payment/pay-with-crypto.tsx +3 -3
- package/components/checkout-panel/shipping-info.tsx +3 -3
- package/components/checkout-panel/step-indicator.tsx +30 -0
- package/components/checkout-panel/step.ts +11 -0
- package/package.json +2 -2
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import { ChevronLeft } from 'lucide-react'
|
|
5
|
+
import { Button } from '@hanzo/ui/primitives'
|
|
6
|
+
|
|
7
|
+
const CloseButton: React.FC<{
|
|
8
|
+
onClose: () => void
|
|
9
|
+
className?: string
|
|
10
|
+
}> = ({
|
|
11
|
+
onClose,
|
|
12
|
+
className=''
|
|
13
|
+
}) => (
|
|
14
|
+
<Button
|
|
15
|
+
variant='ghost'
|
|
16
|
+
size='icon'
|
|
17
|
+
onClick={onClose}
|
|
18
|
+
className={className}
|
|
19
|
+
>
|
|
20
|
+
<ChevronLeft className='w-5 h-5'/>
|
|
21
|
+
</Button>
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export default CloseButton
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { useState } from 'react'
|
|
4
|
-
import { ChevronLeft } from 'lucide-react'
|
|
5
4
|
import { observer } from 'mobx-react-lite'
|
|
6
5
|
|
|
7
|
-
import {
|
|
6
|
+
import { Dialog, DialogPortal, Separator, Toaster } from '@hanzo/ui/primitives'
|
|
8
7
|
import { cn } from '@hanzo/ui/util'
|
|
9
8
|
import { useAuth } from '@hanzo/auth/service'
|
|
10
9
|
import { LoginComponent, AuthWidget } from '@hanzo/auth/components'
|
|
@@ -13,6 +12,8 @@ import ShippingInfo from './shipping-info'
|
|
|
13
12
|
import ThankYou from './thank-you'
|
|
14
13
|
import CartPanel from '../cart-panel'
|
|
15
14
|
import Payment from './payment'
|
|
15
|
+
import CloseButton from './close-button'
|
|
16
|
+
import StepIndicator from './step-indicator'
|
|
16
17
|
|
|
17
18
|
const CheckoutPanel: React.FC<{
|
|
18
19
|
open: boolean
|
|
@@ -24,74 +25,69 @@ const CheckoutPanel: React.FC<{
|
|
|
24
25
|
|
|
25
26
|
const auth = useAuth()
|
|
26
27
|
|
|
27
|
-
const [
|
|
28
|
+
const [step, setStep] = useState<number>(1)
|
|
28
29
|
const [orderId, setOrderId] = useState<string>()
|
|
29
30
|
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
31
|
+
const steps = {
|
|
32
|
+
1: {
|
|
33
|
+
label: 'Payment',
|
|
34
|
+
element: (
|
|
35
|
+
auth.loggedIn ? (
|
|
36
|
+
<Payment
|
|
37
|
+
orderId={orderId}
|
|
38
|
+
setOrderId={setOrderId}
|
|
39
|
+
setStep={setStep}
|
|
40
|
+
/>
|
|
41
|
+
) : (
|
|
42
|
+
<LoginComponent hideHeader className='max-w-[20rem] mx-auto' inputClassName='border-muted-4'>
|
|
43
|
+
<h6 className='font-nav'>Please login to proceed</h6>
|
|
44
|
+
</LoginComponent >
|
|
45
|
+
)
|
|
46
|
+
)}
|
|
47
|
+
,
|
|
48
|
+
2: {
|
|
49
|
+
label: 'Delivery',
|
|
50
|
+
element: (
|
|
51
|
+
<ShippingInfo orderId={orderId} setStep={setStep}/>
|
|
52
|
+
)},
|
|
53
|
+
3: {
|
|
54
|
+
label: 'Done!',
|
|
55
|
+
element: (
|
|
56
|
+
<ThankYou/>
|
|
57
|
+
)}
|
|
58
|
+
} as Record<number, {label: string, element: JSX.Element}>
|
|
45
59
|
|
|
46
|
-
const
|
|
60
|
+
const onClose = () => {
|
|
61
|
+
setStep(1)
|
|
62
|
+
setOpen(false)
|
|
63
|
+
}
|
|
47
64
|
|
|
48
65
|
return (
|
|
49
66
|
<Dialog open={open}>
|
|
50
67
|
<DialogPortal>
|
|
51
|
-
<div
|
|
68
|
+
<div id='PORTAL_OUTER'
|
|
52
69
|
className={cn(
|
|
53
|
-
'fixed
|
|
54
|
-
'
|
|
70
|
+
'fixed top-0 pt-[44px] md:pt-[80px] shadow-lg ',
|
|
71
|
+
'animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10',
|
|
72
|
+
'sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0',
|
|
73
|
+
'!max-w-none w-full h-full min-h-screen bg-transparent backdrop-blur-sm z-50'
|
|
55
74
|
)}
|
|
56
75
|
>
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
setOpen(false)
|
|
65
|
-
}}
|
|
66
|
-
className='w-auto h-auto rounded-full bg-level-1 p-2 md:p-4'
|
|
67
|
-
>
|
|
68
|
-
<ChevronLeft className='w-5 h-5'/>
|
|
69
|
-
</Button>
|
|
70
|
-
<AuthWidget/>
|
|
71
|
-
</div>
|
|
72
|
-
|
|
73
|
-
<div className='grid grid-cols-1 md:grid-cols-2 justify-center h-full overflow-y-auto md:overflow-y-hidden'>
|
|
74
|
-
<div className='flex items-center justify-center py-2'>
|
|
75
|
-
<CartPanel noCheckout className='border-none mt-10 w-full lg:w-1/2'/>
|
|
76
|
+
<div id='GRID' className='grid grid-cols-1 md:grid-cols-2 justify-center h-full overflow-y-auto md:overflow-y-hidden'>
|
|
77
|
+
<div className='bg-background flex flex-row items-start justify-end'>
|
|
78
|
+
<div className='h-full w-full max-w-[750px] relative flex flex-col items-center justify-start px-6 py-8 sm:py-20 '>
|
|
79
|
+
<CloseButton onClose={onClose} className='absolute top-2 left-4 w-auto h-auto rounded-full bg-level-1 hover:bg-level-2 hover:border-muted p-2' />
|
|
80
|
+
<AuthWidget hideLogin className='flex md:hidden absolute top-4 right-4 '/>
|
|
81
|
+
<CartPanel noCheckout className='md:border md:border-muted-2 mt-10 w-full max-w-[550px]'/>
|
|
82
|
+
</div>
|
|
76
83
|
</div>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
<Separator className='w-[4rem] sm:w-[6rem]'/>
|
|
85
|
-
<div className={cn('w-6 h-6 rounded-full border border-foreground flex flex-col justify-center items-center', currentStep === 2 ? 'bg-foreground text-muted-4' : '')}>
|
|
86
|
-
<div className='relative text-foreground top-4 h-0 whitespace-nowrap'>Delivery</div>
|
|
87
|
-
</div>
|
|
88
|
-
<Separator className='w-[4rem] sm:w-[6rem]'/>
|
|
89
|
-
<div className={cn('w-6 h-6 rounded-full border border-foreground flex flex-col justify-center items-center', currentStep === 3 ? 'bg-foreground text-muted-4' : '')}>
|
|
90
|
-
<div className='relative text-foreground top-4 h-0 whitespace-nowrap'>Done!</div>
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
{steps[currentStep - 1]}
|
|
94
|
-
</Main>
|
|
84
|
+
<div className='bg-level-1 flex flex-row items-start justify-start'>
|
|
85
|
+
<div className='h-full w-full max-w-[750px] relative flex flex-col gap-8 sm:gap-14 md:overflow-y-auto px-6 pb-6'>
|
|
86
|
+
<Toaster/>
|
|
87
|
+
<AuthWidget hideLogin className='hidden md:flex absolute top-4 right-4 '/>
|
|
88
|
+
<StepIndicator steps={steps} currentStep={step} className='flex gap-2 mx-auto items-center text-xxs sm:text-base' />
|
|
89
|
+
{steps[step].element}
|
|
90
|
+
</div>
|
|
95
91
|
</div>
|
|
96
92
|
</div>
|
|
97
93
|
</div>
|
|
@@ -21,11 +21,11 @@ const contactFormSchema = z.object({
|
|
|
21
21
|
})
|
|
22
22
|
|
|
23
23
|
const Payment: React.FC<{
|
|
24
|
-
|
|
24
|
+
setStep: (s: number) => void
|
|
25
25
|
orderId?: string
|
|
26
26
|
setOrderId: (orderId?: string) => void
|
|
27
27
|
}> = observer(({
|
|
28
|
-
|
|
28
|
+
setStep,
|
|
29
29
|
orderId,
|
|
30
30
|
setOrderId
|
|
31
31
|
}) => {
|
|
@@ -89,7 +89,7 @@ const Payment: React.FC<{
|
|
|
89
89
|
</TabsList>
|
|
90
90
|
<TabsContent value='card'>
|
|
91
91
|
<PayWithCard
|
|
92
|
-
|
|
92
|
+
setStep={setStep}
|
|
93
93
|
transactionStatus={transactionStatus}
|
|
94
94
|
setTransactionStatus={setTransactionStatus}
|
|
95
95
|
storePaymentInfo={storePaymentInfo}
|
|
@@ -98,7 +98,7 @@ const Payment: React.FC<{
|
|
|
98
98
|
</TabsContent>
|
|
99
99
|
<TabsContent value='crypto'>
|
|
100
100
|
<PayWithCrypto
|
|
101
|
-
|
|
101
|
+
setStep={setStep}
|
|
102
102
|
transactionStatus={transactionStatus}
|
|
103
103
|
setTransactionStatus={setTransactionStatus}
|
|
104
104
|
storePaymentInfo={storePaymentInfo}
|
|
@@ -106,7 +106,7 @@ const Payment: React.FC<{
|
|
|
106
106
|
</TabsContent>
|
|
107
107
|
<TabsContent value='bank'>
|
|
108
108
|
<PayWithBankTransfer
|
|
109
|
-
|
|
109
|
+
setStep={setStep}
|
|
110
110
|
storePaymentInfo={storePaymentInfo}
|
|
111
111
|
contactForm={contactForm}
|
|
112
112
|
/>
|
|
@@ -35,7 +35,7 @@ const InfoField: React.FC<{
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const PayWithBankTransfer: React.FC<{
|
|
38
|
-
|
|
38
|
+
setStep: (step: number) => void
|
|
39
39
|
storePaymentInfo: (paymentInfo: any) => Promise<void>
|
|
40
40
|
contactForm: UseFormReturn<{
|
|
41
41
|
name: string
|
|
@@ -45,14 +45,14 @@ const PayWithBankTransfer: React.FC<{
|
|
|
45
45
|
email: string
|
|
46
46
|
}>
|
|
47
47
|
}> = ({
|
|
48
|
-
|
|
48
|
+
setStep,
|
|
49
49
|
storePaymentInfo,
|
|
50
50
|
contactForm
|
|
51
51
|
}) => {
|
|
52
52
|
const payByBankTransfer = async () => {
|
|
53
53
|
contactForm.handleSubmit(async () => {
|
|
54
54
|
await storePaymentInfo({paymentMethod: 'bank-transfer'})
|
|
55
|
-
|
|
55
|
+
setStep(2)
|
|
56
56
|
})()
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -15,7 +15,7 @@ import PaymentMethods from './payment-methods'
|
|
|
15
15
|
import ContactInfo from './contact-info'
|
|
16
16
|
|
|
17
17
|
const PayWithCard: React.FC<{
|
|
18
|
-
|
|
18
|
+
setStep: (currentStep: number) => void
|
|
19
19
|
transactionStatus: TransactionStatus
|
|
20
20
|
setTransactionStatus: (status: TransactionStatus) => void
|
|
21
21
|
storePaymentInfo: (paymentInfo: any) => Promise<void>
|
|
@@ -27,7 +27,7 @@ const PayWithCard: React.FC<{
|
|
|
27
27
|
email: string
|
|
28
28
|
}>
|
|
29
29
|
}> = ({
|
|
30
|
-
|
|
30
|
+
setStep,
|
|
31
31
|
transactionStatus,
|
|
32
32
|
setTransactionStatus,
|
|
33
33
|
storePaymentInfo,
|
|
@@ -115,7 +115,7 @@ const PayWithCard: React.FC<{
|
|
|
115
115
|
<div className='flex flex-col gap-4'>
|
|
116
116
|
<h5 className='mx-auto font-nav'>Payment confirmed!</h5>
|
|
117
117
|
<p className='mx-auto'>Thank you for your purchase.</p>
|
|
118
|
-
<Button onClick={() =>
|
|
118
|
+
<Button onClick={() => setStep(2)}>Continue</Button>
|
|
119
119
|
</div>
|
|
120
120
|
) : transactionStatus === 'confirmed' ? (
|
|
121
121
|
<h6 className='mx-auto font-nav'>Processing your payment...</h6>
|
|
@@ -32,12 +32,12 @@ declare global {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
const PayWithCrypto: React.FC<{
|
|
35
|
-
|
|
35
|
+
setStep: (currentStep: number) => void
|
|
36
36
|
transactionStatus: TransactionStatus
|
|
37
37
|
setTransactionStatus: (status: TransactionStatus) => void
|
|
38
38
|
storePaymentInfo: (paymentInfo: any) => Promise<void>
|
|
39
39
|
}> = observer(({
|
|
40
|
-
|
|
40
|
+
setStep,
|
|
41
41
|
transactionStatus,
|
|
42
42
|
setTransactionStatus,
|
|
43
43
|
storePaymentInfo
|
|
@@ -151,7 +151,7 @@ const PayWithCrypto: React.FC<{
|
|
|
151
151
|
await storePaymentInfo({
|
|
152
152
|
paymentMethod: 'crypto'
|
|
153
153
|
})
|
|
154
|
-
|
|
154
|
+
setStep(2)
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
const cryptoPriceWidget = !!!(auth.user?.walletAddress) ? (
|
|
@@ -40,10 +40,10 @@ const shippingFormSchema = z.object({
|
|
|
40
40
|
|
|
41
41
|
const ShippingInfo: React.FC<{
|
|
42
42
|
orderId?: string,
|
|
43
|
-
|
|
43
|
+
setStep: (currentStep: number) => void
|
|
44
44
|
}> = ({
|
|
45
45
|
orderId,
|
|
46
|
-
|
|
46
|
+
setStep
|
|
47
47
|
}) => {
|
|
48
48
|
const auth = useAuth()
|
|
49
49
|
const cmmc = useCommerce()
|
|
@@ -66,7 +66,7 @@ const ShippingInfo: React.FC<{
|
|
|
66
66
|
if (auth.user && orderId) {
|
|
67
67
|
await cmmc.updateOrderShippingInfo(orderId, values)
|
|
68
68
|
}
|
|
69
|
-
|
|
69
|
+
setStep(3)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
return (
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { Separator } from '@hanzo/ui/primitives'
|
|
4
|
+
import { cn } from '@hanzo/ui/util'
|
|
5
|
+
|
|
6
|
+
import type { CheckoutSteps } from './step'
|
|
7
|
+
|
|
8
|
+
const StepIndicator: React.FC<{
|
|
9
|
+
steps: CheckoutSteps
|
|
10
|
+
currentStep: number
|
|
11
|
+
className?: string
|
|
12
|
+
}> = ({
|
|
13
|
+
steps,
|
|
14
|
+
currentStep,
|
|
15
|
+
className=''
|
|
16
|
+
}) => (
|
|
17
|
+
<div className={className}>
|
|
18
|
+
{Object.keys(steps).map((key, index) => (<>
|
|
19
|
+
{index !== 0 && (<Separator className='w-[4rem] sm:w-[6rem]'/>)}
|
|
20
|
+
<div className={cn(
|
|
21
|
+
'w-6 h-6 rounded-full border border-foreground flex flex-col justify-center items-center',
|
|
22
|
+
currentStep === parseInt(key) ? 'bg-foreground text-muted-4' : ''
|
|
23
|
+
)}>
|
|
24
|
+
<div className='relative text-foreground top-4 h-0 whitespace-nowrap'>{steps[parseInt(key)].label}</div>
|
|
25
|
+
</div>
|
|
26
|
+
</>))}
|
|
27
|
+
</div>
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
export default StepIndicator
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/commerce",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Library with shopping cart components.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"square": "^35.0.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@hanzo/auth": "^2.0
|
|
41
|
+
"@hanzo/auth": "^2.2.0",
|
|
42
42
|
"@hanzo/ui": "^3.0.2",
|
|
43
43
|
"@hookform/resolvers": "^3.3.4",
|
|
44
44
|
"firebase": "^10.8.0",
|