@hanzo/commerce 7.3.0 → 7.3.2

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.
Files changed (83) hide show
  1. package/components/Icons.tsx +34 -34
  2. package/components/add-to-cart-widget.tsx +183 -183
  3. package/components/buy/buy-card.tsx +259 -259
  4. package/components/buy/carousel-buy-card.tsx +242 -242
  5. package/components/buy/multi-family/all-variants-carousel.tsx +261 -261
  6. package/components/buy/multi-family/family-carousel/index.tsx +77 -77
  7. package/components/buy/multi-family/family-carousel/slide.tsx +83 -83
  8. package/components/buy/multi-family/family-carousel/state.ts +87 -87
  9. package/components/buy/multi-family/index.ts +2 -2
  10. package/components/buy/single-family-selector.tsx +90 -90
  11. package/components/buy/title-and-byline.tsx +25 -25
  12. package/components/cart/cart-panel/cart-line-item.tsx +76 -76
  13. package/components/cart/cart-panel/index.tsx +154 -154
  14. package/components/cart/cart-panel/promo-code.tsx +106 -106
  15. package/components/cart/cart-panel/total-area.tsx +60 -60
  16. package/components/checkout/payment-step-form/card-icon-row.tsx +26 -26
  17. package/components/checkout/payment-step-form/card-icons/amex.tsx +32 -32
  18. package/components/checkout/payment-step-form/card-icons/diners-club.tsx +13 -13
  19. package/components/checkout/payment-step-form/card-icons/discover.tsx +25 -25
  20. package/components/checkout/payment-step-form/card-icons/jcb.tsx +26 -26
  21. package/components/checkout/payment-step-form/card-icons/mastercard.tsx +27 -27
  22. package/components/checkout/payment-step-form/card-icons/visa.tsx +25 -25
  23. package/components/checkout/payment-step-form/cc-button.tsx +17 -17
  24. package/components/checkout/payment-step-form/contact-form.tsx +49 -49
  25. package/components/checkout/payment-step-form/crypto-icons/btc.tsx +11 -11
  26. package/components/checkout/payment-step-form/crypto-icons/eth.tsx +20 -20
  27. package/components/checkout/payment-step-form/crypto-icons/usdt.tsx +13 -13
  28. package/components/checkout/payment-step-form/index.tsx +122 -122
  29. package/components/checkout/payment-step-form/methods/bank-transfer.tsx +79 -79
  30. package/components/checkout/payment-step-form/methods/card.tsx +232 -232
  31. package/components/checkout/payment-step-form/methods/crypto.tsx +227 -227
  32. package/components/checkout/payment-step-form/methods/index.ts +22 -22
  33. package/components/checkout/shipping-step-form.tsx +172 -172
  34. package/components/index.ts +11 -11
  35. package/components/item/product-card.tsx +48 -48
  36. package/components/item-selector/button.tsx +188 -188
  37. package/components/item-selector/carousel/index.tsx +197 -197
  38. package/components/item-selector/carousel/slider.tsx +40 -40
  39. package/components/item-selector/index.ts +5 -5
  40. package/components/item-selector/quantity-indicator.tsx +48 -48
  41. package/components/node-tabs/index.tsx +91 -91
  42. package/components/node-tabs/node-image.tsx +31 -31
  43. package/index.ts +12 -12
  44. package/package.json +60 -60
  45. package/service/context.tsx +45 -45
  46. package/service/debug.ts +41 -41
  47. package/service/impls/standalone/actual-line-item.ts +135 -135
  48. package/service/impls/standalone/get-instance.ts +64 -64
  49. package/service/impls/standalone/index.ts +579 -579
  50. package/service/impls/standalone/order/firebase.ts +14 -14
  51. package/service/impls/standalone/order/index.ts +128 -128
  52. package/service/impls/standalone/persistence.ts +33 -33
  53. package/service/path-utils.ts +25 -25
  54. package/service/sep.ts +6 -6
  55. package/tsconfig.json +10 -10
  56. package/types/README.md +1 -1
  57. package/types/category-node.ts +49 -49
  58. package/types/checkout.ts +46 -46
  59. package/types/commerce-config.ts +13 -13
  60. package/types/commerce-service.ts +127 -127
  61. package/types/family.ts +25 -25
  62. package/types/index.ts +15 -15
  63. package/types/item-selector.ts +96 -96
  64. package/types/line-item.ts +29 -29
  65. package/types/multi-family-selector-props.ts +19 -19
  66. package/types/product.ts +20 -20
  67. package/types/promo.ts +9 -9
  68. package/types/selection-ui-specifier.ts +51 -51
  69. package/types/string-mutator.ts +13 -13
  70. package/types/token-separators.ts +7 -7
  71. package/util/analytics.ts +20 -20
  72. package/util/countries.ts +195 -195
  73. package/util/error.ts +34 -34
  74. package/util/index.ts +70 -70
  75. package/util/item-selector-options-accessor.ts +34 -34
  76. package/util/line-item-ref.ts +23 -23
  77. package/util/multi-family-selector-options-accessor.ts +14 -14
  78. package/util/obs-string-mutator.ts +22 -22
  79. package/util/product-media-accessor.ts +58 -58
  80. package/util/promo-codes.ts +108 -108
  81. package/util/selection-ui-specifiers.ts +29 -29
  82. package/util/square-payment.ts +42 -42
  83. package/util/use-sync-sku-param-w-current-item.ts +88 -88
