@hanzo/commerce 5.1.3 → 6.0.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.
Files changed (59) hide show
  1. package/components/{buy-item/select-category-item-card.tsx → buy/_to_deprecate_select-category-item-card.tsx} +20 -31
  2. package/components/{select-category-item-panel.tsx → buy/_to_deprecate_select-category-item-panel.tsx} +12 -20
  3. package/components/{buy-item/buy-item-popup.tsx → buy/_unused_buy-popup.tsx_} +4 -4
  4. package/components/{add-to-cart-widget.tsx → buy/add-to-cart-widget.tsx} +5 -3
  5. package/components/buy/buy-button.tsx +31 -0
  6. package/components/buy/buy-card.tsx +169 -0
  7. package/components/buy/buy-drawer.tsx +78 -0
  8. package/components/buy/buy-trigger-wrapper.tsx +20 -0
  9. package/components/{cart-accordian.tsx → cart/cart-accordian.tsx} +2 -1
  10. package/components/{cart-panel → cart/cart-panel}/cart-line-item.tsx +28 -5
  11. package/components/{cart-panel → cart/cart-panel}/index.tsx +3 -3
  12. package/components/{cart-panel → cart/cart-panel}/promo-code.tsx +3 -3
  13. package/components/{payment-step-form → checkout/payment-step-form}/contact-form.tsx +1 -1
  14. package/components/{payment-step-form → checkout/payment-step-form}/index.tsx +3 -3
  15. package/components/{payment-step-form → checkout/payment-step-form}/methods/bank-transfer.tsx +1 -1
  16. package/components/{payment-step-form → checkout/payment-step-form}/methods/card.tsx +4 -4
  17. package/components/{payment-step-form → checkout/payment-step-form}/methods/crypto.tsx +3 -3
  18. package/components/{payment-step-form → checkout/payment-step-form}/methods/index.ts +1 -1
  19. package/components/{shipping-step-form.tsx → checkout/shipping-step-form.tsx} +4 -4
  20. package/components/facet-values-widget/facet-image.tsx +2 -2
  21. package/components/facet-values-widget/index.tsx +13 -12
  22. package/components/index.ts +19 -17
  23. package/components/item/item-media.tsx +58 -0
  24. package/components/{product-card.tsx → item/product-card.tsx} +5 -7
  25. package/components/select/carousel-selector.tsx +64 -0
  26. package/components/select/image-selector.tsx +125 -0
  27. package/components/select/radio-selector.tsx +66 -0
  28. package/package.json +2 -1
  29. package/service/context.tsx +4 -4
  30. package/service/impls/standalone/index.ts +4 -4
  31. package/service/impls/standalone/standalone-service.ts +74 -62
  32. package/types/commerce-service.ts +20 -16
  33. package/types/index.ts +2 -2
  34. package/types/item-selector.ts +12 -5
  35. package/types/product.ts +1 -0
  36. package/types/tree-node.ts +24 -0
  37. package/util/index.ts +9 -9
  38. package/util/use-sync-sku-param-w-current-item.ts +5 -5
  39. package/components/buy-item/buy-item-button-wrapper.tsx +0 -27
  40. package/components/buy-item/buy-item-button.tsx +0 -34
  41. package/components/buy-item/buy-item-card.tsx +0 -92
  42. package/components/buy-item/buy-item-mobile-drawer.tsx +0 -54
  43. package/components/buy-item/select-category-and-item-widget.tsx +0 -83
  44. package/components/category-item-radio-selector.tsx +0 -55
  45. package/components/category-item-scroll-selector.tsx +0 -40
  46. package/components/item-carousel.tsx +0 -80
  47. package/types/facet.ts +0 -35
  48. /package/components/{cart-icon.tsx → cart/cart-icon.tsx} +0 -0
  49. /package/components/{payment-step-form → checkout/payment-step-form}/card-icon-row.tsx +0 -0
  50. /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/amex.tsx +0 -0
  51. /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/diners-club.tsx +0 -0
  52. /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/discover.tsx +0 -0
  53. /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/jcb.tsx +0 -0
  54. /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/mastercard.tsx +0 -0
  55. /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/visa.tsx +0 -0
  56. /package/components/{payment-step-form → checkout/payment-step-form}/cc-button.tsx +0 -0
  57. /package/components/{payment-step-form → checkout/payment-step-form}/crypto-icons/btc.tsx +0 -0
  58. /package/components/{payment-step-form → checkout/payment-step-form}/crypto-icons/eth.tsx +0 -0
  59. /package/components/{payment-step-form → checkout/payment-step-form}/crypto-icons/usdt.tsx +0 -0
