@hanzo/commerce 7.3.2 → 7.3.4
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/Icons.tsx +34 -34
- package/components/add-to-cart-widget.tsx +183 -183
- package/components/buy/buy-card.tsx +259 -259
- package/components/buy/carousel-buy-card.tsx +242 -242
- package/components/buy/multi-family/all-variants-carousel.tsx +261 -261
- package/components/buy/multi-family/family-carousel/index.tsx +77 -77
- package/components/buy/multi-family/family-carousel/slide.tsx +83 -83
- package/components/buy/multi-family/family-carousel/state.ts +87 -87
- package/components/buy/multi-family/index.ts +2 -2
- package/components/buy/single-family-selector.tsx +90 -90
- package/components/buy/title-and-byline.tsx +25 -25
- package/components/cart/cart-panel/cart-line-item.tsx +76 -76
- package/components/cart/cart-panel/index.tsx +154 -154
- package/components/cart/cart-panel/promo-code.tsx +106 -106
- package/components/cart/cart-panel/total-area.tsx +60 -60
- package/components/checkout/payment-step-form/card-icon-row.tsx +26 -26
- package/components/checkout/payment-step-form/card-icons/amex.tsx +32 -32
- package/components/checkout/payment-step-form/card-icons/diners-club.tsx +13 -13
- package/components/checkout/payment-step-form/card-icons/discover.tsx +25 -25
- package/components/checkout/payment-step-form/card-icons/jcb.tsx +26 -26
- package/components/checkout/payment-step-form/card-icons/mastercard.tsx +27 -27
- package/components/checkout/payment-step-form/card-icons/visa.tsx +25 -25
- package/components/checkout/payment-step-form/cc-button.tsx +17 -17
- package/components/checkout/payment-step-form/contact-form.tsx +49 -49
- package/components/checkout/payment-step-form/crypto-icons/btc.tsx +11 -11
- package/components/checkout/payment-step-form/crypto-icons/eth.tsx +20 -20
- package/components/checkout/payment-step-form/crypto-icons/usdt.tsx +13 -13
- package/components/checkout/payment-step-form/index.tsx +122 -122
- package/components/checkout/payment-step-form/methods/bank-transfer.tsx +79 -79
- package/components/checkout/payment-step-form/methods/card.tsx +232 -232
- package/components/checkout/payment-step-form/methods/crypto.tsx +227 -227
- package/components/checkout/payment-step-form/methods/index.ts +22 -22
- package/components/checkout/shipping-step-form.tsx +172 -172
- package/components/index.ts +11 -11
- package/components/item/product-card.tsx +48 -48
- package/components/item-selector/button.tsx +188 -188
- package/components/item-selector/carousel/index.tsx +197 -197
- package/components/item-selector/carousel/slider.tsx +40 -40
- package/components/item-selector/index.ts +5 -5
- package/components/item-selector/quantity-indicator.tsx +48 -48
- package/components/node-tabs/index.tsx +91 -91
- package/components/node-tabs/node-image.tsx +31 -31
- package/index.ts +12 -12
- package/package.json +60 -60
- package/service/context.tsx +45 -45
- package/service/debug.ts +41 -41
- package/service/impls/standalone/actual-line-item.ts +135 -135
- package/service/impls/standalone/get-instance.ts +64 -64
- package/service/impls/standalone/index.ts +579 -579
- package/service/impls/standalone/order/firebase.ts +14 -14
- package/service/impls/standalone/order/index.ts +128 -128
- package/service/impls/standalone/persistence.ts +33 -33
- package/service/path-utils.ts +25 -25
- package/service/sep.ts +6 -6
- package/tsconfig.json +10 -10
- package/types/README.md +1 -1
- package/types/category-node.ts +49 -49
- package/types/checkout.ts +46 -46
- package/types/commerce-config.ts +13 -13
- package/types/commerce-service.ts +127 -127
- package/types/family.ts +25 -25
- package/types/index.ts +15 -15
- package/types/item-selector.ts +96 -96
- package/types/line-item.ts +29 -29
- package/types/multi-family-selector-props.ts +19 -19
- package/types/product.ts +20 -20
- package/types/promo.ts +9 -9
- package/types/selection-ui-specifier.ts +51 -51
- package/types/string-mutator.ts +13 -13
- package/types/token-separators.ts +7 -7
- package/util/analytics.ts +20 -20
- package/util/countries.ts +195 -195
- package/util/error.ts +34 -34
- package/util/index.ts +70 -70
- package/util/item-selector-options-accessor.ts +34 -34
- package/util/line-item-ref.ts +23 -23
- package/util/multi-family-selector-options-accessor.ts +14 -14
- package/util/obs-string-mutator.ts +22 -22
- package/util/product-media-accessor.ts +58 -58
- package/util/promo-codes.ts +108 -108
- package/util/selection-ui-specifiers.ts +29 -29
- package/util/square-payment.ts +42 -42
- package/util/use-sync-sku-param-w-current-item.ts +88 -88
|
@@ -1,242 +1,242 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
import React, {
|
|
3
|
-
useRef,
|
|
4
|
-
useEffect,
|
|
5
|
-
type ComponentType,
|
|
6
|
-
useState
|
|
7
|
-
} from 'react'
|
|
8
|
-
import { observer } from 'mobx-react-lite'
|
|
9
|
-
|
|
10
|
-
import { cn } from '@hanzo/ui/util'
|
|
11
|
-
|
|
12
|
-
import type {
|
|
13
|
-
ItemSelectorProps,
|
|
14
|
-
LineItem,
|
|
15
|
-
Family,
|
|
16
|
-
CategoryNode,
|
|
17
|
-
CategoryNodeRole,
|
|
18
|
-
SelectionUISpecifier,
|
|
19
|
-
ItemSelectorOptions,
|
|
20
|
-
MultiFamilySelectorProps,
|
|
21
|
-
MultiFamilySelectorOptions,
|
|
22
|
-
} from '../../types'
|
|
23
|
-
|
|
24
|
-
import { useCommerce } from '../../service/context'
|
|
25
|
-
import { getSelectionUISpecifier } from '../../util'
|
|
26
|
-
|
|
27
|
-
import { CarouselItemSelector, ButtonItemSelector } from '../item-selector'
|
|
28
|
-
import SingleFamilySelector from './single-family-selector'
|
|
29
|
-
import { FamilyCarousel, AllVariantsCarousel } from './multi-family'
|
|
30
|
-
|
|
31
|
-
import AddToCartWidget from '../add-to-cart-widget'
|
|
32
|
-
|
|
33
|
-
const SCROLL = {
|
|
34
|
-
scrollAfter: 5,
|
|
35
|
-
scrollHeightClx: 'h-[65vh]'
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const MEDIA_CONSTRAINT = {w: 200, h: 200}
|
|
39
|
-
|
|
40
|
-
const sortItems = (items: LineItem[], sort: 'asc' | 'desc' | 'none'): LineItem[] => (
|
|
41
|
-
((sort === 'asc') ?
|
|
42
|
-
items.sort((a: LineItem, b: LineItem): number => (a.price - b.price))
|
|
43
|
-
:
|
|
44
|
-
((sort === 'desc') ?
|
|
45
|
-
items.sort((a: LineItem, b: LineItem): number => (b.price - a.price ))
|
|
46
|
-
:
|
|
47
|
-
items
|
|
48
|
-
)
|
|
49
|
-
)
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
const CarouselBuyCard: React.FC<{
|
|
53
|
-
skuPath: string
|
|
54
|
-
checkoutButton: React.ReactNode
|
|
55
|
-
clx?: string
|
|
56
|
-
selectorClx?: string
|
|
57
|
-
addBtnClx?: string
|
|
58
|
-
buttonsAreaClx?: string
|
|
59
|
-
mobile?: boolean
|
|
60
|
-
onQuantityChanged?: (sku: string, oldV: number, newV: number) => void
|
|
61
|
-
}> = ({
|
|
62
|
-
skuPath,
|
|
63
|
-
checkoutButton,
|
|
64
|
-
clx='',
|
|
65
|
-
selectorClx='',
|
|
66
|
-
addBtnClx='',
|
|
67
|
-
buttonsAreaClx='',
|
|
68
|
-
mobile=false,
|
|
69
|
-
onQuantityChanged,
|
|
70
|
-
}) => {
|
|
71
|
-
|
|
72
|
-
const cmmc = useCommerce()
|
|
73
|
-
|
|
74
|
-
const r = useRef<{
|
|
75
|
-
role: CategoryNodeRole
|
|
76
|
-
item: LineItem | undefined
|
|
77
|
-
family: Family | undefined
|
|
78
|
-
families: Family[] | undefined
|
|
79
|
-
node: CategoryNode
|
|
80
|
-
uiSpec: SelectionUISpecifier
|
|
81
|
-
single?: {
|
|
82
|
-
items: LineItem[]
|
|
83
|
-
Selector: ComponentType<ItemSelectorProps>
|
|
84
|
-
selOptions: ItemSelectorOptions | undefined
|
|
85
|
-
scrollable: boolean
|
|
86
|
-
showItemMedia: boolean
|
|
87
|
-
}
|
|
88
|
-
multi?: {
|
|
89
|
-
Selector: ComponentType<MultiFamilySelectorProps>
|
|
90
|
-
selectorOptions: MultiFamilySelectorOptions | undefined
|
|
91
|
-
itemOptions: ItemSelectorOptions | undefined
|
|
92
|
-
initialFamilyId: string
|
|
93
|
-
}
|
|
94
|
-
} | undefined>(undefined)
|
|
95
|
-
|
|
96
|
-
const [changeMeToRerender, setChangeMeToRerender] = useState<boolean>(false)
|
|
97
|
-
|
|
98
|
-
useEffect(() => {
|
|
99
|
-
|
|
100
|
-
if (!skuPath || skuPath.length === 0 ) {
|
|
101
|
-
// The component is being hidden (w an amination)
|
|
102
|
-
// keep things the same so no layout jump
|
|
103
|
-
return
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const peek = cmmc.peek(skuPath)
|
|
107
|
-
if (typeof peek === 'string') {
|
|
108
|
-
throw new Error(peek)
|
|
109
|
-
}
|
|
110
|
-
if (peek.role === 'non-outermost') {
|
|
111
|
-
throw new Error(`BuyCard: skuPath ${skuPath} isn't an outermost tree node or product family!`)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const uiSpec = getSelectionUISpecifier(skuPath)
|
|
115
|
-
|
|
116
|
-
r.current = {
|
|
117
|
-
...peek,
|
|
118
|
-
node: peek.node!, // else exception was thrown.
|
|
119
|
-
uiSpec,
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (peek.role === 'single-family') {
|
|
123
|
-
|
|
124
|
-
const sort = (): 'none' | 'asc' | 'desc' => {
|
|
125
|
-
const options = uiSpec.singleFamily?.options ?? {}
|
|
126
|
-
const showSlider = 'showSlider' in options ? options.showSlider! : true
|
|
127
|
-
return ('sort' in options) ?
|
|
128
|
-
options.sort!
|
|
129
|
-
:
|
|
130
|
-
(showSlider ? 'asc' : 'none')
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const items = peek.family!.products as LineItem[]
|
|
134
|
-
const Selector: ComponentType<ItemSelectorProps> =
|
|
135
|
-
(uiSpec.singleFamily?.type === 'buttons') ? ButtonItemSelector : CarouselItemSelector
|
|
136
|
-
const selOptions = uiSpec.singleFamily?.options
|
|
137
|
-
|
|
138
|
-
r.current.single = {
|
|
139
|
-
items: sortItems(items, sort()),
|
|
140
|
-
Selector,
|
|
141
|
-
selOptions,
|
|
142
|
-
scrollable: !!(items.length > SCROLL.scrollAfter),
|
|
143
|
-
showItemMedia: uiSpec.singleFamily?.type !== 'carousel'
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const currItem = peek.item ?? r.current.single.items[0]
|
|
147
|
-
cmmc.setCurrentItem(currItem.sku)
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
const initialFamily = peek.family ? peek.family : peek.families![0]
|
|
151
|
-
// TODO: Does this ever need to be sorted??
|
|
152
|
-
const currItem = peek.item ?? initialFamily.products[0]
|
|
153
|
-
|
|
154
|
-
// sets currentFamily as well
|
|
155
|
-
cmmc.setCurrentItem(currItem.sku)
|
|
156
|
-
|
|
157
|
-
r.current.multi = {
|
|
158
|
-
Selector: (uiSpec.multiFamily?.type === 'family-carousel') ?
|
|
159
|
-
FamilyCarousel
|
|
160
|
-
:
|
|
161
|
-
AllVariantsCarousel,
|
|
162
|
-
itemOptions: uiSpec.multiFamily?.itemOptions,
|
|
163
|
-
selectorOptions: uiSpec.multiFamily?.selectorOptions,
|
|
164
|
-
initialFamilyId: initialFamily.id
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Must do this since Dialog code takes this comp out of the React shadow DOM
|
|
169
|
-
// (only in prod apparently.)
|
|
170
|
-
setChangeMeToRerender(!changeMeToRerender)
|
|
171
|
-
}, [skuPath])
|
|
172
|
-
|
|
173
|
-
const MultiFamilyUI: React.FC<{
|
|
174
|
-
Selector: ComponentType<MultiFamilySelectorProps>
|
|
175
|
-
selectorOptions: MultiFamilySelectorOptions | undefined
|
|
176
|
-
itemOptions: ItemSelectorOptions | undefined
|
|
177
|
-
families: Family[]
|
|
178
|
-
parent: CategoryNode
|
|
179
|
-
clx?: string
|
|
180
|
-
}> = ({
|
|
181
|
-
Selector,
|
|
182
|
-
itemOptions,
|
|
183
|
-
selectorOptions,
|
|
184
|
-
families,
|
|
185
|
-
parent,
|
|
186
|
-
clx=''
|
|
187
|
-
}) => (
|
|
188
|
-
<Selector
|
|
189
|
-
families={families}
|
|
190
|
-
parent={parent}
|
|
191
|
-
clx={clx}
|
|
192
|
-
itemOptions={itemOptions}
|
|
193
|
-
selectorOptions={selectorOptions}
|
|
194
|
-
mediaConstraint={MEDIA_CONSTRAINT}
|
|
195
|
-
mobile={mobile}
|
|
196
|
-
/>
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
const Buttons: React.FC<{clx?: string}> = observer(({
|
|
200
|
-
clx=''
|
|
201
|
-
}) => (cmmc.currentItem ? (
|
|
202
|
-
<div className={clx}>
|
|
203
|
-
<AddToCartWidget
|
|
204
|
-
item={cmmc.currentItem}
|
|
205
|
-
onQuantityChanged={onQuantityChanged}
|
|
206
|
-
variant={cmmc.cartEmpty ? 'primary' : 'outline'}
|
|
207
|
-
className={addBtnClx}
|
|
208
|
-
/>
|
|
209
|
-
{!cmmc.cartEmpty && checkoutButton}
|
|
210
|
-
</div>
|
|
211
|
-
) : null))
|
|
212
|
-
|
|
213
|
-
return (
|
|
214
|
-
<div className={cn(
|
|
215
|
-
'px-4 md:px-6 pt-3 pb-4 flex flex-col gap-1 items-center',
|
|
216
|
-
r.current?.single?.scrollable ? SCROLL.scrollHeightClx : 'h-auto',
|
|
217
|
-
clx,
|
|
218
|
-
)}>
|
|
219
|
-
{r.current?.single ? (
|
|
220
|
-
<SingleFamilySelector
|
|
221
|
-
{...r.current.single}
|
|
222
|
-
mediaConstraint={MEDIA_CONSTRAINT}
|
|
223
|
-
mobile={mobile}
|
|
224
|
-
clx={selectorClx}
|
|
225
|
-
/>
|
|
226
|
-
) : (r.current?.multi && r.current.families && /* safegaurd for first render, etc. */ (
|
|
227
|
-
<MultiFamilyUI
|
|
228
|
-
{...r.current.multi}
|
|
229
|
-
families={r.current.families}
|
|
230
|
-
parent={r.current.node}
|
|
231
|
-
clx={selectorClx}
|
|
232
|
-
/>
|
|
233
|
-
))}
|
|
234
|
-
<Buttons clx={cn(
|
|
235
|
-
'self-stretch mt-8 flex flex-col items-center gap-3 shrink-0 grow-0',
|
|
236
|
-
buttonsAreaClx
|
|
237
|
-
)}/>
|
|
238
|
-
</div >
|
|
239
|
-
)
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
export default CarouselBuyCard
|
|
1
|
+
'use client'
|
|
2
|
+
import React, {
|
|
3
|
+
useRef,
|
|
4
|
+
useEffect,
|
|
5
|
+
type ComponentType,
|
|
6
|
+
useState
|
|
7
|
+
} from 'react'
|
|
8
|
+
import { observer } from 'mobx-react-lite'
|
|
9
|
+
|
|
10
|
+
import { cn } from '@hanzo/ui/util'
|
|
11
|
+
|
|
12
|
+
import type {
|
|
13
|
+
ItemSelectorProps,
|
|
14
|
+
LineItem,
|
|
15
|
+
Family,
|
|
16
|
+
CategoryNode,
|
|
17
|
+
CategoryNodeRole,
|
|
18
|
+
SelectionUISpecifier,
|
|
19
|
+
ItemSelectorOptions,
|
|
20
|
+
MultiFamilySelectorProps,
|
|
21
|
+
MultiFamilySelectorOptions,
|
|
22
|
+
} from '../../types'
|
|
23
|
+
|
|
24
|
+
import { useCommerce } from '../../service/context'
|
|
25
|
+
import { getSelectionUISpecifier } from '../../util'
|
|
26
|
+
|
|
27
|
+
import { CarouselItemSelector, ButtonItemSelector } from '../item-selector'
|
|
28
|
+
import SingleFamilySelector from './single-family-selector'
|
|
29
|
+
import { FamilyCarousel, AllVariantsCarousel } from './multi-family'
|
|
30
|
+
|
|
31
|
+
import AddToCartWidget from '../add-to-cart-widget'
|
|
32
|
+
|
|
33
|
+
const SCROLL = {
|
|
34
|
+
scrollAfter: 5,
|
|
35
|
+
scrollHeightClx: 'h-[65vh]'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const MEDIA_CONSTRAINT = {w: 200, h: 200}
|
|
39
|
+
|
|
40
|
+
const sortItems = (items: LineItem[], sort: 'asc' | 'desc' | 'none'): LineItem[] => (
|
|
41
|
+
((sort === 'asc') ?
|
|
42
|
+
items.sort((a: LineItem, b: LineItem): number => (a.price - b.price))
|
|
43
|
+
:
|
|
44
|
+
((sort === 'desc') ?
|
|
45
|
+
items.sort((a: LineItem, b: LineItem): number => (b.price - a.price ))
|
|
46
|
+
:
|
|
47
|
+
items
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
const CarouselBuyCard: React.FC<{
|
|
53
|
+
skuPath: string
|
|
54
|
+
checkoutButton: React.ReactNode
|
|
55
|
+
clx?: string
|
|
56
|
+
selectorClx?: string
|
|
57
|
+
addBtnClx?: string
|
|
58
|
+
buttonsAreaClx?: string
|
|
59
|
+
mobile?: boolean
|
|
60
|
+
onQuantityChanged?: (sku: string, oldV: number, newV: number) => void
|
|
61
|
+
}> = ({
|
|
62
|
+
skuPath,
|
|
63
|
+
checkoutButton,
|
|
64
|
+
clx='',
|
|
65
|
+
selectorClx='',
|
|
66
|
+
addBtnClx='',
|
|
67
|
+
buttonsAreaClx='',
|
|
68
|
+
mobile=false,
|
|
69
|
+
onQuantityChanged,
|
|
70
|
+
}) => {
|
|
71
|
+
|
|
72
|
+
const cmmc = useCommerce()
|
|
73
|
+
|
|
74
|
+
const r = useRef<{
|
|
75
|
+
role: CategoryNodeRole
|
|
76
|
+
item: LineItem | undefined
|
|
77
|
+
family: Family | undefined
|
|
78
|
+
families: Family[] | undefined
|
|
79
|
+
node: CategoryNode
|
|
80
|
+
uiSpec: SelectionUISpecifier
|
|
81
|
+
single?: {
|
|
82
|
+
items: LineItem[]
|
|
83
|
+
Selector: ComponentType<ItemSelectorProps>
|
|
84
|
+
selOptions: ItemSelectorOptions | undefined
|
|
85
|
+
scrollable: boolean
|
|
86
|
+
showItemMedia: boolean
|
|
87
|
+
}
|
|
88
|
+
multi?: {
|
|
89
|
+
Selector: ComponentType<MultiFamilySelectorProps>
|
|
90
|
+
selectorOptions: MultiFamilySelectorOptions | undefined
|
|
91
|
+
itemOptions: ItemSelectorOptions | undefined
|
|
92
|
+
initialFamilyId: string
|
|
93
|
+
}
|
|
94
|
+
} | undefined>(undefined)
|
|
95
|
+
|
|
96
|
+
const [changeMeToRerender, setChangeMeToRerender] = useState<boolean>(false)
|
|
97
|
+
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
|
|
100
|
+
if (!skuPath || skuPath.length === 0 ) {
|
|
101
|
+
// The component is being hidden (w an amination)
|
|
102
|
+
// keep things the same so no layout jump
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const peek = cmmc.peek(skuPath)
|
|
107
|
+
if (typeof peek === 'string') {
|
|
108
|
+
throw new Error(peek)
|
|
109
|
+
}
|
|
110
|
+
if (peek.role === 'non-outermost') {
|
|
111
|
+
throw new Error(`BuyCard: skuPath ${skuPath} isn't an outermost tree node or product family!`)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const uiSpec = getSelectionUISpecifier(skuPath)
|
|
115
|
+
|
|
116
|
+
r.current = {
|
|
117
|
+
...peek,
|
|
118
|
+
node: peek.node!, // else exception was thrown.
|
|
119
|
+
uiSpec,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (peek.role === 'single-family') {
|
|
123
|
+
|
|
124
|
+
const sort = (): 'none' | 'asc' | 'desc' => {
|
|
125
|
+
const options = uiSpec.singleFamily?.options ?? {}
|
|
126
|
+
const showSlider = 'showSlider' in options ? options.showSlider! : true
|
|
127
|
+
return ('sort' in options) ?
|
|
128
|
+
options.sort!
|
|
129
|
+
:
|
|
130
|
+
(showSlider ? 'asc' : 'none')
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const items = peek.family!.products as LineItem[]
|
|
134
|
+
const Selector: ComponentType<ItemSelectorProps> =
|
|
135
|
+
(uiSpec.singleFamily?.type === 'buttons') ? ButtonItemSelector : CarouselItemSelector
|
|
136
|
+
const selOptions = uiSpec.singleFamily?.options
|
|
137
|
+
|
|
138
|
+
r.current.single = {
|
|
139
|
+
items: sortItems(items, sort()),
|
|
140
|
+
Selector,
|
|
141
|
+
selOptions,
|
|
142
|
+
scrollable: !!(items.length > SCROLL.scrollAfter),
|
|
143
|
+
showItemMedia: uiSpec.singleFamily?.type !== 'carousel'
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const currItem = peek.item ?? r.current.single.items[0]
|
|
147
|
+
cmmc.setCurrentItem(currItem.sku)
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const initialFamily = peek.family ? peek.family : peek.families![0]
|
|
151
|
+
// TODO: Does this ever need to be sorted??
|
|
152
|
+
const currItem = peek.item ?? initialFamily.products[0]
|
|
153
|
+
|
|
154
|
+
// sets currentFamily as well
|
|
155
|
+
cmmc.setCurrentItem(currItem.sku)
|
|
156
|
+
|
|
157
|
+
r.current.multi = {
|
|
158
|
+
Selector: (uiSpec.multiFamily?.type === 'family-carousel') ?
|
|
159
|
+
FamilyCarousel
|
|
160
|
+
:
|
|
161
|
+
AllVariantsCarousel,
|
|
162
|
+
itemOptions: uiSpec.multiFamily?.itemOptions,
|
|
163
|
+
selectorOptions: uiSpec.multiFamily?.selectorOptions,
|
|
164
|
+
initialFamilyId: initialFamily.id
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Must do this since Dialog code takes this comp out of the React shadow DOM
|
|
169
|
+
// (only in prod apparently.)
|
|
170
|
+
setChangeMeToRerender(!changeMeToRerender)
|
|
171
|
+
}, [skuPath])
|
|
172
|
+
|
|
173
|
+
const MultiFamilyUI: React.FC<{
|
|
174
|
+
Selector: ComponentType<MultiFamilySelectorProps>
|
|
175
|
+
selectorOptions: MultiFamilySelectorOptions | undefined
|
|
176
|
+
itemOptions: ItemSelectorOptions | undefined
|
|
177
|
+
families: Family[]
|
|
178
|
+
parent: CategoryNode
|
|
179
|
+
clx?: string
|
|
180
|
+
}> = ({
|
|
181
|
+
Selector,
|
|
182
|
+
itemOptions,
|
|
183
|
+
selectorOptions,
|
|
184
|
+
families,
|
|
185
|
+
parent,
|
|
186
|
+
clx=''
|
|
187
|
+
}) => (
|
|
188
|
+
<Selector
|
|
189
|
+
families={families}
|
|
190
|
+
parent={parent}
|
|
191
|
+
clx={clx}
|
|
192
|
+
itemOptions={itemOptions}
|
|
193
|
+
selectorOptions={selectorOptions}
|
|
194
|
+
mediaConstraint={MEDIA_CONSTRAINT}
|
|
195
|
+
mobile={mobile}
|
|
196
|
+
/>
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
const Buttons: React.FC<{clx?: string}> = observer(({
|
|
200
|
+
clx=''
|
|
201
|
+
}) => (cmmc.currentItem ? (
|
|
202
|
+
<div className={clx}>
|
|
203
|
+
<AddToCartWidget
|
|
204
|
+
item={cmmc.currentItem}
|
|
205
|
+
onQuantityChanged={onQuantityChanged}
|
|
206
|
+
variant={cmmc.cartEmpty ? 'primary' : 'outline'}
|
|
207
|
+
className={addBtnClx}
|
|
208
|
+
/>
|
|
209
|
+
{!cmmc.cartEmpty && checkoutButton}
|
|
210
|
+
</div>
|
|
211
|
+
) : null))
|
|
212
|
+
|
|
213
|
+
return (
|
|
214
|
+
<div className={cn(
|
|
215
|
+
'px-4 md:px-6 pt-3 pb-4 flex flex-col gap-1 items-center',
|
|
216
|
+
r.current?.single?.scrollable ? SCROLL.scrollHeightClx : 'h-auto',
|
|
217
|
+
clx,
|
|
218
|
+
)}>
|
|
219
|
+
{r.current?.single ? (
|
|
220
|
+
<SingleFamilySelector
|
|
221
|
+
{...r.current.single}
|
|
222
|
+
mediaConstraint={MEDIA_CONSTRAINT}
|
|
223
|
+
mobile={mobile}
|
|
224
|
+
clx={selectorClx}
|
|
225
|
+
/>
|
|
226
|
+
) : (r.current?.multi && r.current.families && /* safegaurd for first render, etc. */ (
|
|
227
|
+
<MultiFamilyUI
|
|
228
|
+
{...r.current.multi}
|
|
229
|
+
families={r.current.families}
|
|
230
|
+
parent={r.current.node}
|
|
231
|
+
clx={selectorClx}
|
|
232
|
+
/>
|
|
233
|
+
))}
|
|
234
|
+
<Buttons clx={cn(
|
|
235
|
+
'self-stretch mt-8 flex flex-col items-center gap-3 shrink-0 grow-0',
|
|
236
|
+
buttonsAreaClx
|
|
237
|
+
)}/>
|
|
238
|
+
</div >
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export default CarouselBuyCard
|