@hanzo/commerce 4.4.0 → 4.4.1

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.
@@ -13,8 +13,7 @@ import {
13
13
  Toaster
14
14
  } from '@hanzo/ui/primitives'
15
15
  import { cn } from '@hanzo/ui/util'
16
- import { useAuth } from '@hanzo/auth/service'
17
- import { LoginComponent, AuthWidget } from '@hanzo/auth/components'
16
+ import { AuthWidget } from '@hanzo/auth/components'
18
17
 
19
18
  import ShippingInfo from './shipping-info'
20
19
  import ThankYou from './thank-you'
@@ -33,7 +32,6 @@ const CheckoutPanel: React.FC<{
33
32
  setOpen
34
33
  }) => {
35
34
 
36
- const auth = useAuth()
37
35
  const cmmc = useCommerce()
38
36
 
39
37
  const [step, setStep] = useState<number>(1)
@@ -43,17 +41,11 @@ const CheckoutPanel: React.FC<{
43
41
  1: {
44
42
  label: 'Payment',
45
43
  element: (
46
- auth.loggedIn ? (
47
- <Payment
48
- orderId={orderId}
49
- setOrderId={setOrderId}
50
- setStep={setStep}
51
- />
52
- ) : (
53
- <LoginComponent hideHeader className='max-w-[20rem] mx-auto' inputClassName='border-muted-4'>
54
- <h6 className='font-nav'>Please login to proceed</h6>
55
- </LoginComponent >
56
- )
44
+ <Payment
45
+ orderId={orderId}
46
+ setOrderId={setOrderId}
47
+ setStep={setStep}
48
+ />
57
49
  )}
58
50
  ,
59
51
  2: {
@@ -49,16 +49,14 @@ const Payment: React.FC<{
49
49
  }, [auth.loggedIn])
50
50
 
51
51
  const storePaymentInfo = async (paymentInfo: any) => {
52
- if (auth.user) {
53
- const {name, email} = contactForm.getValues()
54
- let id
55
- if (!orderId) {
56
- id = await cmmc.createOrder(email ? email : auth.user.email, name)
57
- setOrderId(id)
58
- }
59
- if (id) {
60
- await cmmc.updateOrderPaymentInfo(id, paymentInfo)
61
- }
52
+ const {name, email} = contactForm.getValues()
53
+ let id
54
+ if (!orderId) {
55
+ id = await cmmc.createOrder(email, name)
56
+ setOrderId(id)
57
+ }
58
+ if (id) {
59
+ await cmmc.updateOrderPaymentInfo(id, paymentInfo)
62
60
  }
63
61
  }
64
62
 
@@ -67,21 +65,21 @@ const Payment: React.FC<{
67
65
  <TabsList className='grid w-full grid-cols-3 mx-auto bg-level-2 h-auto'>
68
66
  <TabsTrigger
69
67
  value='card'
70
- className='font-nav whitespace-normal h-full text-sm sm:text-base'
68
+ className='whitespace-normal h-full text-sm sm:text-base'
71
69
  disabled={transactionStatus === 'paid' || transactionStatus === 'confirmed'}
72
70
  >
73
71
  PAY WITH CARD
74
72
  </TabsTrigger>
75
73
  <TabsTrigger
76
74
  value='crypto'
77
- className='font-nav whitespace-normal h-full text-sm sm:text-base'
75
+ className='whitespace-normal h-full text-sm sm:text-base'
78
76
  disabled={transactionStatus === 'paid' || transactionStatus === 'confirmed'}
79
77
  >
80
78
  PAY WITH CRYPTO
81
79
  </TabsTrigger>
82
80
  <TabsTrigger
83
81
  value='bank'
84
- className='font-nav whitespace-normal h-full text-sm sm:text-base'
82
+ className='whitespace-normal h-full text-sm sm:text-base'
85
83
  disabled={transactionStatus === 'paid' || transactionStatus === 'confirmed'}
86
84
  >
87
85
  BANK TRANSFER
@@ -102,6 +100,7 @@ const Payment: React.FC<{
102
100
  transactionStatus={transactionStatus}
103
101
  setTransactionStatus={setTransactionStatus}
104
102
  storePaymentInfo={storePaymentInfo}
103
+ contactForm={contactForm}
105
104
  />
106
105
  </TabsContent>
107
106
  <TabsContent value='bank'>
@@ -112,13 +112,13 @@ const PayWithCard: React.FC<{
112
112
  >
113
113
  <ApplyTypography className='flex flex-col gap-2 mt-6'>
114
114
  {transactionStatus === 'paid' ? (
115
+ <h6 className='mx-auto font-nav'>Processing your payment...</h6>
116
+ ) : transactionStatus === 'confirmed' ? (
115
117
  <div className='flex flex-col gap-4'>
116
118
  <h5 className='mx-auto font-nav'>Payment confirmed!</h5>
117
119
  <p className='mx-auto'>Thank you for your purchase.</p>
118
120
  <Button onClick={() => setStep(2)}>Continue</Button>
119
121
  </div>
120
- ) : transactionStatus === 'confirmed' ? (
121
- <h6 className='mx-auto font-nav'>Processing your payment...</h6>
122
122
  ) : (
123
123
  <>
124
124
  <GooglePay/>
@@ -24,6 +24,9 @@ import { Ethereum as EthIconFromAuth } from '@hanzo/auth/icons'
24
24
  import Eth from '../icons/eth'
25
25
  import { useCommerce } from '../../../service/context'
26
26
  import type { TransactionStatus } from '../../../types'
27
+ import ContactInfo from './contact-info'
28
+ import type { UseFormReturn } from 'react-hook-form'
29
+ import { LoginComponent } from '@hanzo/auth/components'
27
30
 
28
31
  declare global {
29
32
  interface Window{
@@ -36,11 +39,19 @@ const PayWithCrypto: React.FC<{
36
39
  transactionStatus: TransactionStatus
37
40
  setTransactionStatus: (status: TransactionStatus) => void
38
41
  storePaymentInfo: (paymentInfo: any) => Promise<void>
42
+ contactForm: UseFormReturn<{
43
+ name: string
44
+ email: string
45
+ }, any, {
46
+ name: string
47
+ email: string
48
+ }>
39
49
  }> = observer(({
40
50
  setStep,
41
51
  transactionStatus,
42
52
  setTransactionStatus,
43
- storePaymentInfo
53
+ storePaymentInfo,
54
+ contactForm
44
55
  }) => {
45
56
  const c = useCommerce()
46
57
  const auth = useAuth()
@@ -90,61 +101,69 @@ const PayWithCrypto: React.FC<{
90
101
  }, [c.cartTotal])
91
102
 
92
103
  const sendPayment = async (ether: number) => {
93
- // Check that we are on ethereum network
94
- try {
95
- await window.ethereum.request({
96
- method: 'wallet_switchEthereumChain',
97
- params: [{ chainId: "0x1"}],
98
- })
99
- const newProvider = new ethers.BrowserProvider(window.ethereum)
100
- setProvider(newProvider)
101
- if (auth.user?.walletAddress) {
102
- newProvider.getBalance(auth.user?.walletAddress).then((balance: any) => {
103
- setAvailableAmount(Number(balance)/(10**18))
104
+ contactForm.handleSubmit(async () => {
105
+ // Check that we are on ethereum network
106
+ try {
107
+ await window.ethereum.request({
108
+ method: 'wallet_switchEthereumChain',
109
+ params: [{ chainId: "0x1"}],
104
110
  })
111
+ const newProvider = new ethers.BrowserProvider(window.ethereum)
112
+ setProvider(newProvider)
113
+ if (auth.user?.walletAddress) {
114
+ newProvider.getBalance(auth.user?.walletAddress).then((balance: any) => {
115
+ setAvailableAmount(Number(balance)/(10**18))
116
+ })
117
+ }
118
+ } catch (err) {
119
+ toast({title: 'Please switch your wallet to the Ethereum network.'})
120
+ return
105
121
  }
106
- } catch (err) {
107
- toast({title: 'Please switch your wallet to the Ethereum network.'})
108
- return
109
- }
110
122
 
111
- try {
112
- if (!provider) {
113
- // :aa TODO string table
114
- throw new Error('No crypto wallet found. Please install it.')
115
- }
116
-
117
- await window.ethereum.send('eth_requestAccounts')
118
-
119
- const signer = await provider.getSigner()
120
- ethers.getAddress(process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS ?? '')
121
- const tx = await signer.sendTransaction({
122
- to: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS,
123
- value: ethers.parseEther(ether.toString())
124
- })
125
- console.log({ ether, addr: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS })
126
- console.log('tx', tx)
127
- setTransactionStatus('paid')
128
-
129
- provider.waitForTransaction(tx.hash)
130
- .then(async (receipt) => {
131
- console.log(receipt)
132
- await storePaymentInfo({
133
- ether,
134
- addr: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS,
135
- receipt
136
- })
137
- setTransactionStatus('confirmed')
123
+ try {
124
+ if (!provider) {
125
+ // :aa TODO string table
126
+ throw new Error('No crypto wallet found. Please install it.')
127
+ }
128
+
129
+ await window.ethereum.send('eth_requestAccounts')
130
+
131
+ const signer = await provider.getSigner()
132
+ ethers.getAddress(process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS ?? '')
133
+ const tx = await signer.sendTransaction({
134
+ to: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS,
135
+ value: ethers.parseEther(ether.toString())
138
136
  })
139
- .catch((error) => {
140
- console.error(error)
141
- setTransactionStatus('error')
137
+ console.log({ ether, addr: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS })
138
+ console.log('tx', tx)
139
+ setTransactionStatus('paid')
140
+ await storePaymentInfo({
141
+ ether,
142
+ transactionHash: tx.hash,
143
+ to: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS,
144
+ paymentMethod: 'crypto'
142
145
  })
143
- } catch (err) {
144
- console.log(err)
145
- // :aa TODO string table
146
- toast({title: 'Not enough funds in your wallet'})
147
- }
146
+
147
+ provider.waitForTransaction(tx.hash)
148
+ .then(async (receipt) => {
149
+ console.log(receipt)
150
+ await storePaymentInfo({
151
+ ether,
152
+ addr: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS,
153
+ receipt
154
+ })
155
+ setTransactionStatus('confirmed')
156
+ })
157
+ .catch((error) => {
158
+ console.error(error)
159
+ setTransactionStatus('error')
160
+ })
161
+ } catch (err) {
162
+ console.log(err)
163
+ // :aa TODO string table
164
+ toast({title: 'Not enough funds in your wallet'})
165
+ }
166
+ })()
148
167
  }
149
168
 
150
169
  const nextStep = async () => {
@@ -154,69 +173,57 @@ const PayWithCrypto: React.FC<{
154
173
  setStep(2)
155
174
  }
156
175
 
157
- const cryptoPriceWidget = !!!(auth.user?.walletAddress) ? (
158
- <div className='w-full mx-auto max-w-[20rem]'>
159
- <Button
160
- variant='outline'
161
- className='w-full flex items-center gap-2'
162
- onClick={auth.associateWallet.bind(auth)}
163
- >
164
- <EthIconFromAuth height={20}/>Connect your wallet
165
- </Button>
166
- </div>
167
- ) : (
168
- <div className='flex flex-col gap-2 w-full'>
169
- <div className='flex gap-2 grid grid-cols-3'>
170
- <Select onValueChange={(token) => {/*ONLY ETH setSelectedToken(token) */}} defaultValue='eth'>
171
- <SelectTrigger>
172
- <SelectValue defaultValue='eth' className='border-muted-4'/>
173
- </SelectTrigger>
174
- <SelectContent>
175
- <SelectGroup>
176
- <SelectItem value='eth'><div className='flex items-center gap-2'><Eth height={14}/>ETH</div></SelectItem>
177
- {/* <SelectItem value='btc' ><div className='flex items-center gap-2'><Btc height={14}/>BTC</div></SelectItem>
178
- <SelectItem value='usdt' ><div className='flex items-center gap-2'><Usdt height={14}/>USDT</div></SelectItem> */}
179
- </SelectGroup>
180
- </SelectContent>
181
- </Select>
182
- <div className='col-span-2'>
183
- <Input
184
- value={amount ? amount/(10**18) : amount}
185
- contentEditable={false}
186
- className='border-muted-4'
187
- />
188
- <div className='relative flex items-center gap-2 -top-[32px] justify-end px-2 py-1 rounded-lg bg-muted-4 w-fit text-xs float-right mr-3'>
189
- <Eth height={10}/>
190
- ETH
176
+ return (
177
+ <div className='flex flex-col gap-6 mt-6'>
178
+ <div className='flex flex-col gap-2 w-full'>
179
+ <ContactInfo form={contactForm}/>
180
+ <div className='flex gap-2 grid grid-cols-3'>
181
+ <Select onValueChange={(token) => {/*ONLY ETH setSelectedToken(token) */}} defaultValue='eth'>
182
+ <SelectTrigger>
183
+ <SelectValue defaultValue='eth' className='border-muted-4'/>
184
+ </SelectTrigger>
185
+ <SelectContent>
186
+ <SelectGroup>
187
+ <SelectItem value='eth'><div className='flex items-center gap-2'><Eth height={14}/>ETH</div></SelectItem>
188
+ {/* <SelectItem value='btc' ><div className='flex items-center gap-2'><Btc height={14}/>BTC</div></SelectItem>
189
+ <SelectItem value='usdt' ><div className='flex items-center gap-2'><Usdt height={14}/>USDT</div></SelectItem> */}
190
+ </SelectGroup>
191
+ </SelectContent>
192
+ </Select>
193
+ <div className='col-span-2'>
194
+ <Input
195
+ value={amount ? amount/(10**18) : amount}
196
+ contentEditable={false}
197
+ className='border-muted-4'
198
+ />
199
+ <div className='relative flex items-center gap-2 -top-[32px] justify-end px-2 py-1 rounded-lg bg-muted-4 w-fit text-xs float-right mr-3'>
200
+ <Eth height={10}/>
201
+ ETH
202
+ </div>
191
203
  </div>
192
204
  </div>
205
+ <div>Available funds in your wallet: {availableAmount} ETH</div>
206
+
207
+ {transactionStatus === 'error' ? (
208
+ <h4 className='text-destructive'>There was an error while confirming the transaction.</h4>
209
+ ) : transactionStatus === 'paid' ? (
210
+ <h4>Waiting for transaction to be confirmed on chain.</h4>
211
+ ) : transactionStatus === 'confirmed' ? (
212
+ <h4>Transaction confirmed!</h4>
213
+ ) : null}
214
+
215
+ {transactionStatus === 'unpaid' ? (
216
+ <Button
217
+ onClick={() => sendPayment(amount ? amount/(10**18) : 0)}
218
+ className='mx-auto w-full'
219
+ disabled={loadingPrice}
220
+ >
221
+ Pay
222
+ </Button>
223
+ ) : (
224
+ <Button onClick={nextStep} className='mx-auto w-full'>Continue</Button>
225
+ )}
193
226
  </div>
194
- <div>Available funds in your wallet: {availableAmount} ETH</div>
195
-
196
- {transactionStatus === 'error' ? (
197
- <h4 className='text-destructive'>There was an error while confirming the transaction.</h4>
198
- ) : transactionStatus === 'paid' ? (
199
- <h4>Waiting for transaction to be confirmed on chain.</h4>
200
- ) : transactionStatus === 'confirmed' ? (
201
- <h4>Transaction confirmed!</h4>
202
- ) : null}
203
- </div>
204
- )
205
-
206
- return (
207
- <div className='flex flex-col gap-6 mt-6'>
208
- {cryptoPriceWidget}
209
- {transactionStatus === 'unpaid' ? (
210
- <Button
211
- onClick={() => sendPayment(amount ? amount/(10**18) : 0)}
212
- className='mx-auto w-full'
213
- disabled={loadingPrice}
214
- >
215
- Pay
216
- </Button>
217
- ) : (
218
- <Button onClick={nextStep} className='mx-auto w-full'>Continue</Button>
219
- )}
220
227
  </div>
221
228
  )
222
229
  })
@@ -28,8 +28,6 @@ import { useCommerce } from '../..'
28
28
  import { countries } from './countries'
29
29
 
30
30
  const shippingFormSchema = z.object({
31
- firstName: z.string().min(2, 'First name must be at least 2 characters.'),
32
- lastName: z.string().min(2, 'Last name must be at least 2 characters.'),
33
31
  addressLine1: z.string().min(2, 'Address must be at least 2 characters.'),
34
32
  addressLine2: z.string().optional(),
35
33
  zipCode: z.string().min(2, 'Zip code is invalid.'),
@@ -51,8 +49,6 @@ const ShippingInfo: React.FC<{
51
49
  const shippingForm = useForm<z.infer<typeof shippingFormSchema>>({
52
50
  resolver: zodResolver(shippingFormSchema),
53
51
  defaultValues: {
54
- firstName: '',
55
- lastName: '',
56
52
  addressLine1: '',
57
53
  addressLine2: '',
58
54
  zipCode: '',
@@ -63,7 +59,7 @@ const ShippingInfo: React.FC<{
63
59
  })
64
60
 
65
61
  const onSubmit = async (values: z.infer<typeof shippingFormSchema>) => {
66
- if (auth.user && orderId) {
62
+ if (orderId) {
67
63
  await cmmc.updateOrderShippingInfo(orderId, values)
68
64
  }
69
65
  setStep(3)
@@ -73,62 +69,32 @@ const ShippingInfo: React.FC<{
73
69
  <Form {...shippingForm}>
74
70
  <form onSubmit={shippingForm.handleSubmit(onSubmit)} className='text-left'>
75
71
  <div className='flex flex-col gap-4'>
76
- <div className='flex gap-4 items-end'>
77
- <FormField
78
- control={shippingForm.control}
79
- name='firstName'
80
- render={({ field }) => (
81
- <FormItem className='space-y-1 w-full'>
82
- <FormLabel>First name</FormLabel>
83
- <FormControl>
84
- <Input {...field} className='border-muted-4'/>
85
- </FormControl>
86
- <FormMessage />
87
- </FormItem>
88
- )}
89
- />
90
- <FormField
91
- control={shippingForm.control}
92
- name='lastName'
93
- render={({ field }) => (
94
- <FormItem className='space-y-1 w-full'>
95
- <FormLabel>Last name</FormLabel>
96
- <FormControl>
97
- <Input {...field} className='border-muted-4'/>
98
- </FormControl>
99
- <FormMessage />
100
- </FormItem>
101
- )}
102
- />
103
- </div>
104
- <div className='flex gap-4 items-end'>
105
- <FormField
106
- control={shippingForm.control}
107
- name='addressLine1'
108
- render={({ field }) => (
109
- <FormItem className='space-y-1 w-full'>
110
- <FormLabel>Address line 1</FormLabel>
111
- <FormControl>
112
- <Input {...field} className='border-muted-4'/>
113
- </FormControl>
114
- <FormMessage />
115
- </FormItem>
116
- )}
117
- />
118
- <FormField
119
- control={shippingForm.control}
120
- name='addressLine2'
121
- render={({ field }) => (
122
- <FormItem className='space-y-1 w-full'>
123
- <FormLabel>Address line 2 (optional)</FormLabel>
124
- <FormControl>
125
- <Input {...field} className='border-muted-4'/>
126
- </FormControl>
127
- <FormMessage />
128
- </FormItem>
129
- )}
130
- />
131
- </div>
72
+ <FormField
73
+ control={shippingForm.control}
74
+ name='addressLine1'
75
+ render={({ field }) => (
76
+ <FormItem className='space-y-1 w-full'>
77
+ <FormLabel>Address line 1</FormLabel>
78
+ <FormControl>
79
+ <Input {...field} className='border-muted-4'/>
80
+ </FormControl>
81
+ <FormMessage />
82
+ </FormItem>
83
+ )}
84
+ />
85
+ <FormField
86
+ control={shippingForm.control}
87
+ name='addressLine2'
88
+ render={({ field }) => (
89
+ <FormItem className='space-y-1 w-full'>
90
+ <FormLabel>Address line 2 (optional)</FormLabel>
91
+ <FormControl>
92
+ <Input {...field} className='border-muted-4'/>
93
+ </FormControl>
94
+ <FormMessage />
95
+ </FormItem>
96
+ )}
97
+ />
132
98
  <div className='flex gap-4 items-end'>
133
99
  <FormField
134
100
  control={shippingForm.control}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/commerce",
3
- "version": "4.4.0",
3
+ "version": "4.4.1",
4
4
  "description": "Library with shopping cart components.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",