@hanzo/commerce 7.3.2 → 7.3.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 (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,172 +1,172 @@
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
- Form,
11
- FormControl,
12
- FormField,
13
- FormItem,
14
- FormMessage,
15
- Select,
16
- SelectContent,
17
- SelectItem,
18
- SelectTrigger,
19
- SelectValue
20
- } from '@hanzo/ui/primitives'
21
-
22
- import { useCommerce } from '../../service/context'
23
-
24
- import countries from '../../util/countries'
25
- import { sendGAEvent } from '../../util/analytics'
26
-
27
- import type { CheckoutStepComponentProps } from '../../types'
28
-
29
- const shippingFormSchema = z.object({
30
- addressLine1: z.string().min(2, 'Address must be at least 2 characters.'),
31
- addressLine2: z.string().optional(),
32
- zipCode: z.string().min(2, 'Zip code is invalid.'),
33
- city: z.string().min(2, 'City is invalid.'),
34
- state: z.string().optional(),
35
- country: z.string().min(2, 'Country is invalid.'),
36
- })
37
-
38
- const ShippingStepForm: React.FC<CheckoutStepComponentProps> = ({
39
- orderId,
40
- onDone
41
- }) => {
42
- const cmmc = useCommerce()
43
-
44
- const shippingForm = useForm<z.infer<typeof shippingFormSchema>>({
45
- resolver: zodResolver(shippingFormSchema),
46
- defaultValues: {
47
- addressLine1: '',
48
- addressLine2: '',
49
- zipCode: '',
50
- city: '',
51
- state: '',
52
- country: '',
53
- },
54
- })
55
-
56
- const onSubmit = async (values: z.infer<typeof shippingFormSchema>) => {
57
- if (orderId) {
58
- await cmmc.updateOrderShippingInfo(orderId, values)
59
- }
60
- sendGAEvent('add_shipping_info', {
61
- items: cmmc.cartItems.map((item) => ({
62
- item_id: item.sku,
63
- item_name: item.title,
64
- item_category: item.familyId,
65
- price: item.price,
66
- quantity: item.quantity
67
- })),
68
- num_items: cmmc.cartItems.length,
69
- value: cmmc.cartTotal,
70
- currency: 'USD',
71
- })
72
- onDone()
73
- }
74
-
75
- return (
76
- <Form {...shippingForm}>
77
- <form onSubmit={shippingForm.handleSubmit(onSubmit)} className='text-left'>
78
- <div className='flex flex-col gap-4'>
79
- <FormField
80
- control={shippingForm.control}
81
- name='addressLine1'
82
- render={({ field }) => (
83
- <FormItem className='space-y-1 w-full'>
84
- <FormControl>
85
- <Input {...field} placeholder='Address line 1'/>
86
- </FormControl>
87
- <FormMessage />
88
- </FormItem>
89
- )}
90
- />
91
- <FormField
92
- control={shippingForm.control}
93
- name='addressLine2'
94
- render={({ field }) => (
95
- <FormItem className='space-y-1 w-full'>
96
- <FormControl>
97
- <Input {...field} placeholder='Address line 2 (optional)'/>
98
- </FormControl>
99
- <FormMessage />
100
- </FormItem>
101
- )}
102
- />
103
- <div className='flex gap-4 items-end'>
104
- <FormField
105
- control={shippingForm.control}
106
- name='zipCode'
107
- render={({ field }) => (
108
- <FormItem className='space-y-1 w-full'>
109
- <FormControl>
110
- <Input {...field} placeholder='Zip code'/>
111
- </FormControl>
112
- <FormMessage />
113
- </FormItem>
114
- )}
115
- />
116
- <FormField
117
- control={shippingForm.control}
118
- name='city'
119
- render={({ field }) => (
120
- <FormItem className='space-y-1 w-full'>
121
- <FormControl>
122
- <Input {...field} placeholder='City'/>
123
- </FormControl>
124
- <FormMessage />
125
- </FormItem>
126
- )}
127
- />
128
- </div>
129
- <div className='flex gap-4 items-start'>
130
- <FormField
131
- control={shippingForm.control}
132
- name='state'
133
- render={({ field }) => (
134
- <FormItem className='space-y-1 w-full'>
135
- <FormControl>
136
- <Input {...field} placeholder='State (optional)'/>
137
- </FormControl>
138
- <FormMessage />
139
- </FormItem>
140
- )}
141
- />
142
- <FormField
143
- control={shippingForm.control}
144
- name='country'
145
- render={({ field }) => (
146
- <FormItem className='space-y-1 w-full'>
147
- <Select onValueChange={field.onChange} defaultValue={field.value}>
148
- <FormControl>
149
- <SelectTrigger className='bg-level-1 border-muted-4'>
150
- <SelectValue placeholder='Country' />
151
- </SelectTrigger>
152
- </FormControl>
153
- <SelectContent>
154
- {countries.map((country) => (
155
- <SelectItem key={country.id} value={country.name}>
156
- {country.name}
157
- </SelectItem>
158
- ))}
159
- </SelectContent>
160
- </Select>
161
- </FormItem>
162
- )}
163
- />
164
- </div>
165
- </div>
166
- <Button type='submit' className='mx-auto w-full mt-4'>Confirm order</Button>
167
- </form>
168
- </Form>
169
- )
170
- }
171
-
172
- export default ShippingStepForm
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
+ Form,
11
+ FormControl,
12
+ FormField,
13
+ FormItem,
14
+ FormMessage,
15
+ Select,
16
+ SelectContent,
17
+ SelectItem,
18
+ SelectTrigger,
19
+ SelectValue
20
+ } from '@hanzo/ui/primitives'
21
+
22
+ import { useCommerce } from '../../service/context'
23
+
24
+ import countries from '../../util/countries'
25
+ import { sendGAEvent } from '../../util/analytics'
26
+
27
+ import type { CheckoutStepComponentProps } from '../../types'
28
+
29
+ const shippingFormSchema = z.object({
30
+ addressLine1: z.string().min(2, 'Address must be at least 2 characters.'),
31
+ addressLine2: z.string().optional(),
32
+ zipCode: z.string().min(2, 'Zip code is invalid.'),
33
+ city: z.string().min(2, 'City is invalid.'),
34
+ state: z.string().optional(),
35
+ country: z.string().min(2, 'Country is invalid.'),
36
+ })
37
+
38
+ const ShippingStepForm: React.FC<CheckoutStepComponentProps> = ({
39
+ orderId,
40
+ onDone
41
+ }) => {
42
+ const cmmc = useCommerce()
43
+
44
+ const shippingForm = useForm<z.infer<typeof shippingFormSchema>>({
45
+ resolver: zodResolver(shippingFormSchema),
46
+ defaultValues: {
47
+ addressLine1: '',
48
+ addressLine2: '',
49
+ zipCode: '',
50
+ city: '',
51
+ state: '',
52
+ country: '',
53
+ },
54
+ })
55
+
56
+ const onSubmit = async (values: z.infer<typeof shippingFormSchema>) => {
57
+ if (orderId) {
58
+ await cmmc.updateOrderShippingInfo(orderId, values)
59
+ }
60
+ sendGAEvent('add_shipping_info', {
61
+ items: cmmc.cartItems.map((item) => ({
62
+ item_id: item.sku,
63
+ item_name: item.title,
64
+ item_category: item.familyId,
65
+ price: item.price,
66
+ quantity: item.quantity
67
+ })),
68
+ num_items: cmmc.cartItems.length,
69
+ value: cmmc.cartTotal,
70
+ currency: 'USD',
71
+ })
72
+ onDone()
73
+ }
74
+
75
+ return (
76
+ <Form {...shippingForm}>
77
+ <form onSubmit={shippingForm.handleSubmit(onSubmit)} className='text-left'>
78
+ <div className='flex flex-col gap-4'>
79
+ <FormField
80
+ control={shippingForm.control}
81
+ name='addressLine1'
82
+ render={({ field }) => (
83
+ <FormItem className='space-y-1 w-full'>
84
+ <FormControl>
85
+ <Input {...field} placeholder='Address line 1'/>
86
+ </FormControl>
87
+ <FormMessage />
88
+ </FormItem>
89
+ )}
90
+ />
91
+ <FormField
92
+ control={shippingForm.control}
93
+ name='addressLine2'
94
+ render={({ field }) => (
95
+ <FormItem className='space-y-1 w-full'>
96
+ <FormControl>
97
+ <Input {...field} placeholder='Address line 2 (optional)'/>
98
+ </FormControl>
99
+ <FormMessage />
100
+ </FormItem>
101
+ )}
102
+ />
103
+ <div className='flex gap-4 items-end'>
104
+ <FormField
105
+ control={shippingForm.control}
106
+ name='zipCode'
107
+ render={({ field }) => (
108
+ <FormItem className='space-y-1 w-full'>
109
+ <FormControl>
110
+ <Input {...field} placeholder='Zip code'/>
111
+ </FormControl>
112
+ <FormMessage />
113
+ </FormItem>
114
+ )}
115
+ />
116
+ <FormField
117
+ control={shippingForm.control}
118
+ name='city'
119
+ render={({ field }) => (
120
+ <FormItem className='space-y-1 w-full'>
121
+ <FormControl>
122
+ <Input {...field} placeholder='City'/>
123
+ </FormControl>
124
+ <FormMessage />
125
+ </FormItem>
126
+ )}
127
+ />
128
+ </div>
129
+ <div className='flex gap-4 items-start'>
130
+ <FormField
131
+ control={shippingForm.control}
132
+ name='state'
133
+ render={({ field }) => (
134
+ <FormItem className='space-y-1 w-full'>
135
+ <FormControl>
136
+ <Input {...field} placeholder='State (optional)'/>
137
+ </FormControl>
138
+ <FormMessage />
139
+ </FormItem>
140
+ )}
141
+ />
142
+ <FormField
143
+ control={shippingForm.control}
144
+ name='country'
145
+ render={({ field }) => (
146
+ <FormItem className='space-y-1 w-full'>
147
+ <Select onValueChange={field.onChange} defaultValue={field.value}>
148
+ <FormControl>
149
+ <SelectTrigger className='bg-level-1 border-muted-4'>
150
+ <SelectValue placeholder='Country' />
151
+ </SelectTrigger>
152
+ </FormControl>
153
+ <SelectContent>
154
+ {countries.map((country) => (
155
+ <SelectItem key={country.id} value={country.name}>
156
+ {country.name}
157
+ </SelectItem>
158
+ ))}
159
+ </SelectContent>
160
+ </Select>
161
+ </FormItem>
162
+ )}
163
+ />
164
+ </div>
165
+ </div>
166
+ <Button type='submit' className='mx-auto w-full mt-4'>Confirm order</Button>
167
+ </form>
168
+ </Form>
169
+ )
170
+ }
171
+
172
+ export default ShippingStepForm
@@ -1,11 +1,11 @@
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
+ 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,48 +1,48 @@
1
- import React from 'react'
2
-
3
- import {
4
- Card,
5
- CardContent,
6
- CardFooter,
7
- CardHeader,
8
- CardTitle,
9
- MediaStack
10
- } from '@hanzo/ui/primitives'
11
-
12
- import { cn } from '@hanzo/ui/util'
13
-
14
- import { formatCurrencyValue } from '../../util'
15
- import type { LineItem } from '../../types'
16
-
17
- import AddToCartWidget from '../add-to-cart-widget'
18
-
19
- interface ProductCardProps extends React.HTMLAttributes<HTMLDivElement> {
20
- item: LineItem
21
- }
22
-
23
- const ProductCard: React.FC<ProductCardProps> = ({
24
- item,
25
- className,
26
- ...props
27
- }) => (
28
- <Card
29
- className={cn('max-h-[360px] lg:min-w-[200px] max-w-[260px] overflow-hidden', className)}
30
- {...props}
31
- >
32
- <CardHeader className='w-full border-b p-6 min-h-[180px] max-h-[240px] relative'>
33
- <MediaStack media={item} constrainTo={{w: 700, h:700}} clx='p-6' />
34
- </CardHeader>
35
- <CardContent className='grid gap-2.5 p-4'>
36
- <CardTitle className='text-sm sm:text-base flex flex-col justify-start items-center line-clap-3'>
37
- {item.title.split(', ').map((e, i) => (<p key={i}>{e}</p>))}
38
- <p className='mt-1 font-semibold'>{formatCurrencyValue(item.price)}</p>
39
- </CardTitle>
40
- </CardContent>
41
- <CardFooter className='p-4 flex flex-row justify-center'>
42
- <AddToCartWidget item={item} />
43
- </CardFooter>
44
- </Card>
45
- )
46
-
47
-
48
- export default ProductCard
1
+ import React from 'react'
2
+
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ CardFooter,
7
+ CardHeader,
8
+ CardTitle,
9
+ MediaStack
10
+ } from '@hanzo/ui/primitives'
11
+
12
+ import { cn } from '@hanzo/ui/util'
13
+
14
+ import { formatCurrencyValue } from '../../util'
15
+ import type { LineItem } from '../../types'
16
+
17
+ import AddToCartWidget from '../add-to-cart-widget'
18
+
19
+ interface ProductCardProps extends React.HTMLAttributes<HTMLDivElement> {
20
+ item: LineItem
21
+ }
22
+
23
+ const ProductCard: React.FC<ProductCardProps> = ({
24
+ item,
25
+ className,
26
+ ...props
27
+ }) => (
28
+ <Card
29
+ className={cn('max-h-[360px] lg:min-w-[200px] max-w-[260px] overflow-hidden', className)}
30
+ {...props}
31
+ >
32
+ <CardHeader className='w-full border-b p-6 min-h-[180px] max-h-[240px] relative'>
33
+ <MediaStack media={item} constrainTo={{w: 700, h:700}} clx='p-6' />
34
+ </CardHeader>
35
+ <CardContent className='grid gap-2.5 p-4'>
36
+ <CardTitle className='text-sm sm:text-base flex flex-col justify-start items-center line-clap-3'>
37
+ {item.title.split(', ').map((e, i) => (<p key={i}>{e}</p>))}
38
+ <p className='mt-1 font-semibold'>{formatCurrencyValue(item.price)}</p>
39
+ </CardTitle>
40
+ </CardContent>
41
+ <CardFooter className='p-4 flex flex-row justify-center'>
42
+ <AddToCartWidget item={item} />
43
+ </CardFooter>
44
+ </Card>
45
+ )
46
+
47
+
48
+ export default ProductCard