@hanzo/commerce 7.7.0 → 7.7.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 (90) hide show
  1. package/dist/components/checkout/payment-step-form/methods/card.js +20 -2
  2. package/dist/components/checkout/payment-step-form/methods/card.js.map +1 -1
  3. package/package.json +38 -9
  4. package/billing.ts +0 -2
  5. package/client.ts +0 -783
  6. package/components/Icons.tsx +0 -35
  7. package/components/add-to-cart-widget.tsx +0 -195
  8. package/components/buy/buy-card.tsx +0 -269
  9. package/components/buy/carousel-buy-card.tsx +0 -243
  10. package/components/buy/multi-family/all-variants-carousel.tsx +0 -259
  11. package/components/buy/multi-family/family-carousel/index.tsx +0 -75
  12. package/components/buy/multi-family/family-carousel/slide.tsx +0 -82
  13. package/components/buy/multi-family/family-carousel/state.ts +0 -87
  14. package/components/buy/multi-family/index.ts +0 -2
  15. package/components/buy/single-family-selector.tsx +0 -91
  16. package/components/buy/title-and-byline.tsx +0 -26
  17. package/components/cart/cart-panel/cart-line-item.tsx +0 -77
  18. package/components/cart/cart-panel/index.tsx +0 -157
  19. package/components/cart/cart-panel/promo-code.tsx +0 -105
  20. package/components/cart/cart-panel/total-area.tsx +0 -61
  21. package/components/checkout/payment-step-form/card-icon-row.tsx +0 -26
  22. package/components/checkout/payment-step-form/card-icons/amex.tsx +0 -32
  23. package/components/checkout/payment-step-form/card-icons/diners-club.tsx +0 -13
  24. package/components/checkout/payment-step-form/card-icons/discover.tsx +0 -25
  25. package/components/checkout/payment-step-form/card-icons/jcb.tsx +0 -26
  26. package/components/checkout/payment-step-form/card-icons/mastercard.tsx +0 -27
  27. package/components/checkout/payment-step-form/card-icons/visa.tsx +0 -25
  28. package/components/checkout/payment-step-form/cc-button.tsx +0 -18
  29. package/components/checkout/payment-step-form/contact-form.tsx +0 -48
  30. package/components/checkout/payment-step-form/crypto-icons/btc.tsx +0 -11
  31. package/components/checkout/payment-step-form/crypto-icons/eth.tsx +0 -20
  32. package/components/checkout/payment-step-form/crypto-icons/usdt.tsx +0 -13
  33. package/components/checkout/payment-step-form/index.tsx +0 -113
  34. package/components/checkout/payment-step-form/methods/bank-transfer.tsx +0 -81
  35. package/components/checkout/payment-step-form/methods/card.tsx +0 -230
  36. package/components/checkout/payment-step-form/methods/crypto.tsx +0 -226
  37. package/components/checkout/payment-step-form/methods/index.ts +0 -23
  38. package/components/checkout/shipping-step-form.tsx +0 -171
  39. package/components/index.ts +0 -11
  40. package/components/item/product-card.tsx +0 -66
  41. package/components/item-selector/button.tsx +0 -213
  42. package/components/item-selector/carousel/index.tsx +0 -196
  43. package/components/item-selector/carousel/slider.tsx +0 -37
  44. package/components/item-selector/index.ts +0 -5
  45. package/components/item-selector/quantity-indicator.tsx +0 -50
  46. package/components/node-tabs/index.tsx +0 -90
  47. package/components/node-tabs/node-image.tsx +0 -31
  48. package/index.ts +0 -55
  49. package/metering.test.ts +0 -199
  50. package/metering.ts +0 -289
  51. package/product-card.test.tsx +0 -104
  52. package/service/context.tsx +0 -45
  53. package/service/debug.ts +0 -41
  54. package/service/impls/standalone/actual-line-item.ts +0 -136
  55. package/service/impls/standalone/get-instance.ts +0 -64
  56. package/service/impls/standalone/index.ts +0 -579
  57. package/service/impls/standalone/order/firebase.ts +0 -5
  58. package/service/impls/standalone/order/index.ts +0 -58
  59. package/service/impls/standalone/persistence.ts +0 -33
  60. package/service/path-utils.ts +0 -26
  61. package/service/sep.ts +0 -7
  62. package/tsconfig.json +0 -17
  63. package/types/README.md +0 -2
  64. package/types/category-node.ts +0 -50
  65. package/types/checkout.ts +0 -47
  66. package/types/commerce-config.ts +0 -13
  67. package/types/commerce-service.ts +0 -128
  68. package/types/family.ts +0 -26
  69. package/types/index.ts +0 -15
  70. package/types/item-selector.ts +0 -97
  71. package/types/line-item.ts +0 -29
  72. package/types/multi-family-selector-props.ts +0 -20
  73. package/types/product.ts +0 -21
  74. package/types/promo.ts +0 -10
  75. package/types/selection-ui-specifier.ts +0 -52
  76. package/types/string-mutator.ts +0 -14
  77. package/types/token-separators.ts +0 -7
  78. package/util/analytics.ts +0 -21
  79. package/util/countries.ts +0 -196
  80. package/util/error.ts +0 -34
  81. package/util/index.ts +0 -71
  82. package/util/item-selector-options-accessor.ts +0 -35
  83. package/util/line-item-ref.ts +0 -23
  84. package/util/multi-family-selector-options-accessor.ts +0 -15
  85. package/util/obs-string-mutator.ts +0 -22
  86. package/util/product-media-accessor.ts +0 -58
  87. package/util/promo-codes.ts +0 -106
  88. package/util/selection-ui-specifiers.ts +0 -30
  89. package/util/square-payment.ts +0 -50
  90. package/util/use-sync-sku-param-w-current-item.ts +0 -88