@@ -1,232 +1,232 @@
1
- 'use client'
2
- import React, { useEffect, useState } from 'react'
3
-
4
- // @ts-ignore
5
- import { ApplePay, GooglePay, CreditCard, PaymentForm } from 'react-square-web-payments-sdk'
6
-
7
- import { observer } from 'mobx-react-lite'
8
-
9
- import {
10
- ApplyTypography,
11
- Button,
12
- Separator,
13
- Skeleton,
14
- } from '@hanzo/ui/primitives'
15
-
16
- import { cn } from '@hanzo/ui/util'
17
-
18
- import { useCommerce } from '../../../../service/context'
19
- import { processSquareCardPayment } from '../../../../util'
20
- import type { PaymentMethodComponentProps } from '../../../../types'
21
- import { sendFBEvent, sendGAEvent } from '../../../../util/analytics'
22
-
23
- import ContactInfo from '../contact-form'
24
- import PaymentMethods from '../card-icon-row'
25
-
26
- const PayWithCard: React.FC<PaymentMethodComponentProps> = observer(({
27
- onDone,
28
- transactionStatus,
29
- setTransactionStatus,
30
- storePaymentInfo,
31
- contactForm,
32
- }) => {
33
- const cmmc = useCommerce()
34
-
35
- const cardTokenizeResponseReceived = async (
36
- token: any,
37
- verifiedBuyer: any
38
- ) => {
39
- contactForm.handleSubmit(async () => {
40
- setTransactionStatus('paid')
41
- const res = await processSquareCardPayment(token.token, cmmc.promoAppliedCartTotal, verifiedBuyer.token)
42
- if (res) {
43
- await storePaymentInfo({paymentMethod: token.details.method ?? null, processed: res})
44
- setTransactionStatus('confirmed')
45
- sendGAEvent('purchase', {
46
- transaction_id: res.payment?.id,
47
- value: res.payment?.amountMoney?.amount,
48
- currency: res.payment?.amountMoney?.currency,
49
- items: cmmc.cartItems.map((item) => ({
50
- item_id: item.sku,
51
- item_name: item.title,
52
- item_category: item.familyId,
53
- price: item.price,
54
- quantity: item.quantity
55
- })),
56
- })
57
- sendFBEvent('Purchase', {
58
- content_ids: cmmc.cartItems.map((item) => item.sku),
59
- contents: cmmc.cartItems.map(item => ({
60
- id: item.sku,
61
- quantity: item.quantity
62
- })),
63
- num_items: cmmc.cartItems.length,
64
- value: cmmc.promoAppliedCartTotal,
65
- currency: 'USD',
66
- })
67
- } else {
68
- setTransactionStatus('error')
69
- }
70
- })()
71
- }
72
-
73
- const createVerificationDetails = () => {
74
- const {name, email} = contactForm.getValues()
75
- return {
76
- amount: cmmc.promoAppliedCartTotal.toFixed(2),
77
- billingContact: {
78
- givenName: name,
79
- email,
80
- },
81
- currencyCode: 'USD',
82
- intent: 'CHARGE',
83
- }
84
- }
85
-
86
- const createPaymentRequest = () => ({
87
- countryCode: "US",
88
- currencyCode: "USD",
89
- lineItems: cmmc.cartItems.map(item => ({
90
- amount: item.price.toFixed(2),
91
- label: item.title,
92
- id: item.sku,
93
- })),
94
- requestBillingContact: false,
95
- requestShippingContact: false,
96
- total: {
97
- amount: cmmc.promoAppliedCartTotal.toFixed(2),
98
- label: "Total",
99
- },
100
- })
101
-
102
- /**
103
- * Reload payment form after checkout value changes (promo code applied, etc.)
104
- * Reloading is required so that Apple Pay and Google Pay buttons are updated for new cart total.
105
- */
106
- const [loadingPaymentForm, setLoadingPaymentForm] = useState<boolean>(false)
107
- useEffect(() => {
108
- setLoadingPaymentForm(true)
109
- const timeout = setTimeout(() => setLoadingPaymentForm(false), 1000)
110
- return () => clearTimeout(timeout)
111
- }, [cmmc.promoAppliedCartTotal])
112
-
113
- if (loadingPaymentForm) {
114
- return (
115
- <div className='flex flex-col gap-2'>
116
- <Skeleton className='w-full h-10' />
117
- <Skeleton className='w-full h-10' />
118
- </div>
119
- )
120
- }
121
-
122
- return (
123
- <PaymentForm
124
- /**
125
- * Identifies the calling form with a verified application ID generated from
126
- * the Square Application Dashboard.
127
- */
128
- applicationId={process.env.NEXT_PUBLIC_SQUARE_APPLICATION_ID}
129
- /**
130
- * Invoked when payment form receives the result of a tokenize generation
131
- * request. The result will be a valid credit card or wallet token, or an error.
132
- */
133
- cardTokenizeResponseReceived={cardTokenizeResponseReceived}
134
- /**
135
- * This function enable the Strong Customer Authentication (SCA) flow
136
- *
137
- * We strongly recommend use this function to verify the buyer and reduce
138
- * the chance of fraudulent transactions.
139
- */
140
- createVerificationDetails={createVerificationDetails}
141
- /**
142
- * This function is required for digital wallets (Apple Pay, Google Pay)
143
- */
144
- createPaymentRequest={createPaymentRequest}
145
- /**
146
- * Identifies the location of the merchant that is taking the payment.
147
- * Obtained from the Square Application Dashboard - Locations tab.
148
- */
149
- locationId={process.env.NEXT_PUBLIC_SQUARE_LOCATION_ID}
150
- >
151
- <ApplyTypography className='flex flex-col mt-6 gap-1'>
152
- {transactionStatus === 'paid' ? (
153
- <h6 className='mx-auto'>Processing your payment...</h6>
154
- ) : transactionStatus === 'confirmed' ? (
155
- <div className='flex flex-col gap-4'>
156
- <h5 className='mx-auto'>Payment confirmed!</h5>
157
- <p className='mx-auto'>Thank you for your purchase.</p>
158
- <Button onClick={onDone}>Continue</Button>
159
- </div>
160
- ) : (
161
- <div className='flex flex-col gap-1'>
162
- <GooglePay/>
163
- <ApplePay/>
164
-
165
- <div className='flex gap-2 whitespace-nowrap items-center my-1 sm:my-3 text-xs text-muted'>
166
- <Separator className='grow w-auto'/><div className='shrink-0 mx-1'>or</div><Separator className='grow w-auto'/>
167
- </div>
168
-
169
- <PaymentMethods />
170
-
171
- <ContactInfo form={contactForm}/>
172
- {/* Imitates hanzo/ui Button and Input styles, I was unable to render the
173
- hanzo/ui button outright and keeping the submit form functionality*/}
174
- <CreditCard
175
- style={{
176
- '.input-container': {
177
- borderColor: '#666666',
178
- borderRadius: '8px',
179
- },
180
- '.input-container.is-focus': {
181
- borderColor: '#ffffff',
182
- },
183
- '.input-container.is-error': {
184
- borderColor: '#ff1600',
185
- },
186
- '.message-text': {
187
- color: '#999999',
188
- },
189
- '.message-icon': {
190
- color: '#999999',
191
- },
192
- '.message-text.is-error': {
193
- color: '#ff1600',
194
- },
195
- '.message-icon.is-error': {
196
- color: '#ff1600',
197
- },
198
- input: {
199
- backgroundColor: 'transparent',
200
- color: '#FFFFFF',
201
- fontSize: '15px',
202
- fontFamily: 'helvetica neue, sans-serif',
203
- },
204
- 'input::placeholder': {
205
- color: '#999999',
206
- },
207
- 'input.is-error': {
208
- color: '#ff1600',
209
- },
210
- }}
211
- render={(Button: any) => (
212
- <Button className={cn(
213
- 'items-center justify-center font-medium transition-colors focus-visible:outline-none focus-visible:ring-2',
214
- 'focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background',
215
- '!bg-primary !text-primary-fg hover:!bg-primary-hover font-nav whitespace-nowrap not-typography h-10 py-2 px-4',
216
- '!text-sm rounded-md lg:min-w-[220px] sm:min-w-[220px] flex'
217
- )}>
218
- Pay
219
- </Button>
220
- )}
221
- />
222
- {transactionStatus === 'error' && (
223
- <p className='mx-auto text-destructive'>There was an error processing your payment.</p>
224
- )}
225
- </div>
226
- )}
227
- </ApplyTypography>
228
- </PaymentForm>
229
- )
230
- })
231
-
232
- export default PayWithCard
1
+ 'use client'
2
+ import React, { useEffect, useState } from 'react'
3
+
4
+ // @ts-ignore
5
+ import { ApplePay, GooglePay, CreditCard, PaymentForm } from 'react-square-web-payments-sdk'
6
+
7
+ import { observer } from 'mobx-react-lite'
8
+
9
+ import {
10
+ ApplyTypography,
11
+ Button,
12
+ Separator,
13
+ Skeleton,
14
+ } from '@hanzo/ui/primitives'
15
+
16
+ import { cn } from '@hanzo/ui/util'
17
+
18
+ import { useCommerce } from '../../../../service/context'
19
+ import { processSquareCardPayment } from '../../../../util'
20
+ import type { PaymentMethodComponentProps } from '../../../../types'
21
+ import { sendFBEvent, sendGAEvent } from '../../../../util/analytics'
22
+
23
+ import ContactInfo from '../contact-form'
24
+ import PaymentMethods from '../card-icon-row'
25
+
26
+ const PayWithCard: React.FC<PaymentMethodComponentProps> = observer(({
27
+ onDone,
28
+ transactionStatus,
29
+ setTransactionStatus,
30
+ storePaymentInfo,
31
+ contactForm,
32
+ }) => {
33
+ const cmmc = useCommerce()
34
+
35
+ const cardTokenizeResponseReceived = async (
36
+ token: any,
37
+ verifiedBuyer: any
38
+ ) => {
39
+ contactForm.handleSubmit(async () => {
40
+ setTransactionStatus('paid')
41
+ const res = await processSquareCardPayment(token.token, cmmc.promoAppliedCartTotal, verifiedBuyer.token)
42
+ if (res) {
43
+ await storePaymentInfo({paymentMethod: token.details.method ?? null, processed: res})
44
+ setTransactionStatus('confirmed')
45
+ sendGAEvent('purchase', {
46
+ transaction_id: res.payment?.id,
47
+ value: res.payment?.amountMoney?.amount,
48
+ currency: res.payment?.amountMoney?.currency,
49
+ items: cmmc.cartItems.map((item) => ({
50
+ item_id: item.sku,
51
+ item_name: item.title,
52
+ item_category: item.familyId,
53
+ price: item.price,
54
+ quantity: item.quantity
55
+ })),
56
+ })
57
+ sendFBEvent('Purchase', {
58
+ content_ids: cmmc.cartItems.map((item) => item.sku),
59
+ contents: cmmc.cartItems.map(item => ({
60
+ id: item.sku,
61
+ quantity: item.quantity
62
+ })),
63
+ num_items: cmmc.cartItems.length,
64
+ value: cmmc.promoAppliedCartTotal,
65
+ currency: 'USD',
66
+ })
67
+ } else {
68
+ setTransactionStatus('error')
69
+ }
70
+ })()
71
+ }
72
+
73
+ const createVerificationDetails = () => {
74
+ const {name, email} = contactForm.getValues()
75
+ return {
76
+ amount: cmmc.promoAppliedCartTotal.toFixed(2),
77
+ billingContact: {
78
+ givenName: name,
79
+ email,
80
+ },
81
+ currencyCode: 'USD',
82
+ intent: 'CHARGE',
83
+ }
84
+ }
85
+
86
+ const createPaymentRequest = () => ({
87
+ countryCode: "US",
88
+ currencyCode: "USD",
89
+ lineItems: cmmc.cartItems.map(item => ({
90
+ amount: item.price.toFixed(2),
91
+ label: item.title,
92
+ id: item.sku,
93
+ })),
94
+ requestBillingContact: false,
95
+ requestShippingContact: false,
96
+ total: {
97
+ amount: cmmc.promoAppliedCartTotal.toFixed(2),
98
+ label: "Total",
99
+ },
100
+ })
101
+
102
+ /**
103
+ * Reload payment form after checkout value changes (promo code applied, etc.)
104
+ * Reloading is required so that Apple Pay and Google Pay buttons are updated for new cart total.
105
+ */
106
+ const [loadingPaymentForm, setLoadingPaymentForm] = useState<boolean>(false)
107
+ useEffect(() => {
108
+ setLoadingPaymentForm(true)
109
+ const timeout = setTimeout(() => setLoadingPaymentForm(false), 1000)
110
+ return () => clearTimeout(timeout)
111
+ }, [cmmc.promoAppliedCartTotal])
112
+
113
+ if (loadingPaymentForm) {
114
+ return (
115
+ <div className='flex flex-col gap-2'>
116
+ <Skeleton className='w-full h-10' />
117
+ <Skeleton className='w-full h-10' />
118
+ </div>
119
+ )
120
+ }
121
+
122
+ return (
123
+ <PaymentForm
124
+ /**
125
+ * Identifies the calling form with a verified application ID generated from
126
+ * the Square Application Dashboard.
127
+ */
128
+ applicationId={process.env.NEXT_PUBLIC_SQUARE_APPLICATION_ID}
129
+ /**
130
+ * Invoked when payment form receives the result of a tokenize generation
131
+ * request. The result will be a valid credit card or wallet token, or an error.
132
+ */
133
+ cardTokenizeResponseReceived={cardTokenizeResponseReceived}
134
+ /**
135
+ * This function enable the Strong Customer Authentication (SCA) flow
136
+ *
137
+ * We strongly recommend use this function to verify the buyer and reduce
138
+ * the chance of fraudulent transactions.
139
+ */
140
+ createVerificationDetails={createVerificationDetails}
141
+ /**
142
+ * This function is required for digital wallets (Apple Pay, Google Pay)
143
+ */
144
+ createPaymentRequest={createPaymentRequest}
145
+ /**
146
+ * Identifies the location of the merchant that is taking the payment.
147
+ * Obtained from the Square Application Dashboard - Locations tab.
148
+ */
149
+ locationId={process.env.NEXT_PUBLIC_SQUARE_LOCATION_ID}
150
+ >
151
+ <ApplyTypography className='flex flex-col mt-6 gap-1'>
152
+ {transactionStatus === 'paid' ? (
153
+ <h6 className='mx-auto'>Processing your payment...</h6>
154
+ ) : transactionStatus === 'confirmed' ? (
155
+ <div className='flex flex-col gap-4'>
156
+ <h5 className='mx-auto'>Payment confirmed!</h5>
157
+ <p className='mx-auto'>Thank you for your purchase.</p>
158
+ <Button onClick={onDone}>Continue</Button>
159
+ </div>
160
+ ) : (
161
+ <div className='flex flex-col gap-1'>
162
+ <GooglePay/>
163
+ <ApplePay/>
164
+
165
+ <div className='flex gap-2 whitespace-nowrap items-center my-1 sm:my-3 text-xs text-muted'>
166
+ <Separator className='grow w-auto'/><div className='shrink-0 mx-1'>or</div><Separator className='grow w-auto'/>
167
+ </div>
168
+
169
+ <PaymentMethods />
170
+
171
+ <ContactInfo form={contactForm}/>
172
+ {/* Imitates hanzo/ui Button and Input styles, I was unable to render the
173
+ hanzo/ui button outright and keeping the submit form functionality*/}
174
+ <CreditCard
175
+ style={{
176
+ '.input-container': {
177
+ borderColor: '#666666',
178
+ borderRadius: '8px',
179
+ },
180
+ '.input-container.is-focus': {
181
+ borderColor: '#ffffff',
182
+ },
183
+ '.input-container.is-error': {
184
+ borderColor: '#ff1600',
185
+ },
186
+ '.message-text': {
187
+ color: '#999999',
188
+ },
189
+ '.message-icon': {
190
+ color: '#999999',
191
+ },
192
+ '.message-text.is-error': {
193
+ color: '#ff1600',
194
+ },
195
+ '.message-icon.is-error': {
196
+ color: '#ff1600',
197
+ },
198
+ input: {
199
+ backgroundColor: 'transparent',
200
+ color: '#FFFFFF',
201
+ fontSize: '15px',
202
+ fontFamily: 'helvetica neue, sans-serif',
203
+ },
204
+ 'input::placeholder': {
205
+ color: '#999999',
206
+ },
207
+ 'input.is-error': {
208
+ color: '#ff1600',
209
+ },
210
+ }}
211
+ render={(Button: any) => (
212
+ <Button className={cn(
213
+ 'items-center justify-center font-medium transition-colors focus-visible:outline-none focus-visible:ring-2',
214
+ 'focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background',
215
+ '!bg-primary !text-primary-fg hover:!bg-primary-hover font-nav whitespace-nowrap not-typography h-10 py-2 px-4',
216
+ '!text-sm rounded-md lg:min-w-[220px] sm:min-w-[220px] flex'
217
+ )}>
218
+ Pay
219
+ </Button>
220
+ )}
221
+ />
222
+ {transactionStatus === 'error' && (
223
+ <p className='mx-auto text-destructive'>There was an error processing your payment.</p>
224
+ )}
225
+ </div>
226
+ )}
227
+ </ApplyTypography>
228
+ </PaymentForm>
229
+ )
230
+ })
231
+
232
+ export default PayWithCard