@@ -7,37 +7,36 @@ import { Skeleton } from '@hanzo/ui/primitives'
7
7
 
8
8
  import type { ItemSelector, LineItem } from '../../types'
9
9
 
10
- import AddToCartWidget from '../add-to-cart-widget'
11
- import CategoryItemRadioSelector from '../category-item-radio-selector'
12
- import CategoryItemScrollSelector from '../category-item-scroll-selector'
10
+ import AddToCartWidget from './add-to-cart-widget'
11
+ import RadioItemSelector from '../select/radio-selector'
13
12
  import { formatCurrencyValue } from '../../util'
14
13
 
15
14
  const SelectCategoryItemCard: React.FC<React.HTMLAttributes<HTMLDivElement> & ItemSelector & {
16
15
  isLoading?: boolean
17
16
  mobile?: boolean
18
- noTitle?: boolean
17
+ title?: string
19
18
  onQuantityChanged?: (sku: string, oldV: number, newV: number) => void
20
19
  }> = /* NOT observer */({
21
- category,
20
+ items,
22
21
  selectedItemRef: selItemRef,
23
22
  selectSku,
24
23
  className,
25
24
  isLoading = false,
26
25
  mobile = false,
27
- noTitle = false,
26
+ title,
28
27
  onQuantityChanged,
29
28
  ...props
30
29
  }) => {
31
30
 
32
- const soleOption = category.products.length === 1
31
+ const soleOption = items.length === 1
33
32
 
34
33
  const SelectProductComp: React.FC<{ className?: string }> = ({
35
34
  className = ''
36
35
  }) => {
37
36
 
38
- const mobilePicker = (mobile || category.products.length > 6)
37
+ const mobilePicker = (mobile || items.length > 6)
39
38
  if (soleOption) {
40
- const item = category.products[0] as LineItem
39
+ const item = items[0] as LineItem
41
40
  return (
42
41
  <div className={cn('flex flex-col justify-center items-center ' + (mobilePicker ? 'h-[180px] ' : 'h-auto min-h-24'), className)}>
43
42
  <p className='text-lg text-center font-semibold'>{item.titleAsOption + ', ' + formatCurrencyValue(item.price)}</p>
@@ -50,25 +49,15 @@ const SelectCategoryItemCard: React.FC<React.HTMLAttributes<HTMLDivElement> & It
50
49
  'sm:w-pr-80 sm:mx-auto md:w-full flex flex-col justify-start items-center',
51
50
  className
52
51
  )}>
53
- {!noTitle && (<div className={'h-[1px] bg-muted-3 ' + (mobilePicker ? 'w-pr-55' : 'w-pr-60') } /> )}
54
- {mobilePicker ? (
55
- <CategoryItemScrollSelector
56
- category={category}
57
- selectedItemRef={selItemRef}
58
- selectSku={selectSku}
59
- itemClx='h-10 border-b px-4'
60
- outerClx='min-w-pr-80 h-[180px]' // 80% of 65% parent
61
- />
62
- ) : (
63
- <CategoryItemRadioSelector
64
- category={category}
65
- selectedItemRef={selItemRef}
66
- selectSku={selectSku}
67
- groupClx='mt-2'
68
- showQuantity={false}
69
- itemClx='flex flex-row gap-2.5 items-center'
70
- />
71
- )}
52
+ {title && (<div className={'h-[1px] bg-muted-3 ' + (mobilePicker ? 'w-pr-55' : 'w-pr-60') } /> )}
53
+ <RadioItemSelector
54
+ items={items}
55
+ selectedItemRef={selItemRef}
56
+ selectSku={selectSku}
57
+ clx='mt-2'
58
+ showQuantity={false}
59
+ itemClx='flex flex-row gap-2.5 items-center'
60
+ />
72
61
  </div>
73
62
  )
74
63
  }
