@hanzo/commerce 7.7.1 → 7.7.3

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 (91) hide show
  1. package/dist/components/cart/cart-panel/promo-code.d.ts +2 -2
  2. package/dist/service/impls/standalone/index.js +4 -4
  3. package/dist/service/impls/standalone/index.js.map +1 -1
  4. package/package.json +46 -17
  5. package/billing.ts +0 -2
  6. package/client.ts +0 -783
  7. package/components/Icons.tsx +0 -35
  8. package/components/add-to-cart-widget.tsx +0 -195
  9. package/components/buy/buy-card.tsx +0 -269
  10. package/components/buy/carousel-buy-card.tsx +0 -243
  11. package/components/buy/multi-family/all-variants-carousel.tsx +0 -259
  12. package/components/buy/multi-family/family-carousel/index.tsx +0 -75
  13. package/components/buy/multi-family/family-carousel/slide.tsx +0 -82
  14. package/components/buy/multi-family/family-carousel/state.ts +0 -87
  15. package/components/buy/multi-family/index.ts +0 -2
  16. package/components/buy/single-family-selector.tsx +0 -91
  17. package/components/buy/title-and-byline.tsx +0 -26
  18. package/components/cart/cart-panel/cart-line-item.tsx +0 -77
  19. package/components/cart/cart-panel/index.tsx +0 -157
  20. package/components/cart/cart-panel/promo-code.tsx +0 -105
  21. package/components/cart/cart-panel/total-area.tsx +0 -61
  22. package/components/checkout/payment-step-form/card-icon-row.tsx +0 -26
  23. package/components/checkout/payment-step-form/card-icons/amex.tsx +0 -32
  24. package/components/checkout/payment-step-form/card-icons/diners-club.tsx +0 -13
  25. package/components/checkout/payment-step-form/card-icons/discover.tsx +0 -25
  26. package/components/checkout/payment-step-form/card-icons/jcb.tsx +0 -26
  27. package/components/checkout/payment-step-form/card-icons/mastercard.tsx +0 -27
  28. package/components/checkout/payment-step-form/card-icons/visa.tsx +0 -25
  29. package/components/checkout/payment-step-form/cc-button.tsx +0 -18
  30. package/components/checkout/payment-step-form/contact-form.tsx +0 -48
  31. package/components/checkout/payment-step-form/crypto-icons/btc.tsx +0 -11
  32. package/components/checkout/payment-step-form/crypto-icons/eth.tsx +0 -20
  33. package/components/checkout/payment-step-form/crypto-icons/usdt.tsx +0 -13
  34. package/components/checkout/payment-step-form/index.tsx +0 -113
  35. package/components/checkout/payment-step-form/methods/bank-transfer.tsx +0 -81
  36. package/components/checkout/payment-step-form/methods/card.tsx +0 -253
  37. package/components/checkout/payment-step-form/methods/crypto.tsx +0 -226
  38. package/components/checkout/payment-step-form/methods/index.ts +0 -23
  39. package/components/checkout/shipping-step-form.tsx +0 -171
  40. package/components/index.ts +0 -11
  41. package/components/item/product-card.tsx +0 -66
  42. package/components/item-selector/button.tsx +0 -213
  43. package/components/item-selector/carousel/index.tsx +0 -196
  44. package/components/item-selector/carousel/slider.tsx +0 -37
  45. package/components/item-selector/index.ts +0 -5
  46. package/components/item-selector/quantity-indicator.tsx +0 -50
  47. package/components/node-tabs/index.tsx +0 -90
  48. package/components/node-tabs/node-image.tsx +0 -31
  49. package/index.ts +0 -55
  50. package/metering.test.ts +0 -199
  51. package/metering.ts +0 -289
  52. package/product-card.test.tsx +0 -104
  53. package/service/context.tsx +0 -45
  54. package/service/debug.ts +0 -41
  55. package/service/impls/standalone/actual-line-item.ts +0 -136
  56. package/service/impls/standalone/get-instance.ts +0 -64
  57. package/service/impls/standalone/index.ts +0 -579
  58. package/service/impls/standalone/order/firebase.ts +0 -5
  59. package/service/impls/standalone/order/index.ts +0 -58
  60. package/service/impls/standalone/persistence.ts +0 -33
  61. package/service/path-utils.ts +0 -26
  62. package/service/sep.ts +0 -7
  63. package/tsconfig.json +0 -17
  64. package/types/README.md +0 -2
  65. package/types/category-node.ts +0 -50
  66. package/types/checkout.ts +0 -47
  67. package/types/commerce-config.ts +0 -13
  68. package/types/commerce-service.ts +0 -128
  69. package/types/family.ts +0 -26
  70. package/types/index.ts +0 -15
  71. package/types/item-selector.ts +0 -97
  72. package/types/line-item.ts +0 -29
  73. package/types/multi-family-selector-props.ts +0 -20
  74. package/types/product.ts +0 -21
  75. package/types/promo.ts +0 -10
  76. package/types/selection-ui-specifier.ts +0 -52
  77. package/types/string-mutator.ts +0 -14
  78. package/types/token-separators.ts +0 -7
  79. package/util/analytics.ts +0 -21
  80. package/util/countries.ts +0 -196
  81. package/util/error.ts +0 -34
  82. package/util/index.ts +0 -71
  83. package/util/item-selector-options-accessor.ts +0 -35
  84. package/util/line-item-ref.ts +0 -23
  85. package/util/multi-family-selector-options-accessor.ts +0 -15
  86. package/util/obs-string-mutator.ts +0 -22
  87. package/util/product-media-accessor.ts +0 -58
  88. package/util/promo-codes.ts +0 -106
  89. package/util/selection-ui-specifiers.ts +0 -30
  90. package/util/square-payment.ts +0 -50
  91. package/util/use-sync-sku-param-w-current-item.ts +0 -88