@@ -1,35 +0,0 @@
1
- import {
2
- ShoppingCart,
3
- Menu,
4
- ChevronLeft,
5
- ChevronRight,
6
- Loader2,
7
- Check,
8
- Plus,
9
- Minus,
10
- ChevronDown,
11
- ChevronsLeft,
12
- ChevronsRight,
13
- Image,
14
- Trash2,
15
- Search,
16
- Barcode
17
- } from "lucide-react"
18
-
19
- export default {
20
- shoppingCart: ShoppingCart,
21
- menu: Menu,
22
- chevronLeft: ChevronLeft,
23
- chevronRight: ChevronRight,
24
- spinner: Loader2,
25
- check: Check,
26
- plus: Plus,
27
- minus: Minus,
28
- chevronDown: ChevronDown,
29
- chevronsLeft: ChevronsLeft,
30
- chevronsRight: ChevronsRight,
31
- placeholder: Image,
32
- trash: Trash2,
33
- search: Search,
34
- barcode: Barcode
35
- }
@@ -1,195 +0,0 @@
1
- 'use client'
2
- import React, { useEffect, useRef } from 'react'
3
- import { reaction, type IReactionDisposer } from 'mobx'
4
- import { observer } from 'mobx-react-lite'
5
-
6
- import {
7
- Button,
8
- buttonVariants,
9
- cn,
10
- sx,
11
- } from '@hanzo/ui'
12
- import Icons from './Icons'
13
- import type { LineItem } from '../types'
14
- import { sendFBEvent, sendGAEvent } from '../util/analytics'
15
-
16
- const AddToCartWidget: React.FC<{
17
- item: LineItem
18
- disabled?: boolean
19
- className?: string
20
- buttonClx?: string
21
- variant?: 'minimal' | 'primary' | 'primary-smaller' | 'outline'
22
- onQuantityChanged?: (sku: string, oldV: number, newV: number) => void
23
- }> = observer(({
24
- item,
25
- variant='primary',
26
- disabled=false,
27
- className='',
28
- buttonClx='',
29
- onQuantityChanged
30
- }) => {
31
-
32
- const reactionDisposer = useRef<IReactionDisposer | undefined>(undefined)
33
- useEffect(() => {
34
- if (onQuantityChanged) {
35
- reactionDisposer.current = reaction(
36
- () => (item.quantity),
37
- (quantity: number, previous: number) => {
38
- onQuantityChanged(item.sku, quantity, previous)
39
- }
40
- )
41
- }
42
- return () => {
43
- if (reactionDisposer.current) {
44
- reactionDisposer.current()
45
- }
46
- }
47
- }, [])
48
-
49
- // `rounded-lg` written out, not interpolated. The note that used to sit here
50
- // said safelisting was unnecessary "since its used widely" — which is true
51
- // only for as long as some OTHER file in whatever the consumer scans spells it
52
- // literally. Tailwind reads source text; a template literal is not a class
53
- // name, so this one was borrowing a rule it did not ask for.
54
- const ROUNDED_CLX = ' rounded-lg ' // the class
55
-
56
- const ghost = variant === 'minimal'
57
- const outline = variant === 'outline'
58
- const primary = variant === 'primary'
59
- const priSmaller = variant === 'primary-smaller'
60
-
61
- let iconClx = ghost ? 'h-4 w-4 md:h-3 md:w-3 text-muted-3 ' : (priSmaller ? 'h-4 w-6 px-0.5 opacity-70' : 'h-5 w-7 px-1 opacity-70 ')
62
- iconClx += ghost ? 'group-hover:text-foreground' : 'group-hover:opacity-100'
63
-
64
- let digitClx = ghost ? 'px-2 md:px-0.5 ' : 'sm:px-2 font-semibold '
65
- digitClx += (ghost || outline) ? 'text-foreground ' : 'text-primary-fg '
66
-
67
- if (disabled) {
68
- return (
69
- <div className={cn('flex flex-row items-stretch' + ROUNDED_CLX + (!(primary || priSmaller) ? 'bg-transparent' : 'bg-primary'), className)}>
70
- <div className={'text-sm flex items-center cursor-default ' + digitClx} >{item.quantity}</div>
71
- </div>
72
- )
73
- }
74
-
75
- const inc = (event: React.MouseEvent<HTMLElement>) => {
76
- item.increment()
77
- event.stopPropagation() // in case we're part of a larger selection UI
78
- sendGAEvent('add_to_cart', {
79
- items: [{
80
- item_id: item.sku,
81
- item_name: item.title,
82
- item_category: item.familyId,
83
- price: item.price,
84
- quantity: item.quantity
85
- }],
86
- value: item.price,
87
- currency: 'USD',
88
- })
89
- sendFBEvent('AddToCart', {
90
- content_ids: [item.sku],
91
- contents: [{
92
- id: item.sku,
93
- quantity: item.quantity
94
- }],
95
- content_name: item.title,
96
- value: item.price,
97
- currency: 'USD',
98
- })
99
- }
100
-
101
- const dec = (event: React.MouseEvent<HTMLElement>) => {
102
- item.decrement()
103
- event.stopPropagation() // in case we're part of a larger selection UI
104
- sendGAEvent('remove_from_cart', {
105
- items: [{
106
- item_id: item.sku,
107
- item_name: item.title,
108
- item_category: item.familyId,
109
- price: item.price,
110
- quantity: item.quantity
111
- }],
112
- value: item.price,
113
- currency: 'USD',
114
- })
115
- }
116
-
117
- return ( item.isInCart ? (
118
- <div className={cn(
119
- 'flex flex-row items-stretch justify-between ',
120
- // should match 'sm' and 'default' button heights
121
- (ghost || priSmaller ? 'h-8' : 'h-9'),
122
- ROUNDED_CLX,
123
- (primary || priSmaller ? 'bg-primary' : 'bg-transparent'),
124
- (outline ? 'border border-muted' : ''),
125
- className
126
- )}>
127
- <Button
128
- aria-label={'Remove a ' + item.title + ' from the cart'}
129
- size={ghost || priSmaller ? 'sm' : 'default'}
130
- variant={primary || priSmaller ? 'primary' : 'ghost'}
131
- {...sx(ghost ? 'rounded-full' : 'rounded-lg')}
132
- className={cn(
133
- 'lg:min-w-0 lg:px-2 grow justify-start group',
134
- (ghost || priSmaller ? 'px-1' : 'px-2'),
135
- (outline ? 'hover:bg-transparent' : ''),
136
- buttonClx,
137
- 'h-auto self-stretch' // must be smaller than normal
138
- )}
139
- key='left'
140
- onClick={dec}
141
- >
142
- {(item.quantity > 1) ? (
143
- <Icons.minus className={iconClx} aria-hidden='true'/>
144
- ) : (
145
- <Icons.trash className={iconClx} aria-hidden='true'/>
146
- )}
147
- </Button>
148
- <div className={cn(
149
- 'grow-0 shrink-0 flex items-center cursor-default xs:px-2',
150
- priSmaller || ghost ? 'text-xs' : 'text-sm',
151
- digitClx
152
- )}>
153
- {item.quantity}{ghost ? '' : ' in Bag'}
154
- </div>
155
- <Button
156
- aria-label={'Add another ' + item.title + ' to the cart'}
157
- itemProp='potentialAction'
158
- itemScope
159
- itemType='https://schema.org/AddAction'
160
- size={ghost || priSmaller ? 'sm' : 'default'}
161
-
162
- variant={primary || priSmaller ? 'primary' : 'ghost'}
163
- {...sx(ghost ? 'rounded-full' : 'rounded-lg')}
164
- className={cn(
165
- 'lg:min-w-0 lg:px-2 grow justify-end group',
166
- (ghost || priSmaller ? 'px-1' : 'px-2'),
167
- (outline ? 'hover:bg-transparent' : ''),
168
- buttonClx,
169
- 'h-auto self-stretch' // must be smaller than normal
170
- )}
171
- onClick={inc}
172
- key='right'
173
- >
174
- <Icons.plus className={iconClx} aria-hidden='true'/>
175
- </Button>
176
- </div>
177
- ) : (
178
- <Button
179
- aria-label={'Add a ' + item.title + ' to cart'}
180
- itemProp='potentialAction'
181
- itemScope
182
- itemType='https://schema.org/AddAction'
183
- size={ghost || priSmaller ? 'sm' : 'default'}
184
- variant={ghost ? 'ghost' : (primary || priSmaller ? 'primary' : 'outline')}
185
- {...sx('rounded-lg')}
186
- className={cn(buttonClx, className)}
187
- onClick={inc}
188
- >
189
- <span className='m1-1'>Add</span>
190
- <Icons.plus className='h-5 w-5 ml-1' aria-hidden='true'/>
191
- </Button>
192
- ))
193
- })
194
-
195
- export default AddToCartWidget
@@ -1,269 +0,0 @@
1
- 'use client'
2
- import React, { useRef, useEffect, type ComponentType } from 'react'
3
- import { reaction, type IReactionDisposer } from 'mobx'
4
- import { observer } from 'mobx-react-lite'
5
-
6
- import {
7
- cn,
8
- ApplyTypography,
9
- MediaStack,
10
- } from '@hanzo/ui'
11
- import type {
12
- ItemSelectorProps,
13
- ItemSelectorCompProps,
14
- LineItem,
15
- Family,
16
- CategoryNode,
17
- } from '../../types'
18
-
19
- import { useCommerce } from '../../service/context'
20
- import * as pathUtils from '../../service/path-utils'
21
- import { getFacetValuesMutator, ObsStringMutator } from '../../util'
22
-
23
- import NodeTabs from '../node-tabs'
24
- import AddToCartWidget from '../add-to-cart-widget'
25
-
26
- const BuyCard: React.FC<{
27
- skuPath: string
28
-
29
- /** For any selectors that show a list of choices,
30
- * starting with 'scrollAfter' elements,
31
- * the list will scroll, and the card will
32
- * have 'scrollHeightClx' applied to it to define and fix the height.
33
- * This is most like something like '80vh'
34
- * defaults are '5' and 'h-[70vh]'
35
- * */
36
- scrollAfter?: number
37
- scrollHeightClx?: string
38
-
39
- clx?: string
40
- famWidgetClx?: string
41
- addWidgetClx?: string
42
-
43
- selector: ComponentType<ItemSelectorProps>
44
- selectorProps?: ItemSelectorCompProps
45
-
46
- /** Show all items from all sibling families
47
- * If skuPath defines a Family, the first of it's items will
48
- * be selected. The facet widget will just select a the first
49
- * item in the chosen Family without changings the overall set
50
- * of choices. */
51
- allVariants?: boolean
52
-
53
- familyTabAs?: 'image' | 'label' | 'image-and-label'
54
- showItemMedia?: boolean
55
-
56
- onQuantityChanged?: (sku: string, oldV: number, newV: number) => void
57
- mobile?: boolean
58
- }> = observer(({
59
- skuPath,
60
- scrollAfter=5,
61
- scrollHeightClx='h-[80vh]',
62
- clx='',
63
- famWidgetClx='',
64
- addWidgetClx='',
65
- selector: Selector,
66
- selectorProps={
67
- clx: '',
68
- soleItemClx: '',
69
- itemClx: '',
70
- ext: {}
71
- },
72
- familyTabAs='image-and-label',
73
- showItemMedia=true,
74
- allVariants=false,
75
- mobile=false,
76
- onQuantityChanged,
77
- }) => {
78
-
79
- const cmmc = useCommerce()
80
- const inst = useRef<{
81
- level: number,
82
- requestedFamily : Family | undefined
83
- requestedNode: CategoryNode | undefined
84
- currentFamTokenMutator: ObsStringMutator
85
- disposers: IReactionDisposer[]
86
- } | undefined>(undefined)
87
-
88
-
89
- useEffect(() => {
90
-
91
- let requestedFamily = cmmc.getFamilyById(skuPath)
92
- let requestedNode = requestedFamily ? undefined : cmmc.getNodeAtPath(skuPath)
93
- let initialFamily = undefined
94
-
95
- const { paths, level } = pathUtils.getSelectedPaths(skuPath)
96
-
97
- if (level === 0) {
98
- throw new Error('BuyCard.useEffect(): must specify at least at least one Level in skuPath!')
99
- }
100
- if (requestedFamily) {
101
- if (allVariants && level >= 2) {
102
- // select all siblings of requestedFamily.
103
- // ie, go one level back
104
- delete paths[level]
105
- initialFamily = requestedFamily
106
- requestedFamily = undefined
107
- requestedNode = cmmc.getNodeAtPath(pathUtils.getParentPath(skuPath))
108
- }
109
- }
110
- else {
111
- // select siblings paths
112
- if (allVariants) {
113
- paths[level + 1] = [...requestedNode!.subNodes!.map((node) => (node.skuToken))]
114
- }
115
- // Actually select the the first fam at the fam level,
116
- else {
117
- paths[level + 1] = [requestedNode!.subNodes![0].skuToken]
118
- }
119
- }
120
-
121
- const selectedFams = cmmc.selectPaths(paths)
122
- initialFamily = initialFamily ? initialFamily : (requestedFamily ? requestedFamily : selectedFams[0])
123
- cmmc.setCurrentItem(initialFamily.products[0].sku)
124
- const currentFamTokenMutator = new ObsStringMutator(pathUtils.lastToken(initialFamily!.id))
125
-
126
- inst.current = {
127
- level,
128
- requestedFamily,
129
- requestedNode,
130
- currentFamTokenMutator,
131
- disposers: []
132
- }
133
-
134
- if (!allVariants) {
135
- inst.current?.disposers.push(reaction(
136
- () => {
137
- const fams = cmmc.selectedFamilies
138
- return (fams.length > 0) ? fams[0].id : undefined
139
- },
140
- (famId) => {
141
- if (famId && famId !== cmmc.currentItem?.familyId) {
142
- const fam = cmmc.getFamilyById(famId)
143
- if (fam) {
144
- cmmc.setCurrentItem(fam.products[0].sku)
145
- }
146
- }
147
- }
148
- ))
149
- }
150
-
151
- return () => {
152
- inst.current?.disposers.forEach((d) => {d()})
153
- }
154
-
155
- }, [])
156
-
157
- const setFamilyPath = (pathValue: string | null) => {
158
- if (inst.current?.currentFamTokenMutator.get() !== pathValue) {
159
- inst.current?.currentFamTokenMutator.set(pathValue)
160
- }
161
- const found = cmmc.selectedItems.find((item) => (item.familyId.endsWith(pathValue!)))
162
- if (found) {
163
- cmmc.setCurrentItem(found.sku)
164
- }
165
- }
166
-
167
- const selectSku = (sku: string) => {
168
- cmmc.setCurrentItem(sku)
169
- const pathValue = pathUtils.lastToken(cmmc.currentItem!.familyId)
170
- if (pathValue !== inst.current?.currentFamTokenMutator.get()) {
171
- inst.current?.currentFamTokenMutator.set(pathValue)
172
- }
173
- }
174
-
175
- const famTitle = inst.current?.requestedFamily ? inst.current.requestedFamily.title : cmmc.selectedFamilies[0].title
176
-
177
- const itemsToShow = (!cmmc.hasSelection) ? undefined :
178
- allVariants ? cmmc.selectedItems : cmmc.selectedFamilies[0].products as LineItem[]
179
-
180
-
181
- const TitleArea: React.FC<{
182
- title: string
183
- byline?: string
184
- clx?: string
185
- }> = ({
186
- title,
187
- byline,
188
- clx=''
189
- }) => (
190
- <ApplyTypography className={clx}>
191
- <h3>{title}</h3>
192
- {byline && (<h6>{byline}</h6>)}
193
- </ApplyTypography>
194
- )
195
-
196
- const scroll = !!(itemsToShow && itemsToShow.length > scrollAfter)
197
- return (
198
- <div className={cn(
199
- 'px-4 md:px-6 pt-3 pb-4 flex flex-col items-center min-h-[60vh]',
200
- clx,
201
- scroll ? scrollHeightClx : 'h-auto'
202
- )} >
203
- {inst.current?.requestedNode && (<>
204
- <ApplyTypography className={'mb-2 ' + (scroll ? 'shrink-0' : '')}>
205
- <h3>{inst.current!.requestedNode.label}</h3>
206
- {inst.current!.requestedNode.subNodesLabel && (
207
- <h6 className='!text-center font-bold text-muted mt-3'>{inst.current!.requestedNode.subNodesLabel}</h6>
208
- )}
209
- </ApplyTypography>
210
- <NodeTabs
211
- className={cn(
212
- 'grid gap-0 align-stretch justify-normal',
213
- 'border-b-2 rounded-lg border-level-3 mb-4 -mr-2 -ml-2 max-w-[460px] h-10', // height is needed for iPhone bug
214
- (scroll ? 'shrink-0' : ''),
215
- famWidgetClx
216
- )}
217
- // One column per sub-node. The count used to be interpolated into a
218
- // column-count utility in the className, and Tailwind's extractor never
219
- // saw it: the extractor reads source text, and a template literal is not
220
- // a class name. The element got `display:grid` with the default
221
- // `grid-template-columns: none`, so every family tab row stacked in a
222
- // single column. `repeat(n, minmax(0, 1fr))` is exactly what the utility
223
- // would have compiled to, and it holds for any n.
224
- style={{ gridTemplateColumns: `repeat(${inst.current.requestedNode.subNodes!.length}, minmax(0, 1fr))` }}
225
- mobile={mobile}
226
- mutator={allVariants ?
227
- {
228
- get: () => (inst.current!.currentFamTokenMutator.get()),
229
- set: setFamilyPath
230
- }
231
- :
232
- getFacetValuesMutator(inst.current.level + 1, cmmc)
233
- }
234
- itemClx='flex-col h-auto gap-0 py-1 px-3'
235
- buttonClx={
236
- 'h-full ' +
237
- '!border-level-3'
238
- }
239
- levelNodes={inst.current.requestedNode.subNodes!}
240
- show={familyTabAs}
241
- />
242
- </>)}
243
- {!inst.current?.requestedNode && famTitle && (
244
- <TitleArea title={famTitle} clx=''/>
245
- )}
246
- {(cmmc.currentItem && showItemMedia) && (
247
- <MediaStack media={cmmc.currentItem} constrainTo={{w: 200, h: 200}} className={(scroll ? 'shrink-0' : '')}/>
248
- )}
249
- {itemsToShow && (
250
- <Selector
251
- items={itemsToShow}
252
- selectedItemRef={cmmc}
253
- selectSku={selectSku}
254
- {...selectorProps}
255
- scrollable={scroll}
256
- />
257
- )}
258
- {(cmmc.currentItem) && (
259
- <AddToCartWidget
260
- item={cmmc.currentItem}
261
- onQuantityChanged={onQuantityChanged}
262
- className={cn('min-w-[160px] mx-auto mt-4', (scroll ? 'shrink-0' : ''), addWidgetClx)}
263
- />
264
- )}
265
- </div >
266
- )
267
- })
268
-
269
- export default BuyCard