@@ -90,7 +79,7 @@ const SelectCategoryItemCard: React.FC<React.HTMLAttributes<HTMLDivElement> & It
90
79
  isLoading ? (<Skeleton className={'h-8 w-full ' + className} />) : (
91
80
 
92
81
  <div className={cn('text-center flex flex-col justify-start items-center', className)}>
93
- <p className='font-heading text-center'>{category.title}</p>
82
+ <p className='font-heading text-center'>{title}</p>
94
83
  </div>
95
84
 
96
85
  )))
@@ -103,13 +92,13 @@ const SelectCategoryItemCard: React.FC<React.HTMLAttributes<HTMLDivElement> & It
103
92
  )}
104
93
  {...props}
105
94
  >
106
- {!noTitle && (<TitleArea className='grow pt-3 mb-0' />)}
95
+ {title && (<TitleArea className='grow pt-3 mb-0' />)}
107
96
  <SelectProductComp className='w-pr-65' />
108
97
  <AddToCartComp className='w-pr-65' />
109
98
  </div>
110
99
  ) : (
111
100
  <div className={cn('', className)} {...props}>
112
- {!noTitle && (<TitleArea className='' />)}
101
+ {title && (<TitleArea className='' />)}
113
102
  <div className='flex flex-col justify-start items-center gap-4'>
114
103
  <SelectProductComp />
115
104
  <AddToCartComp className='' />
@@ -6,17 +6,20 @@ import { observer } from 'mobx-react-lite'
6
6
  import { cn } from '@hanzo/ui/util'
7
7
  import { Skeleton } from '@hanzo/ui/primitives'
8
8
 
9
- import type { ItemSelector } from '../types'
10
- import { formatCurrencyValue } from '../util'
11
- import { Icons } from './Icons'
9
+ import type { Category, ObsLineItemRef, LineItem } from '../../types'
10
+ import { formatCurrencyValue } from '../../util'
11
+ import { Icons } from '../Icons'
12
12
 
13
13
  import AddToCartWidget from './add-to-cart-widget'
14
- import CategoryItemRadioSelector from './category-item-radio-selector'
15
- import CategoryItemScrollSelector from './category-item-scroll-selector'
14
+ import RadioItemSelector from '../select/radio-selector'
16
15
 
17
16
  const SelectCategoryItemPanel: React.FC<
18
- React.HTMLAttributes<HTMLDivElement> & ItemSelector &
17
+ React.HTMLAttributes<HTMLDivElement> &
19
18
  {
19
+ category: Category
20
+ selectedItemRef: ObsLineItemRef
21
+ selectSku: (sku: string) => void
22
+ showQuantity?: boolean
20
23
  isLoading?: boolean
21
24
  mobile?: boolean
22
25
  }
@@ -88,25 +91,14 @@ const SelectCategoryItemPanel: React.FC<
88
91
  <h6 className='text-center font-semibold'>Available options</h6>
89
92
  <div className={'h-[1px] bg-muted-3 ' + (mobilePicker ? 'w-pr-55' : 'w-pr-60') } />
90
93
  </div>
91
- {mobilePicker ? (
92
- <CategoryItemScrollSelector
93
- category={category}
94
+ <RadioItemSelector
95
+ items={category.products as LineItem[]}
94
96
  selectedItemRef={selectedItemRef}
95
97
  selectSku={selectSku}
96
98
  showQuantity={showQuantity}
97
- itemClx='h-10 border-b px-4'
98
- outerClx='mb-4 h-[180px]'
99
- />
100
- ) : (
101
- <CategoryItemRadioSelector
102
- category={category}
103
- selectedItemRef={selectedItemRef}
104
- selectSku={selectSku}
105
- showQuantity={showQuantity}
106
- groupClx='block columns-2 gap-4'
99
+ clx='block columns-2 gap-4'
107
100
  itemClx='flex flex-row gap-2 items-center mb-2.5'
108
101
  />
109
- )}
110
102
  </div>
111
103
  )
112
104
  })
