@hanzo/commerce 2.0.0 → 2.1.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.
@@ -1,13 +1,9 @@
1
1
  'use client'
2
2
 
3
- import { useEffect, useState } from 'react'
3
+ import { useState } from 'react'
4
4
  import { ChevronLeft } from 'lucide-react'
5
5
  import { observer } from 'mobx-react-lite'
6
6
 
7
- import { zodResolver } from '@hookform/resolvers/zod'
8
- import * as z from 'zod'
9
- import { useForm } from 'react-hook-form'
10
-
11
7
  import { Button, Main, Separator, Toaster } from '@hanzo/ui/primitives'
12
8
  import { cn } from '@hanzo/ui/util'
13
9
  import { useAuth } from '@hanzo/auth/service'
@@ -15,85 +11,41 @@ import { LoginComponent, AuthWidget } from '@hanzo/auth/components'
15
11
 
16
12
  import ShippingInfo from './shipping-info'
17
13
  import ThankYou from './thank-you'
18
- import PayWithCrypto from './pay-with-crypto'
19
- import PayByBankTransfer from './pay-by-bank-transfer'
20
- import ContactInfo from './contact-info'
21
14
  import { Cart } from '..'
22
- import { useCommerce } from '../../service/context'
23
-
24
- const contactFormSchema = z.object({
25
- name: z.string().min(2, 'Name must be at least 2 characters.'),
26
- email: z.string().email(),
27
- })
15
+ import Payment from './payment'
28
16
 