@@ -1,226 +0,0 @@
1
- 'use client'
2
-
3
- import React, { useEffect, useState } from 'react'
4
- import { autorun } from 'mobx'
5
- import { observer } from 'mobx-react-lite'
6
-
7
- import { ethers } from 'ethers'
8
-
9
- import {
10
- Button,
11
- Input,
12
- Select,
13
- SelectContent,
14
- SelectGroup,
15
- SelectItem,
16
- SelectTrigger,
17
- SelectValue,
18
- toast,
19
- } from '@hanzo/ui'
20
- import Eth from '../crypto-icons/eth'
21
- import { useCommerce } from '../../../../service/context'
22
- import type { PaymentMethodComponentProps } from '../../../../types'
23
- import { sendFBEvent, sendGAEvent } from '../../../../util/analytics'
24
-
25
- import ContactForm from '../contact-form'
26
-
27
- declare global {
28
- interface Window{
29
- ethereum?: any
30
- }
31
- }
32
-
33
- const PayWithCrypto: React.FC<PaymentMethodComponentProps> = observer(({
34
- onDone,
35
- transactionStatus,
36
- setTransactionStatus,
37
- storePaymentInfo,
38
- contactForm
39
- }) => {
40
- const cmmc = useCommerce()
41
-
42
- const [loadingPrice, setLoadingPrice] = useState(false)
43
- //const [selectedToken, setSelectedToken] = useState('eth')
44
- const [amount, setAmount] = useState<number>()
45
- const [provider, setProvider] = useState<ethers.BrowserProvider>()
46
-
47
- //const selectedToken = 'eth'
48
-
49
- useEffect(() => {
50
- setTransactionStatus('unpaid')
51
- // responding to changes in user.walletAddress
52
- return autorun(() => {
53
- const newProvider = new ethers.BrowserProvider(window.ethereum)
54
- setProvider(newProvider)
55
- })
56
- }, [])
57
-
58
- // Get latest USD -> ETH exchange rate
59
- useEffect(() => {
60
- const fetchPrice = () => {
61
- setLoadingPrice(true)
62
- fetch(process.env.NEXT_PUBLIC_ETH_EXCHANGE_RATE_API ?? '')
63
- .then(res => res.json())
64
- .then((exchangeRate) => {
65
- const oneUsdInWei = (10**18) / exchangeRate.data.amount
66
- const usdAmountInWei = oneUsdInWei * cmmc.promoAppliedCartTotal
67
- setAmount(usdAmountInWei)
68
- setLoadingPrice(false)
69
- })
70
- }
71
-
72
- // Call immediately on load
73
- fetchPrice()
74
-
75
- // Then set interval to call every 30 seconds
76
- const interval = setInterval(fetchPrice, 30000)
77
-
78
- return () => clearInterval(interval)
79
- }, [cmmc.promoAppliedCartTotal])
80
-
81
- const sendPayment = async (ether: number) => {
82
- contactForm.handleSubmit(async () => {
83
- // Check that we are on ethereum network
84
- try {
85
- await window.ethereum.request({
86
- method: 'wallet_switchEthereumChain',
87
- params: [{ chainId: "0x1"}],
88
- })
89
- const newProvider = new ethers.BrowserProvider(window.ethereum)
90
- setProvider(newProvider)
91
- } catch (err) {
92
- toast('Please switch your wallet to the Ethereum network.')
93
- return
94
- }
95
-
96
- try {
97
- if (!provider) {
98
- // :aa TODO string table
99
- throw new Error('No crypto wallet found. Please install it.')
100
- }
101
-
102
- await window.ethereum.send('eth_requestAccounts')
103
-
104
- const signer = await provider.getSigner()
105
- ethers.getAddress(process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS ?? '')
106
- const price = ethers.parseEther(ether.toString())
107
- const tx = await signer.sendTransaction({
108
- to: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS,
109
- value: price
110
- })
111
- console.log({ ether, addr: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS })
112
- console.log('tx', tx)
113
- setTransactionStatus('paid')
114
- await storePaymentInfo({
115
- ether,
116
- transactionHash: tx.hash,
117
- to: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS,
118
- paymentMethod: 'crypto'
119
- })
120
-
121
- provider.waitForTransaction(tx.hash)
122
- .then(async (receipt) => {
123
- console.log(receipt)
124
- await storePaymentInfo({
125
- ether,
126
- addr: process.env.NEXT_PUBLIC_ETH_PAYMENT_ADDRESS,
127
- receipt,
128
- paymentMethod: 'crypto'
129
- })
130
- sendGAEvent('purchase', {
131
- transaction_id: tx.hash,
132
- value: price,
133
- currency: 'ETH',
134
- items: cmmc.cartItems.map((item) => ({
135
- item_id: item.sku,
136
- item_name: item.title,
137
- item_category: item.familyId,
138
- price: item.price,
139
- quantity: item.quantity
140
- })),
141
- })
142
- sendFBEvent('Purchase', {
143
- content_ids: cmmc.cartItems.map((item) => item.sku),
144
- contents: cmmc.cartItems.map(item => ({
145
- id: item.sku,
146
- quantity: item.quantity
147
- })),
148
- num_items: cmmc.cartItems.length,
149
- value: price,
150
- currency: 'ETH',
151
- })
152
- setTransactionStatus('confirmed')
153
- })
154
- .catch((error) => {
155
- console.error(error)
156
- setTransactionStatus('error')
157
- })
158
- } catch (err) {
159
- console.log(err)
160
- // :aa TODO string table
161
- toast('Not enough funds in your wallet')
162
- }
163
- })()
164
- }
165
-
166
- const nextStep = async () => {
167
- await storePaymentInfo({
168
- paymentMethod: 'crypto'
169
- })
170
- onDone()
171
- }
172
-
173
- return (
174
- <div className='flex flex-col gap-6 mt-6'>
175
- <div className='flex flex-col w-full'>
176
- <ContactForm form={contactForm}/>
177
- <div className='flex gap-2 grid grid-cols-3'>
178
- <Select onValueChange={(token) => {/*ONLY ETH setSelectedToken(token) */}} defaultValue='eth'>
179
- <SelectTrigger>
180
- <SelectValue />
181
- </SelectTrigger>
182
- <SelectContent>
183
- <SelectGroup>
184
- <SelectItem value='eth'><div className='flex items-center gap-2'><Eth height={14}/>ETH</div></SelectItem>
185
- {/* <SelectItem value='btc' ><div className='flex items-center gap-2'><Btc height={14}/>BTC</div></SelectItem>
186
- <SelectItem value='usdt' ><div className='flex items-center gap-2'><Usdt height={14}/>USDT</div></SelectItem> */}
187
- </SelectGroup>
188
- </SelectContent>
189
- </Select>
190
- <div className='col-span-2'>
191
- <Input
192
- value={amount ? amount/(10**18) : amount}
193
- contentEditable={false}
194
- />
195
- <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'>
196
- <Eth height={10}/>
197
- ETH
198
- </div>
199
- </div>
200
- </div>
201
-
202
- {transactionStatus === 'error' ? (
203
- <h4 className='text-destructive'>There was an error while confirming the transaction.</h4>
204
- ) : transactionStatus === 'paid' ? (
205
- <h4>Waiting for transaction to be confirmed on chain.</h4>
206
- ) : transactionStatus === 'confirmed' ? (
207
- <h4>Transaction confirmed!</h4>
208
- ) : null}
209
-
210
- {transactionStatus === 'unpaid' ? (
211
- <Button
212
- onClick={() => sendPayment(amount ? amount/(10**18) : 0)}
213
- className='mx-auto w-full'
214
- disabled={loadingPrice}
215
- >
216
- Pay
217
- </Button>
218
- ) : (
219
- <Button onClick={nextStep} className='mx-auto w-full'>Continue</Button>
220
- )}
221
- </div>
222
- </div>
223
- )
224
- })
225
-
226
- export default PayWithCrypto
@@ -1,23 +0,0 @@
1
- import type { PaymentMethodDesc } from '../../../../types'
2
-
3
- import Card from './card'
4
- import Crypto from './crypto'
5
- import BankTransfer from './bank-transfer'
6
-
7
- export default [
8
- {
9
- value: 'card',
10
- label: 'Card',
11
- Comp: Card
12
- },
13
- {
14
- value: 'crypto',
15
- label: 'Wallet',
16
- Comp: Crypto
17
- },
18
- {
19
- value: 'bank',
20
- label: 'Bank Wire',
21
- Comp: BankTransfer
22
- },
23
- ] satisfies PaymentMethodDesc[]
@@ -1,171 +0,0 @@
1
- 'use client'
2
-
3
- import * as z from 'zod'
4
- import { useForm } from 'react-hook-form'
5
- import { zodResolver } from '@hookform/resolvers/zod'
6
-
7
- import {
8
- Input,
9
- Button,
10
- Select,
11
- SelectContent,
12
- SelectItem,
13
- SelectTrigger,
14
- SelectValue,
15
- Form,
16
- FormControl,
17
- FormField,
18
- FormItem,
19
- FormMessage,
20
- } from '@hanzo/ui'
21
- import { useCommerce } from '../../service/context'
22
-
23
- import countries from '../../util/countries'
24
- import { sendGAEvent } from '../../util/analytics'
25
-
26
- import type { CheckoutStepComponentProps } from '../../types'
27
-
28
- const shippingFormSchema = z.object({
29
- addressLine1: z.string().min(2, 'Address must be at least 2 characters.'),
30
- addressLine2: z.string().optional(),
31
- zipCode: z.string().min(2, 'Zip code is invalid.'),
32
- city: z.string().min(2, 'City is invalid.'),
33
- state: z.string().optional(),
34
- country: z.string().min(2, 'Country is invalid.'),
35
- })
36
-
37
- const ShippingStepForm: React.FC<CheckoutStepComponentProps> = ({
38
- orderId,
39
- onDone
40
- }) => {
41
- const cmmc = useCommerce()
42
-
43
- const shippingForm = useForm<z.infer<typeof shippingFormSchema>>({
44
- resolver: zodResolver(shippingFormSchema as any),
45
- defaultValues: {
46
- addressLine1: '',
47
- addressLine2: '',
48
- zipCode: '',
49
- city: '',
50
- state: '',
51
- country: '',
52
- },
53
- })
54
-
55
- const onSubmit = async (values: z.infer<typeof shippingFormSchema>) => {
56
- if (orderId) {
57
- await cmmc.updateOrderShippingInfo(orderId, values)
58
- }
59
- sendGAEvent('add_shipping_info', {
60
- items: cmmc.cartItems.map((item) => ({
61
- item_id: item.sku,
62
- item_name: item.title,
63
- item_category: item.familyId,
64
- price: item.price,
65
- quantity: item.quantity
66
- })),
67
- num_items: cmmc.cartItems.length,
68
- value: cmmc.cartTotal,
69
- currency: 'USD',
70
- })
71
- onDone()
72
- }
73
-
74
- return (
75
- <Form {...shippingForm}>
76
- <form onSubmit={shippingForm.handleSubmit(onSubmit)} className='text-left'>
77
- <div className='flex flex-col gap-4'>
78
- <FormField
79
- control={shippingForm.control}
80
- name='addressLine1'
81
- render={({ field }) => (
82
- <FormItem className='space-y-1 w-full'>
83
- <FormControl>
84
- <Input {...field} placeholder='Address line 1'/>
85
- </FormControl>
86
- <FormMessage />
87
- </FormItem>
88
- )}
89
- />
90
- <FormField
91
- control={shippingForm.control}
92
- name='addressLine2'
93
- render={({ field }) => (
94
- <FormItem className='space-y-1 w-full'>
95
- <FormControl>
96
- <Input {...field} placeholder='Address line 2 (optional)'/>
97
- </FormControl>
98
- <FormMessage />
99
- </FormItem>
100
- )}
101
- />
102
- <div className='flex gap-4 items-end'>
103
- <FormField
104
- control={shippingForm.control}
105
- name='zipCode'
106
- render={({ field }) => (
107
- <FormItem className='space-y-1 w-full'>
108
- <FormControl>
109
- <Input {...field} placeholder='Zip code'/>
110
- </FormControl>
111
- <FormMessage />
112
- </FormItem>
113
- )}
114
- />
115
- <FormField
116
- control={shippingForm.control}
117
- name='city'
118
- render={({ field }) => (
119
- <FormItem className='space-y-1 w-full'>
120
- <FormControl>
121
- <Input {...field} placeholder='City'/>
122
- </FormControl>
123
- <FormMessage />
124
- </FormItem>
125
- )}
126
- />
127
- </div>
128
- <div className='flex gap-4 items-start'>
129
- <FormField
130
- control={shippingForm.control}
131
- name='state'
132
- render={({ field }) => (
133
- <FormItem className='space-y-1 w-full'>
134
- <FormControl>
135
- <Input {...field} placeholder='State (optional)'/>
136
- </FormControl>
137
- <FormMessage />
138
- </FormItem>
139
- )}
140
- />
141
- <FormField
142
- control={shippingForm.control}
143
- name='country'
144
- render={({ field }) => (
145
- <FormItem className='space-y-1 w-full'>
146
- <Select onValueChange={field.onChange} defaultValue={field.value}>
147
- <FormControl>
148
- <SelectTrigger className='bg-level-1 border-muted-4'>
149
- <SelectValue placeholder='Country' />
150
- </SelectTrigger>
151
- </FormControl>
152
- <SelectContent>
153
- {countries.map((country) => (
154
- <SelectItem key={country.id} value={country.name}>
155
- {country.name}
156
- </SelectItem>
157
- ))}
158
- </SelectContent>
159
- </Select>
160
- </FormItem>
161
- )}
162
- />
163
- </div>
164
- </div>
165
- <Button type='submit' className='mx-auto w-full mt-4'>Confirm order</Button>
166
- </form>
167
- </Form>
168
- )
169
- }
170
-
171
- export default ShippingStepForm
@@ -1,11 +0,0 @@
1
- export { default as AddToCartWidget } from './add-to-cart-widget'
2
- export { default as CarouselBuyCard } from './buy/carousel-buy-card'
3
-
4
- export { default as CartPanel } from './cart/cart-panel'
5
-
6
- export { default as Icons } from './Icons'
7
- export { default as PaymentStepForm } from './checkout/payment-step-form'
8
- export { default as ProductCard } from './item/product-card'
9
- export { default as ShippingStepForm } from './checkout/shipping-step-form'
10
-
11
- export * from './item-selector'
@@ -1,66 +0,0 @@
1
- import React from 'react'
2
-
3
- import {
4
- Card,
5
- CardContent,
6
- CardFooter,
7
- CardHeader,
8
- CardTitle,
9
- MediaStack,
10
- cn,
11
- } from '@hanzo/ui'
12
- import { formatCurrencyValue } from '../../util'
13
- import type { LineItem } from '../../types'
14
-
15
- import AddToCartWidget from '../add-to-cart-widget'
16
-
17
- interface ProductCardProps extends React.HTMLAttributes<HTMLDivElement> {
18
- item: LineItem
19
- }
20
-
21
- const ProductCard: React.FC<ProductCardProps> = ({
22
- item,
23
- className,
24
- ...props
25
- }) => (
26
- <Card
27
- itemScope
28
- itemType='https://schema.org/Product'
29
- className={cn('max-h-[360px] lg:min-w-[200px] max-w-[260px] overflow-hidden', className)}
30
- // A div's whole attribute set, spread onto a cross-platform component that
31
- // names a few of them differently. The element a Card renders IS a div, and
32
- // it is the one these reach.
33
- {...(props as object)}
34
- >
35
- {/* Standard schema.org Product microdata. Neutral and analytics-agnostic:
36
- track.js `annotate`, GA4 Merchant, or any reader picks up the item with
37
- zero per-app config. Machine values live in <meta> so the visible,
38
- formatted UI is untouched. */}
39
- <meta itemProp='name' content={item.title} />
40
- <meta itemProp='sku' content={item.sku} />
41
- <CardHeader className='w-full border-b p-6 min-h-[180px] max-h-[240px] relative'>
42
- <MediaStack media={item} constrainTo={{w: 700, h:700}} className='p-6' />
43
- </CardHeader>
44
- <CardContent className='grid gap-2.5 p-4'>
45
- <CardTitle className='text-sm sm:text-base flex flex-col justify-start items-center line-clap-3'>
46
- {item.title.split(', ').map((e, i) => (<p key={i}>{e}</p>))}
47
- <p
48
- className='mt-1 font-semibold'
49
- itemProp='offers'
50
- itemScope
51
- itemType='https://schema.org/Offer'
52
- >
53
- <meta itemProp='price' content={String(item.price)} />
54
- <meta itemProp='priceCurrency' content='USD' />
55
- {formatCurrencyValue(item.price)}
56
- </p>
57
- </CardTitle>
58
- </CardContent>
59
- <CardFooter className='p-4 flex flex-row justify-center'>
60
- <AddToCartWidget item={item} />
61
- </CardFooter>
62
- </Card>
63
- )
64
-
65
-
66
- export default ProductCard