@@ -12,9 +12,9 @@ import {
12
12
 
13
13
  import { cn } from '@hanzo/ui/util'
14
14
 
15
- import BuyItemCard from './buy-item-card'
15
+ import BuyCard from './buy-item-card'
16
16
 
17
- const BuyItemPopup: React.FC<PropsWithChildren & {
17
+ const BuyPopup: React.FC<PropsWithChildren & {
18
18
  skuPath: string
19
19
  triggerClx?: string
20
20
  popupClx?: string
@@ -42,10 +42,10 @@ const BuyItemPopup: React.FC<PropsWithChildren & {
42
42
  </PopoverTrigger>
43
43
  <PopoverContent className={cn('relative flex flex-col p-0 px-4 pb-4 pt-2', popupClx)}>
44
44
  <PopoverClose className='absolute z-20 right-2 top-2 self-end hover:bg-level-3 text-muted hover:text-accent p-1 rounded-full'><X className='w-5 h-5'/></PopoverClose>
45
- <BuyItemCard skuPath={skuPath} onQuantityChanged={onQuantityChanged} className={cn("w-full relative ", cardClx)}/>
45
+ <BuyCard skuPath={skuPath} onQuantityChanged={onQuantityChanged} className={cn("w-full relative ", cardClx)}/>
46
46
  </PopoverContent>
47
47
  </Popover>
48
48
  )
49
49
  }
50
50
 
51
- export default BuyItemPopup
51
+ export default BuyPopup
@@ -5,9 +5,9 @@ import { observer } from 'mobx-react-lite'
5
5
  import { Button, toast, type ButtonSizes } from '@hanzo/ui/primitives'
6
6
  import { cn } from '@hanzo/ui/util'
7
7
 
8
- import { Icons } from './Icons'
9
- import type { LineItem } from '../types'
10
- import { sendFBEvent, sendGAEvent } from '../util/analytics'
8
+ import { Icons } from '../Icons'
9
+ import type { LineItem } from '../../types'
10
+ import { sendFBEvent, sendGAEvent } from '../../util/analytics'
11
11
 
12
12
  const AddToCartWidget: React.FC<{
13
13
  item: LineItem
@@ -44,12 +44,14 @@ const AddToCartWidget: React.FC<{
44
44
  if (onQuantityChanged) {
45
45
  onQuantityChanged(item.sku, old, old + 1)
46
46
  }
47
+ /*
47
48
  if (old === 0) {
48
49
  toast(`Added ${item.title} to your bag.`)
49
50
  }
50
51
  else {
51
52
  toast(`Changed quantity to ${old + 1} for ${item.title}.`)
52
53
  }
54
+ */
53
55
  sendGAEvent('add_to_cart', {
54
56
  items: [{
55
57
  item_id: item.sku,
@@ -0,0 +1,31 @@
1
+ 'use client'
2
+ import React, {type PropsWithChildren} from 'react'
3
+
4
+ import { type ButtonVariants, type ButtonSizes, Button } from '@hanzo/ui/primitives'
5
+
6
+ import BuyTriggerWrapper from './buy-trigger-wrapper'
7
+ import { cn } from '@hanzo/ui/util'
8
+
9
+ const BuyButton: React.FC<PropsWithChildren & {
10
+ skuPath: string
11
+ variant? : ButtonVariants
12
+ size?: ButtonSizes
13
+ /* rounded?: ButtonRounded // TODO: wait for version bump*/
14
+ className?: string
15
+ mobile?: boolean
16
+ }> = ({
17
+ skuPath,
18
+ variant,
19
+ size,
20
+ children,
21
+ className='',
22
+ mobile=false
23
+ }) => (
24
+ <BuyTriggerWrapper skuPath={skuPath} mobile={mobile}
25
+ trigger={ <Button size={size} variant={variant} className={cn(className, '')}>{children}</Button> }
26
+ />
27
+ )
28
+
29
+
30
+
31
+ export default BuyButton
@@ -0,0 +1,169 @@
1
+ 'use client'
2
+ import React, { useRef, useEffect, type ComponentType } from 'react'
3
+ import { autorun } from 'mobx'
4
+ import { observer } from 'mobx-react-lite'
5
+
6
+ import { cn } from '@hanzo/ui/util'
7
+
8
+ import type { SelectedPaths, ItemSelectorProps, LineItem } from '../../types'
9
+ import { useCommerce } from '../../service/context'
10
+ import { getFacetValuesMutator } from '../../util'
11
+
12
+ import FacetValuesWidget from '../facet-values-widget'
13
+ import AddToCartWidget from './add-to-cart-widget'
14
+ import ItemMedia from '../item/item-media'
15
+ import { ApplyTypography } from '@hanzo/ui/primitives'
16
+
17
+ const BuyCard: React.FC<{
18
+ skuPath: string
19
+ selector: ComponentType<ItemSelectorProps>
20
+ selShowPrice?: boolean
21
+ selShowQuantity?: boolean
22
+ selClx?: string
23
+ selSoleItemClx?: string
24
+ selItemClx?: string
25
+ selExt?: any
26
+ allVariants?: boolean
27
+ className?: string
28
+ facetsWidgetClx?: string
29
+ facetsAs?: 'image' | 'label' | 'image-and-label'
30
+ addWidgetClx?: string
31
+ mobile?: boolean
32
+ onQuantityChanged?: (sku: string, oldV: number, newV: number) => void
33
+ }> = observer(({
34
+ skuPath,
35
+ className='',
36
+ facetsWidgetClx='',
37
+ selector: Selector,
38
+ selShowPrice=true,
39
+ selShowQuantity=false,
40
+ selClx='',
41
+ selItemClx='',
42
+ selSoleItemClx='',
43
+ selExt,
44
+ addWidgetClx='',
45
+ facetsAs='image-and-label',
46
+ allVariants=true,
47
+ mobile=false,
48
+ onQuantityChanged,
49
+ }) => {
50
+
51
+ const cmmc = useCommerce()
52
+ const levelRef = useRef<number>(-1)
53
+
54
+ const requestedCat = cmmc.getCategory(skuPath)
55
+ const levelNode = requestedCat ? undefined : cmmc.getNodeAtPath(skuPath)
56
+
57
+ useEffect(() => {
58
+
59
+ const toks = skuPath.split('-')
60
+ levelRef.current = toks.length - 1
61
+ if (levelRef.current === 0) {
62
+ throw new Error('BuyCard.useEffect(): must specify at least a Level 1 skuPath!')
63
+ }
64
+ const fsv: SelectedPaths = {}
65
+ for (let level = 1; level <= levelRef.current; level++ ) {
66
+ fsv[level] = [toks[level]]
67
+ }
68
+ // Actually specify the requested Cat,
69
+ // or the first Cat if no Cats at this level
70
+ if (!requestedCat) {
71
+ fsv[levelRef.current + 1] = [levelNode!.subNodes![0].skuToken]
72
+ }
73
+ cmmc.selectPaths(fsv)
74
+
75
+ return autorun(() => {
76
+ const cats = cmmc.selectedCategories
77
+ // Original requestedCat was legit
78
+ if (requestedCat /* && (cats.length === 0 || cats[0].id !== requestedCat.id) */) {
79
+ if (
80
+ !cmmc.currentItem
81
+ ||
82
+ cmmc.currentItem.categoryId !== requestedCat.id
83
+ ||
84
+ requestedCat.products.length === 1
85
+ ) {
86
+ cmmc.setCurrentItem(requestedCat.products[0].sku)
87
+ }
88
+ }
89
+ else if (cats.length > 0) {
90
+ if (!cmmc.currentItem || cmmc.currentItem.categoryId !== cats[0].id) {
91
+ cmmc.setCurrentItem(cats[0].products[0].sku)
92
+ }
93
+ }
94
+ })
95
+ }, [requestedCat, levelNode?.subNodes])
96
+
97
+ const TitleArea: React.FC<{
98
+ title: string
99
+ byline?: string
100
+ clx?: string
101
+ }> = ({
102
+ title,
103
+ byline,
104
+ clx=''
105
+ }) => (
106
+ <ApplyTypography className={clx}>
107
+ <h3>{title}</h3>
108
+ {byline && (<h6>{byline}</h6>)}
109
+ </ApplyTypography>
110
+ )
111
+
112
+ const catTitle = requestedCat ? requestedCat.title : cmmc.selectedCategories?.[0]?.title
113
+
114
+ return (
115
+ <div className={cn('px-4 md:px-6 pt-3 pb-4 flex flex-col items-center', className)} >
116
+ {levelNode && (<>
117
+ <ApplyTypography className=''>
118
+ <h3>{levelNode.label}</h3>
119
+ {levelNode.subNodesLabel && (
120
+ <h6 className='!text-center mt-4 mb-1'>{levelNode.subNodesLabel}</h6>
121
+ )}
122
+ </ApplyTypography>
123
+ <FacetValuesWidget
124
+ className={cn(
125
+ 'grid gap-0 ' + `grid-cols-${levelNode!.subNodes!.length}`,
126
+ 'border-b-2 rounded-lg border-level-3 mb-4 -mr-2 -ml-2 max-w-[460px]',
127
+ facetsWidgetClx
128
+ )}
129
+ mobile={mobile}
130
+ mutator={getFacetValuesMutator(levelRef.current + 1, cmmc)}
131
+ itemClx='flex-col h-auto gap-0 py-1 px-3'
132
+ buttonClx={
133
+ 'h-full ' +
134
+ '!border-level-3'
135
+ }
136
+ facetValues={levelNode!.subNodes!}
137
+ show={facetsAs}
138
+ />
139
+ </>)}
140
+ {!levelNode && catTitle && (
141
+ <TitleArea title={catTitle} clx=''/>
142
+ )}
143
+ {(cmmc.currentItem) && (<ItemMedia item={cmmc.currentItem} />)}
144
+ {cmmc.selectedCategories[0] && (
145
+ <Selector
146
+ items={cmmc.selectedCategories[0].products as LineItem[]}
147
+ selectedItemRef={cmmc}
148
+ selectSku={cmmc.setCurrentItem.bind(cmmc)}
149
+ clx={selClx}
150
+ itemClx={selItemClx}
151
+ soleItemClx={selSoleItemClx}
152
+ ext={selExt}
153
+ showPrice={selShowPrice}
154
+ showQuantity={selShowQuantity}
155
+ />
156
+ )}
157
+ {(cmmc.currentItem) && (
158
+ <AddToCartWidget
159
+ size='default'
160
+ item={cmmc.currentItem}
161
+ onQuantityChanged={onQuantityChanged}
162
+ className={cn('min-w-[160px] mx-auto mt-4', addWidgetClx)}
163
+ />
164
+ )}
165
+ </div >
166
+ )
167
+ })
168
+
169
+ export default BuyCard
@@ -0,0 +1,78 @@
1
+ 'use client'
2
+ import React, { useState, type ReactNode } from 'react'
3
+
4
+ import { X as LucideX} from 'lucide-react'
5
+
6
+ import {
7
+ Drawer,
8
+ DrawerTrigger,
9
+ DrawerContent,
10
+ Button,
11
+ } from '@hanzo/ui/primitives'
12
+
13
+ import { cn } from '@hanzo/ui/util'
14
+
15
+ import BuyCard from './buy-card'
16
+ import RadioItemSelector from '../select/radio-selector'
17
+ import ImageItemSelector from '../select/image-selector'
18
+
19
+ const BuyDrawer: React.FC<{
20
+ skuPath: string
21
+ trigger: ReactNode
22
+ triggerClx?: string
23
+ drawerClx?: string
24
+ cardClx?: string
25
+ mobile?: boolean
26
+ }> = ({
27
+ skuPath,
28
+ trigger,
29
+ triggerClx='',
30
+ drawerClx='',
31
+ cardClx='',
32
+ mobile=false
33
+ }) => {
34
+
35
+ const [open, setOpen] = useState<boolean>(false)
36
+
37
+ const onQuantityChanged = (sku: string, oldV: number, newV: number) => {
38
+ //if (oldV === 0 && newV === 1) {
39
+ // setTimeout(() => {setOpen(false)}, 150)
40
+ //}
41
+ }
42
+
43
+ return (
44
+ <Drawer open={open} onOpenChange={setOpen} >
45
+ <DrawerTrigger asChild className={triggerClx}>
46
+ {trigger}
47
+ </DrawerTrigger>
48
+ <DrawerContent
49
+ className={cn('rounded-t-xl z-[52] mt-6 pb-12 h-auto min-h-[35vh] pt-6 md:max-w-[550px] md:mx-auto', drawerClx)}
50
+ overlayClx='z-[51]'
51
+ >
52
+ <BuyCard
53
+ skuPath={skuPath}
54
+ mobile={mobile}
55
+ onQuantityChanged={onQuantityChanged}
56
+ className={cn('w-full', cardClx)}
57
+ selector={ImageItemSelector}
58
+ selClx=''
59
+ selItemClx=''
60
+ selSoleItemClx='mb-3'
61
+ addWidgetClx=''
62
+ facetsAs='label'
63
+ />
64
+ <Button
65
+ variant='ghost'
66
+ size='icon'
67
+ onClick={() => {setOpen(false)}}
68
+ className={'absolute top-4 right-4 w-8 h-8 group rounded-full p-1 hidden md:flex items-center'}
69
+ >
70
+ <LucideX className='w-6 h-6 text-muted group-hover:text-foreground'/>
71
+ </Button>
72
+
73
+ </DrawerContent>
74
+ </Drawer>
75
+ )
76
+ }
77
+
78
+ export default BuyDrawer
@@ -0,0 +1,20 @@
1
+ 'use client'
2
+ import React from 'react'
3
+
4
+ import BuyDrawer from './buy-drawer'
5
+
6
+ const BuyTriggerWrapper: React.FC<{
7
+ skuPath: string
8
+ trigger: React.ReactNode
9
+ mobileTrigger?: React.ReactNode
10
+ mobile?: boolean
11
+ }> = ({
12
+ skuPath,
13
+ trigger,
14
+ mobileTrigger,
15
+ mobile
16
+ }) => (
17
+ <BuyDrawer skuPath={skuPath} trigger={trigger} mobile={mobile}/>
18
+ )
19
+
20
+ export default BuyTriggerWrapper
@@ -11,7 +11,8 @@ import {
11
11
  AccordionTrigger,
12
12
  } from '@hanzo/ui/primitives'
13
13
 
14
- import { formatCurrencyValue, useCommerce } from '..'
14
+ import { formatCurrencyValue } from '../../util'
15
+ import { useCommerce } from '../../service/context'
15
16
 
16
17
  import CartPanel from './cart-panel'
17
18
 
@@ -6,10 +6,11 @@ import { observer } from 'mobx-react-lite'
6
6
 
7
7
  import { cn } from '@hanzo/ui/util'
8
8
 
9
- import type { LineItem } from '../../types'
10
- import { formatCurrencyValue } from '../../util'
11
- import AddToCartWidget from '../add-to-cart-widget'
12
- import { useCommerce } from '../..'
9
+ import type { LineItem } from '../../../types'
10
+ import { formatCurrencyValue } from '../../../util'
11
+ import AddToCartWidget from '../../buy/add-to-cart-widget'
12
+ import { useCommerce } from '../../../service/context'
13
+ import type { Dimensions } from '@hanzo/ui/types'
13
14
 
14
15
  const DEF_IMG_SIZE=40
15
16
 
@@ -36,11 +37,33 @@ const CartLineItem: React.FC<{
36
37
  const cmmc = useCommerce()
37
38
  const promoPrice = showPromoCode ? cmmc.itemPromoPrice(item) : undefined
38
39
 
40
+ let dim: Dimensions
41
+ if (item.imgAR) {
42
+ if (item.imgAR >= 1) {
43
+ dim = {
44
+ w: imgSizePx,
45
+ h: imgSizePx / item.imgAR
46
+ }
47
+ }
48
+ else {
49
+ dim = {
50
+ w: imgSizePx * item.imgAR,
51
+ h: imgSizePx
52
+ }
53
+ }
54
+ }
55
+ else {
56
+ dim = {
57
+ w: imgSizePx,
58
+ h: imgSizePx
59
+ }
60
+ }
61
+
39
62
  return (
40
63
  <div className={cn('flex flex-col justify-start items-start text-sm font-sans', className)}>
41
64
  <div className='flex flex-row justify-between items-center gap-2'>
42
65
  {!!item.img ? (
43
- <Image src={item.img} alt={item.title + ' image'} height={imgSizePx} width={imgSizePx} className=''/>
66
+ <Image src={item.img} alt={item.title + ' image'} height={dim.h} width={dim.w} className=''/>
44
67
  ) : ( // placeholder so things align
45
68
  <div style={{height: imgSizePx, width: imgSizePx}}/>
46
69
  )}
@@ -5,9 +5,9 @@ import { observer } from 'mobx-react-lite'
5
5
  import { Button, ScrollArea } from '@hanzo/ui/primitives'
6
6
  import { cn } from '@hanzo/ui/util'
7
7
 
8
- import { useCommerce } from '../../service/context'
9
- import { formatCurrencyValue } from '../../util'
10
- import { sendFBEvent, sendGAEvent } from '../../util/analytics'
8
+ import { useCommerce } from '../../../service/context'
9
+ import { formatCurrencyValue } from '../../../util'
10
+ import { sendFBEvent, sendGAEvent } from '../../../util/analytics'
11
11
 
12
12
  import CartLineItem from './cart-line-item'
13
13
  import PromoCode from './promo-code'
@@ -10,9 +10,9 @@ import { observer } from 'mobx-react-lite'
10
10
 
11
11
  import { Button, Form, FormControl, FormField, FormItem, Input } from '@hanzo/ui/primitives'
12
12
 
13
- import { useCommerce } from '../..'
14
- import type { Promo } from '../../types'
15
- import getPromoFromApi from '../../util/promo-codes'
13
+ import { useCommerce } from '../../../service/context'
14
+ import type { Promo } from '../../../types'
15
+ import getPromoFromApi from '../../../util/promo-codes'
16
16
 
17
17
  const formSchema = z.object({
18
18
  code: z.string().min(1, 'Invalid code'),
@@ -7,7 +7,7 @@ import {
7
7
  } from '@hanzo/ui/primitives/form'
8
8
  import { Input } from '@hanzo/ui/primitives'
9
9
 
10
- import type { ContactFormType } from '../../types'
10
+ import type { ContactFormType } from '../../../types'
11
11
 
12
12
  const ContactForm: React.FC<{
13
13
  form: ContactFormType,
@@ -9,9 +9,9 @@ import { useForm } from 'react-hook-form'
9
9
  import { Tabs, TabsContent, TabsList, TabsTrigger } from '@hanzo/ui/primitives'
10
10
  import { useAuth } from '@hanzo/auth/service'
11
11
 
12
- import { useCommerce } from '../../service/context'
13
- import { sendFBEvent, sendGAEvent } from '../../util/analytics'
14
- import type { CheckoutStepComponentProps, TransactionStatus } from '../../types'
12
+ import { useCommerce } from '../../../service/context'
13
+ import { sendFBEvent, sendGAEvent } from '../../../util/analytics'
14
+ import type { CheckoutStepComponentProps, TransactionStatus } from '../../../types'
15
15
 
16
16
  import METHODS from './methods'
17
17
 
@@ -5,7 +5,7 @@ import { Copy } from 'lucide-react'
5
5
 
6
6
  import { Button, toast } from '@hanzo/ui/primitives'
7
7
 
8
- import type { PaymentMethodComponentProps } from '../../../types'
8
+ import type { PaymentMethodComponentProps } from '../../../../types'
9
9
 
10
10
  import ContactForm from '../contact-form'
11
11
 
@@ -15,10 +15,10 @@ import {
15
15
 
16
16
  import { cn } from '@hanzo/ui/util'
17
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'
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
22
 
23
23
  import ContactInfo from '../contact-form'
24
24
  import PaymentMethods from '../card-icon-row'
@@ -19,9 +19,9 @@ import {
19
19
  } from '@hanzo/ui/primitives'
20
20
 
21
21
  import Eth from '../crypto-icons/eth'
22
- import { useCommerce } from '../../../service/context'
23
- import type { PaymentMethodComponentProps } from '../../../types'
24
- import { sendFBEvent, sendGAEvent } from '../../../util/analytics'
22
+ import { useCommerce } from '../../../../service/context'
23
+ import type { PaymentMethodComponentProps } from '../../../../types'
24
+ import { sendFBEvent, sendGAEvent } from '../../../../util/analytics'
25
25
 
26
26
  import ContactForm from '../contact-form'
27
27