29
17
  const Checkout: React.FC<{toggleCheckout: () => void}> = observer(({toggleCheckout}) => {
30
18
  const auth = useAuth()
31
- const cmmc = useCommerce()
32
19
 
33
20
  const [currentStep, setCurrentStep] = useState(1)
34
- const [paymentMethod, setPaymentMethod] = useState<'crypto' | 'bank' | undefined>()
35
21
  const [orderId, setOrderId] = useState<string>()
36
22
 
37
- const contactForm = useForm<z.infer<typeof contactFormSchema>>({
38
- resolver: zodResolver(contactFormSchema),
39
- defaultValues: {
40
- name: auth.user?.displayName ?? '',
41
- email: auth.user?.email ?? '',
42
- },
43
- })
44
-
45
- useEffect(() => {
46
- if (auth.loggedIn) {
47
- contactForm.setValue('name', auth.user?.displayName ?? '')
48
- contactForm.setValue('email', auth.user?.email ?? '')
49
- }
50
- }, [auth.loggedIn])
51
-
52
- const selectPaymentMethod = async (method: 'crypto' | 'bank') => {
53
- contactForm.handleSubmit(async () => {
54
- if (auth.user) {
55
- if (!!orderId) {
56
- await cmmc.updateOrder(orderId, auth.user.email, method)
57
- } else {
58
- const id = await cmmc.createOrder(auth.user.email, method)
59
- setOrderId(id)
60
- }
61
- }
62
- setPaymentMethod(method)
63
- setCurrentStep(2)
64
- })()
65
- }
66
-
67
-
68
23
  const step1 = auth.loggedIn ? (
69
- <ContactInfo form={contactForm} selectPaymentMethod={selectPaymentMethod}/>
24
+ <Payment
25
+ orderId={orderId}
26
+ setOrderId={setOrderId}
27
+ setCurrentStep={setCurrentStep}
28
+ />
70
29
  ) : (
71
30
  <LoginComponent hideHeader className='max-w-[20rem] mx-auto'/>
72
31
  )
73
32
 
74
- const step2 = paymentMethod === 'crypto' ? (
75
- <PayWithCrypto setCurrentStep={setCurrentStep}/>
76
- ) : (
77
- <PayByBankTransfer setCurrentStep={setCurrentStep}/>
78
- )
79
-
80
- const step3 = (
81
- <ShippingInfo orderId={orderId} paymentMethod={paymentMethod} setCurrentStep={setCurrentStep}/>
33
+ const step2 = (
34
+ <ShippingInfo orderId={orderId} setCurrentStep={setCurrentStep}/>
82
35
  )
83
36
 
84
- const step4 = <ThankYou/>
37
+ const step3 = <ThankYou/>
85
38
 
86
- const steps = [step1, step2, step3, step4]
39
+ const steps = [step1, step2, step3]
87
40
 
88
41
  return (
89
- <div className="fixed top-0 left-0 !max-w-none w-full h-full min-h-screen bg-background z-[51]">
42
+ <div className="fixed top-0 left-0 !max-w-none w-full h-full min-h-screen bg-background z-50">
90
43
  <Toaster/>
91
44
  <Main className='flex flex-col gap-1 h-full'>
92
- <div className='flex justify-between'>
45
+ <div className='flex justify-between items-center'>
93
46
  <Button
94
47
  variant='ghost'
95
48
  size='icon'
96
- className='sm:ml-2 sm:mt-2'
97
49
  onClick={() => {
98
50
  setCurrentStep(0)
99
51
  toggleCheckout()
@@ -109,18 +61,18 @@ const Checkout: React.FC<{toggleCheckout: () => void}> = observer(({toggleChecko
109
61
  <Cart hideCheckout className='fixed justify-center border-none mt-10 w-1/3 max-w-[40rem]'/>
110
62
  </div>
111
63
 
112
- <div className='flex flex-col gap-8 sm:gap-14 col-span-5 md:col-span-3 max-w-[30rem] w-full mx-auto overflow-y-auto h-[calc(100%-40px)] sm:h-[calc(100%-48px)] py-4'>
64
+ <div className='flex flex-col gap-8 sm:gap-14 col-span-5 md:col-span-3 max-w-[30rem] w-full mx-auto overflow-y-auto h-[calc(100%-40px)] sm:h-[calc(100%-48px)] py-4 px-1'>
113
65
  <div className='flex gap-2 mx-auto items-center text-xxs sm:text-base'>
114
66
  <div className={cn('w-6 h-6 rounded-full border border-foreground flex flex-col justify-center items-center', currentStep === 1 ? 'bg-foreground text-muted-4' : '')}>
115
- <div className='relative text-foreground top-4 h-0 whitespace-nowrap'>Contact</div>
67
+ <div className='relative text-foreground top-4 h-0 whitespace-nowrap'>Payment</div>
116
68
  </div>
117
69
  <Separator className='w-[4rem] sm:w-[6rem]'/>
118
70
  <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' : '')}>
119
- <div className='relative text-foreground top-4 h-0 whitespace-nowrap'>Payment</div>
71
+ <div className='relative text-foreground top-4 h-0 whitespace-nowrap'>Delivery</div>
120
72
  </div>
121
73
  <Separator className='w-[4rem] sm:w-[6rem]'/>
122
74
  <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' : '')}>
123
- <div className='relative text-foreground top-4 h-0 whitespace-nowrap'>Delivery</div>
75
+ <div className='relative text-foreground top-4 h-0 whitespace-nowrap'>Done!</div>
124
76
  </div>
125
77
  </div>
126
78
  {steps[currentStep - 1]}
@@ -0,0 +1,59 @@
1
+ import {
2
+ Form,
3
+ FormControl,
4
+ FormField,
5
+ FormItem,
6
+ FormLabel,
7
+ FormMessage,
8
+ } from '@hanzo/ui/primitives/form'
9
+ import { Input } from '@hanzo/ui/primitives'
10
+ import type { UseFormReturn } from 'react-hook-form'
11
+
12
+ const ContactInfo: React.FC<{
13
+ form: UseFormReturn<{
14
+ name: string
15
+ email: string
16
+ }, any, {
17
+ name: string
18
+ email: string
19
+ }>,
20
+ }> = ({
21
+ form,
22
+ }) => {
23
+ return (
24
+ <Form {...form}>
25
+ <form className='text-left'>
26
+ <div className='flex flex-col sm:flex-row gap-2'>
27
+ <FormField
28
+ control={form.control}
29
+ name='name'
30
+ render={({ field }) => (
31
+ <FormItem className='space-y-1 w-full'>
32
+ <FormLabel>Full name</FormLabel>
33
+ <FormControl>
34
+ <Input {...field} />
35
+ </FormControl>
36
+ <FormMessage />
37
+ </FormItem>
38
+ )}
39
+ />
40
+ <FormField
41
+ control={form.control}
42
+ name='email'
43
+ render={({ field }) => (
44
+ <FormItem className='space-y-1 w-full'>
45
+ <FormLabel>Email</FormLabel>
46
+ <FormControl>
47
+ <Input {...field} />
48
+ </FormControl>
49
+ <FormMessage />
50
+ </FormItem>
51
+ )}
52
+ />
53
+ </div>
54
+ </form>
55
+ </Form>
56
+ )
57
+ }
58
+
59
+ export default ContactInfo
@@ -0,0 +1,117 @@
1
+ 'use client'
2
+
3
+ import { useEffect, useState } from 'react'
4
+ import { observer } from 'mobx-react-lite'
5
+
6
+ import { zodResolver } from '@hookform/resolvers/zod'
7
+ import * as z from 'zod'
8
+ import { useForm } from 'react-hook-form'
9
+
10
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@hanzo/ui/primitives'
11
+ import { useAuth } from '@hanzo/auth/service'
12
+ import PayWithCrypto from './pay-with-crypto'
13
+ import PayWithBankTransfer from './pay-with-bank-transfer'
14
+ import PayWithCard from './pay-with-card'
15
+ import { useCommerce, type TransactionStatus } from '../../..'
16
+
17
+ const contactFormSchema = z.object({
18
+ name: z.string().min(1, 'Enter your full name.'),
19
+ email: z.string().email(),
20
+ })
21
+
22
+ const Payment: React.FC<{
23
+ setCurrentStep: (currentStep: number) => void
24
+ orderId?: string
25
+ setOrderId: (orderId?: string) => void
26
+ }> = observer(({
27
+ setCurrentStep,
28
+ orderId,
29
+ setOrderId
30
+ }) => {
31
+ const cmmc = useCommerce()
32
+ const auth = useAuth()
33
+ const [transactionStatus, setTransactionStatus] = useState<TransactionStatus>('unpaid')
34
+
35
+ const contactForm = useForm<z.infer<typeof contactFormSchema>>({
36
+ resolver: zodResolver(contactFormSchema),
37
+ defaultValues: {
38
+ name: auth.user?.displayName ?? '',
39
+ email: auth.user?.email ?? '',
40
+ },
41
+ })
42
+
43
+ useEffect(() => {
44
+ if (auth.loggedIn) {
45
+ contactForm.setValue('name', auth.user?.displayName ?? '')
46
+ contactForm.setValue('email', auth.user?.email ?? '')
47
+ }
48
+ }, [auth.loggedIn])
49
+
50
+ const storePaymentInfo = async (paymentInfo: any) => {
51
+ if (auth.user) {
52
+ const {name, email} = contactForm.getValues()
53
+ let id
54
+ if (!orderId) {
55
+ id = await cmmc.createOrder(email ? email : auth.user.email, name)
56
+ setOrderId(id)
57
+ }
58
+ if (id) {
59
+ await cmmc.updateOrderPaymentInfo(id, paymentInfo)
60
+ }
61
+ }
62
+ }
63
+
64
+ return (
65
+ <Tabs defaultValue='card' className='w-full mx-auto max-w-[50rem]'>
66
+ <TabsList className='grid w-full grid-cols-3 mx-auto bg-level-2 h-auto'>
67
+ <TabsTrigger
68
+ value='card'
69
+ className='font-nav whitespace-normal h-full text-sm sm:text-base'
70
+ disabled={transactionStatus === 'paid' || transactionStatus === 'confirmed'}
71
+ >
72
+ PAY WITH CARD
73
+ </TabsTrigger>
74
+ <TabsTrigger
75
+ value='crypto'
76
+ className='font-nav whitespace-normal h-full text-sm sm:text-base'
77
+ disabled={transactionStatus === 'paid' || transactionStatus === 'confirmed'}
78
+ >
79
+ PAY WITH CRYPTO
80
+ </TabsTrigger>
81
+ <TabsTrigger
82
+ value='bank'
83
+ className='font-nav whitespace-normal h-full text-sm sm:text-base'
84
+ disabled={transactionStatus === 'paid' || transactionStatus === 'confirmed'}
85
+ >
86
+ BANK TRANSFER
87
+ </TabsTrigger>
88
+ </TabsList>
89
+ <TabsContent value='card'>
90
+ <PayWithCard
91
+ setCurrentStep={setCurrentStep}
92
+ transactionStatus={transactionStatus}
93
+ setTransactionStatus={setTransactionStatus}
94
+ storePaymentInfo={storePaymentInfo}
95
+ contactForm={contactForm}
96
+ />
97
+ </TabsContent>
98
+ <TabsContent value='crypto'>
99
+ <PayWithCrypto
100
+ setCurrentStep={setCurrentStep}
101
+ transactionStatus={transactionStatus}
102
+ setTransactionStatus={setTransactionStatus}
103
+ storePaymentInfo={storePaymentInfo}
104
+ />
105
+ </TabsContent>
106
+ <TabsContent value='bank'>
107
+ <PayWithBankTransfer
108
+ setCurrentStep={setCurrentStep}
109
+ storePaymentInfo={storePaymentInfo}
110
+ contactForm={contactForm}
111
+ />
112
+ </TabsContent>
113
+ </Tabs>
114
+ )
115
+ })
116
+
117
+ export default Payment
@@ -0,0 +1,106 @@
1
+ 'use client'
2
+
3
+ import type { ReactNode } from 'react'
4
+ import { Copy } from 'lucide-react'
5
+ import type { UseFormReturn } from 'react-hook-form'
6
+
7
+ import { Button, Tabs, TabsContent, TabsList, TabsTrigger, toast } from '@hanzo/ui/primitives'
8
+ import ContactInfo from './contact-info'
9
+
10
+ const InfoField: React.FC<{
11
+ label: string,
12
+ value: ReactNode,
13
+ copyValue: string
14
+ }> = ({
15
+ label,
16
+ value,
17
+ copyValue
18
+ }) => {
19
+ const copyToClipboard = (label: string, text: string) => {
20
+ navigator.clipboard.writeText(text)
21
+ toast({title: `${label} copied to clipboard`})
22
+ }
23
+
24
+ return (
25
+ <div className='flex flex-col gap-1'>
26
+ <p className='text-xs'>{label}</p>
27
+ <div className='flex items-center justify-between text-lg border rounded-lg py-2 px-4'>
28
+ {value}
29
+ <Button variant='ghost' size='icon' onClick={() => copyToClipboard(label, copyValue)}>
30
+ <Copy className='h-4 w-4'/>
31
+ </Button>
32
+ </div>
33
+ </div>
34
+ )
35
+ }
36
+
37
+ const PayWithBankTransfer: React.FC<{
38
+ setCurrentStep: (step: number) => void
39
+ storePaymentInfo: (paymentInfo: any) => Promise<void>
40
+ contactForm: UseFormReturn<{
41
+ name: string
42
+ email: string
43
+ }, any, {
44
+ name: string
45
+ email: string
46
+ }>
47
+ }> = ({
48
+ setCurrentStep,
49
+ storePaymentInfo,
50
+ contactForm
51
+ }) => {
52
+ const payByBankTransfer = async () => {
53
+ contactForm.handleSubmit(async () => {
54
+ await storePaymentInfo({paymentMethod: 'bank-transfer'})
55
+ setCurrentStep(2)
56
+ })()
57
+ }
58
+
59
+ return (
60
+ <div className='flex flex-col gap-6 mt-6'>
61
+ <ContactInfo form={contactForm}/>
62
+ <Tabs defaultValue="usd" className='w-full mx-auto max-w-[50rem]'>
63
+ <TabsList className="grid w-full grid-cols-2 max-w-[15rem] mx-auto bg-level-2">
64
+ <TabsTrigger value="usd">USD</TabsTrigger>
65
+ <TabsTrigger value="eur">EUR/GBP</TabsTrigger>
66
+ </TabsList>
67
+ <TabsContent value="usd">
68
+ <div className='flex flex-col gap-4 w-full'>
69
+ <InfoField
70
+ label='Beneficiary Bank'
71
+ value={<div>Bank of America<br/>NA 222 Broadway<br/>New York, New York. 10038</div>}
72
+ copyValue='Bank of America, NA 222 Broadway, New York, New York. 10038'
73
+ />
74
+ <InfoField
75
+ label='Beneficiary'
76
+ value={<div>Hanzo, Inc<br/>4811 Mastin Street<br/>Merriam, KS 66203</div>}
77
+ copyValue='Hanzo, Inc, 4811 Mastin Street, Merriam, KS 66203'
78
+ />
79
+ <InfoField label='Routing Number - ACH' value='113000023 / 111000025' copyValue='113000023 / 111000025'/>
80
+ <InfoField label='Routing Number - Wire' value='026009593' copyValue='026009593'/>
81
+ <InfoField label='Routing Number - SWIFT' value='BOFAUS3N' copyValue='BOFAUS3N'/>
82
+ <InfoField label='Reference' value='Lux' copyValue='Lux'/>
83
+ </div>
84
+ </TabsContent>
85
+ <TabsContent value="eur">
86
+ <div className='flex flex-col gap-4 w-full'>
87
+ <InfoField
88
+ label='Beneficiary Bank'
89
+ value={<div>Clear Junction Limited<br/>4th floor<br/>Imperial House</div>}
90
+ copyValue='Clear Junction Limited, 4th floor, Imperial House'
91
+ />
92
+ <InfoField label='Account Number (GBP)' value='33781813' copyValue='33781813'/>
93
+ <InfoField label='Account Name' value='AiDLT Global Ltd.' copyValue='AiDLT Global Ltd.'/>
94
+ <InfoField label='SWIFT/BIC' value='CLJUGB21' copyValue='CLJUGB21'/>
95
+ <InfoField label='Sort Code (GBP)' value='041307' copyValue='041307'/>
96
+ <InfoField label='IBAN' value='GB75 CLJU 0413 0733 78181 3' copyValue='GB75 CLJU 0413 0733 78181 3'/>
97
+ <InfoField label='Reference' value='Lux' copyValue='Lux'/>
98
+ </div>
99
+ </TabsContent>
100
+ </Tabs>
101
+ <Button onClick={payByBankTransfer} className='mx-auto w-full mt-4'>Continue</Button>
102
+ </div>
103
+ )
104
+ }
105
+
106
+ export default PayWithBankTransfer
@@ -0,0 +1,193 @@
1
+ 'use client'
2
+
3
+ // @ts-ignore
4
+ import { ApplePay, GooglePay, CreditCard, PaymentForm } from 'react-square-web-payments-sdk'
5
+ import type { UseFormReturn } from 'react-hook-form'
6
+ import { ApplyTypography, Button } from '@hanzo/ui/primitives'
7
+ import { useCommerce, type TransactionStatus } from '../../..'
8
+ import PaymentMethods from './payment-methods'
9
+ import { processSquareCardPayment } from '../../../util'
10
+ import ContactInfo from './contact-info'
11
+
12
+ const PayWithCard: React.FC<{
13
+ setCurrentStep: (currentStep: number) => void
14
+ transactionStatus: TransactionStatus
15
+ setTransactionStatus: (status: TransactionStatus) => void
16
+ storePaymentInfo: (paymentInfo: any) => Promise<void>
17
+ contactForm: UseFormReturn<{
18
+ name: string
19
+ email: string
20
+ }, any, {
21
+ name: string
22
+ email: string
23
+ }>
24
+ }> = ({
25
+ setCurrentStep,
26
+ transactionStatus,
27
+ setTransactionStatus,
28
+ storePaymentInfo,
29
+ contactForm,
30
+ }) => {
31
+ const cmmc = useCommerce()
32
+
33
+ const cardTokenizeResponseReceived = async (
34
+ token: any,
35
+ verifiedBuyer: any
36
+ ) => {
37
+ contactForm.handleSubmit(async () => {
38
+ setTransactionStatus('paid')
39
+ const res = await processSquareCardPayment(token.token, cmmc.cartTotal, verifiedBuyer.token)
40
+ if (res) {
41
+ console.log(token)
42
+ await storePaymentInfo({paymentMethod: token.details.method ?? null, processed: res})
43
+ setTransactionStatus('confirmed')
44
+ } else {
45
+ setTransactionStatus('error')
46
+ }
47
+ })()
48
+ }
49
+
50
+ const createVerificationDetails = () => {
51
+ const {name, email} = contactForm.getValues()
52
+ return {
53
+ amount: cmmc.cartTotal.toFixed(2),
54
+ billingContact: {
55
+ givenName: name,
56
+ email,
57
+ },
58
+ currencyCode: 'USD',
59
+ intent: 'CHARGE',
60
+ }
61
+ }
62
+
63
+ const createPaymentRequest= () => ({
64
+ countryCode: "US",
65
+ currencyCode: "USD",
66
+ lineItems: cmmc.cartItems.map(item => ({
67
+ amount: item.price.toFixed(2),
68
+ label: item.title,
69
+ id: item.sku,
70
+ })),
71
+ requestBillingContact: false,
72
+ requestShippingContact: false,
73
+ total: {
74
+ amount: cmmc.cartTotal.toFixed(2),
75
+ label: "Total",
76
+ },
77
+ })
78
+
79
+ return (
80
+ <PaymentForm
81
+ /**
82
+ * Identifies the calling form with a verified application ID generated from
83
+ * the Square Application Dashboard.
84
+ */
85
+ applicationId={process.env.NEXT_PUBLIC_SQUARE_APPLICATION_ID}
86
+ /**
87
+ * Invoked when payment form receives the result of a tokenize generation
88
+ * request. The result will be a valid credit card or wallet token, or an error.
89
+ */
90
+ cardTokenizeResponseReceived={cardTokenizeResponseReceived}
91
+ /**
92
+ * This function enable the Strong Customer Authentication (SCA) flow
93
+ *
94
+ * We strongly recommend use this function to verify the buyer and reduce
95
+ * the chance of fraudulent transactions.
96
+ */
97
+ createVerificationDetails={createVerificationDetails}
98
+ /**
99
+ * This function is required for digital wallets (Apple Pay, Google Pay)
100
+ */
101
+ createPaymentRequest={createPaymentRequest}
102
+ /**
103
+ * Identifies the location of the merchant that is taking the payment.
104
+ * Obtained from the Square Application Dashboard - Locations tab.
105
+ */
106
+ locationId={process.env.NEXT_PUBLIC_SQUARE_LOCATION_ID}
107
+ >
108
+ <div className='flex flex-col gap-2 mt-6'>
109
+ {transactionStatus === 'confirmed' ? (
110
+ <ApplyTypography className='flex flex-col gap-4'>
111
+ <h5 className='mx-auto font-nav'>Payment confirmed!</h5>
112
+ <p className='mx-auto'>Thank you for your purchase.</p>
113
+ <Button onClick={() => setCurrentStep(2)}>Continue</Button>
114
+ </ApplyTypography>
115
+ ) : transactionStatus === 'paid' ? (
116
+ <ApplyTypography className='flex flex-col gap-4'>
117
+ <h5 className='mx-auto font-nav'>Processing your payment...</h5>
118
+ </ApplyTypography>
119
+ ) : (
120
+ <>
121
+ <GooglePay/>
122
+ <ApplePay/>
123
+
124
+ <p className='flex gap-2 whitespace-nowrap items-center my-6 sm:my-10 text-sm text-foreground/60'>
125
+ <hr className='bg-foreground/60 w-full border'/> or pay with card <hr className='bg-foreground/60 w-full border'/>
126
+ </p>
127
+
128
+ <ContactInfo form={contactForm}/>
129
+
130
+ <PaymentMethods/>
131
+
132
+ {/* Imitates hanzo/ui Button and Input styles, I was unable to render the
133
+ hanzo/ui button outright and keeping the submit form functionality*/}
134
+ <CreditCard
135
+ style={{
136
+ '.input-container': {
137
+ borderColor: '#2D2D2D',
138
+ borderRadius: '6px',
139
+ },
140
+ '.input-container.is-focus': {
141
+ borderColor: '#ffffff',
142
+ },
143
+ '.input-container.is-error': {
144
+ borderColor: '#ff1600',
145
+ },
146
+ '.message-text': {
147
+ color: '#999999',
148
+ },
149
+ '.message-icon': {
150
+ color: '#999999',
151
+ },
152
+ '.message-text.is-error': {
153
+ color: '#ff1600',
154
+ },
155
+ '.message-icon.is-error': {
156
+ color: '#ff1600',
157
+ },
158
+ input: {
159
+ backgroundColor: '#000000',
160
+ color: '#FFFFFF',
161
+ },
162
+ 'input::placeholder': {
163
+ color: '#999999',
164
+ },
165
+ 'input.is-error': {
166
+ color: '#ff1600',
167
+ },
168
+ }}
169
+ buttonProps={{
170
+ className: 'font-nav h-10',
171
+ css: {
172
+ backgroundColor: '#fff',
173
+ color: '#000',
174
+ padding: 0,
175
+ '&:hover': {
176
+ backgroundColor: '#ffffffd9',
177
+ },
178
+ },
179
+ }}
180
+ />
181
+ {transactionStatus === 'error' && (
182
+ <ApplyTypography>
183
+ <p className='mx-auto text-destructive'>There was an error processing your payment.</p>
184
+ </ApplyTypography>
185
+ )}
186
+ </>
187
+ )}
188
+ </div>
189
+ </PaymentForm>
190
+ )
191
+ }
192
+
193
+ export default PayWithCard