@hanzo/commerce 5.1.2 → 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.
- package/components/{buy-item/select-category-item-card.tsx → buy/_to_deprecate_select-category-item-card.tsx} +20 -31
- package/components/{select-category-item-panel.tsx → buy/_to_deprecate_select-category-item-panel.tsx} +12 -20
- package/components/{buy-item/buy-item-popup.tsx → buy/_unused_buy-popup.tsx_} +4 -4
- package/components/{add-to-cart-widget.tsx → buy/add-to-cart-widget.tsx} +5 -3
- package/components/buy/buy-button.tsx +31 -0
- package/components/buy/buy-card.tsx +169 -0
- package/components/buy/buy-drawer.tsx +78 -0
- package/components/buy/buy-trigger-wrapper.tsx +20 -0
- package/components/{cart-accordian.tsx → cart/cart-accordian.tsx} +2 -1
- package/components/{cart-panel → cart/cart-panel}/cart-line-item.tsx +28 -5
- package/components/{cart-panel → cart/cart-panel}/index.tsx +9 -5
- package/components/{cart-panel → cart/cart-panel}/promo-code.tsx +3 -3
- package/components/{payment-step-form → checkout/payment-step-form}/contact-form.tsx +1 -1
- package/components/{payment-step-form → checkout/payment-step-form}/index.tsx +3 -3
- package/components/{payment-step-form → checkout/payment-step-form}/methods/bank-transfer.tsx +1 -1
- package/components/{payment-step-form → checkout/payment-step-form}/methods/card.tsx +4 -4
- package/components/{payment-step-form → checkout/payment-step-form}/methods/crypto.tsx +3 -3
- package/components/{payment-step-form → checkout/payment-step-form}/methods/index.ts +1 -1
- package/components/{shipping-step-form.tsx → checkout/shipping-step-form.tsx} +4 -4
- package/components/facet-values-widget/facet-image.tsx +2 -2
- package/components/facet-values-widget/index.tsx +13 -12
- package/components/index.ts +19 -17
- package/components/item/item-media.tsx +58 -0
- package/components/{product-card.tsx → item/product-card.tsx} +5 -7
- package/components/select/carousel-selector.tsx +64 -0
- package/components/select/image-selector.tsx +125 -0
- package/components/select/radio-selector.tsx +66 -0
- package/package.json +2 -1
- package/service/context.tsx +4 -4
- package/service/impls/standalone/index.ts +4 -4
- package/service/impls/standalone/standalone-service.ts +74 -62
- package/types/commerce-service.ts +20 -16
- package/types/index.ts +2 -2
- package/types/item-selector.ts +12 -5
- package/types/product.ts +1 -0
- package/types/tree-node.ts +24 -0
- package/util/index.ts +9 -9
- package/util/use-sync-sku-param-w-current-item.ts +5 -5
- package/components/buy-item/buy-item-button-wrapper.tsx +0 -27
- package/components/buy-item/buy-item-button.tsx +0 -34
- package/components/buy-item/buy-item-card.tsx +0 -92
- package/components/buy-item/buy-item-mobile-drawer.tsx +0 -54
- package/components/buy-item/select-category-and-item-widget.tsx +0 -83
- package/components/category-item-radio-selector.tsx +0 -55
- package/components/category-item-scroll-selector.tsx +0 -40
- package/components/item-carousel.tsx +0 -80
- package/types/facet.ts +0 -35
- /package/components/{cart-icon.tsx → cart/cart-icon.tsx} +0 -0
- /package/components/{payment-step-form → checkout/payment-step-form}/card-icon-row.tsx +0 -0
- /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/amex.tsx +0 -0
- /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/diners-club.tsx +0 -0
- /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/discover.tsx +0 -0
- /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/jcb.tsx +0 -0
- /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/mastercard.tsx +0 -0
- /package/components/{payment-step-form → checkout/payment-step-form}/card-icons/visa.tsx +0 -0
- /package/components/{payment-step-form → checkout/payment-step-form}/cc-button.tsx +0 -0
- /package/components/{payment-step-form → checkout/payment-step-form}/crypto-icons/btc.tsx +0 -0
- /package/components/{payment-step-form → checkout/payment-step-form}/crypto-icons/eth.tsx +0 -0
- /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 '
|
|
11
|
-
import
|
|
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
|
-
|
|
17
|
+
title?: string
|
|
19
18
|
onQuantityChanged?: (sku: string, oldV: number, newV: number) => void
|
|
20
19
|
}> = /* NOT observer */({
|
|
21
|
-
|
|
20
|
+
items,
|
|
22
21
|
selectedItemRef: selItemRef,
|
|
23
22
|
selectSku,
|
|
24
23
|
className,
|
|
25
24
|
isLoading = false,
|
|
26
25
|
mobile = false,
|
|
27
|
-
|
|
26
|
+
title,
|
|
28
27
|
onQuantityChanged,
|
|
29
28
|
...props
|
|
30
29
|
}) => {
|
|
31
30
|
|
|
32
|
-
const soleOption =
|
|
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 ||
|
|
37
|
+
const mobilePicker = (mobile || items.length > 6)
|
|
39
38
|
if (soleOption) {
|
|
40
|
-
const item =
|
|
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
|
-
{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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'>{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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 {
|
|
10
|
-
import { formatCurrencyValue } from '
|
|
11
|
-
import { Icons } from '
|
|
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
|
|
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> &
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
category={category}
|
|
94
|
+
<RadioItemSelector
|
|
95
|
+
items={category.products as LineItem[]}
|
|
94
96
|
selectedItemRef={selectedItemRef}
|
|
95
97
|
selectSku={selectSku}
|
|
96
98
|
showQuantity={showQuantity}
|
|
97
|
-
|
|
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
|
|
15
|
+
import BuyCard from './buy-item-card'
|
|
16
16
|
|
|
17
|
-
const
|
|
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
|
-
<
|
|
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
|
|
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 '
|
|
9
|
-
import type { LineItem } from '
|
|
10
|
-
import { sendFBEvent, sendGAEvent } from '
|
|
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
|
|
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 '
|
|
10
|
-
import { formatCurrencyValue } from '
|
|
11
|
-
import AddToCartWidget from '
|
|
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={
|
|
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
|
)}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
import React, { type PropsWithChildren } from 'react'
|
|
2
|
+
import React, { Suspense, type PropsWithChildren } from 'react'
|
|
3
3
|
import { observer } from 'mobx-react-lite'
|
|
4
4
|
|
|
5
5
|
import { Button, ScrollArea } from '@hanzo/ui/primitives'
|
|
6
6
|
import { cn } from '@hanzo/ui/util'
|
|
7
7
|
|
|
8
|
-
import { useCommerce } from '
|
|
9
|
-
import { formatCurrencyValue } from '
|
|
10
|
-
import { sendFBEvent, sendGAEvent } from '
|
|
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'
|
|
@@ -88,7 +88,11 @@ const CartPanel: React.FC<PropsWithChildren & {
|
|
|
88
88
|
/>
|
|
89
89
|
))}
|
|
90
90
|
</>)}
|
|
91
|
-
{showPromoCode &&
|
|
91
|
+
{showPromoCode && (
|
|
92
|
+
<Suspense>
|
|
93
|
+
<PromoCode/>
|
|
94
|
+
</Suspense>
|
|
95
|
+
)}
|
|
92
96
|
{(showShipping || showPromoCode) && (
|
|
93
97
|
<div className='flex flex-col gap-1 py-2 border-t'>
|
|
94
98
|
<p className='flex justify-between'>
|
|
@@ -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 '
|
|
15
|
-
import getPromoFromApi from '
|
|
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 '
|
|
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 '
|
|
13
|
-
import { sendFBEvent, sendGAEvent } from '
|
|
14
|
-
import type { CheckoutStepComponentProps, TransactionStatus } from '
|
|
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
|
|
package/components/{payment-step-form → checkout/payment-step-form}/methods/bank-transfer.tsx
RENAMED
|
@@ -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 '
|
|
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 '
|
|
19
|
-
import { processSquareCardPayment } from '
|
|
20
|
-
import type { PaymentMethodComponentProps } from '
|
|
21
|
-
import { sendFBEvent, sendGAEvent } from '
|
|
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'
|