@luxfi/core 5.2.13 → 5.3.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 (26) hide show
  1. package/commerce/ui/context.tsx +4 -7
  2. package/commerce/ui/store.ts +39 -54
  3. package/components/back-button.tsx +8 -1
  4. package/components/commerce/{checkout-widget/index.tsx → _to_deprecate_checkout-widget/index.tsx_} +0 -4
  5. package/components/commerce/checkout-panel/cart-accordian.tsx +66 -0
  6. package/components/commerce/checkout-panel/checkout-panel-props.ts +10 -0
  7. package/components/commerce/checkout-panel/desktop-cp.tsx +83 -0
  8. package/components/commerce/checkout-panel/index.tsx +16 -19
  9. package/components/commerce/checkout-panel/mobile-cp.tsx +67 -0
  10. package/components/commerce/checkout-panel/policy-links.tsx +29 -0
  11. package/components/commerce/drawer/index.tsx +2 -13
  12. package/components/commerce/drawer/micro.tsx +19 -19
  13. package/components/commerce/mobile-nav-menu-ai.tsx +0 -1
  14. package/components/index.ts +0 -2
  15. package/components/mini-chart/mini-chart.tsx +2 -2
  16. package/package.json +1 -1
  17. package/root-layout/index.tsx +1 -1
  18. package/tsconfig.json +1 -1
  19. package/components/commerce/add-widget.tsx +0 -20
  20. package/components/commerce/checkout-panel/dt-checkout-panel.tsx +0 -85
  21. package/components/commerce/checkout-panel/links-row.tsx +0 -21
  22. package/components/commerce/checkout-panel/mb-checkout-panel.tsx +0 -55
  23. /package/components/commerce/{checkout-widget → _to_deprecate_checkout-widget}/const.ts +0 -0
  24. /package/components/commerce/{checkout-widget → _to_deprecate_checkout-widget}/obs-string-set.ts +0 -0
  25. /package/components/commerce/{checkout-widget → _to_deprecate_checkout-widget}/use-anim-clx-set.ts +0 -0
  26. /package/components/commerce/checkout-panel/{dt-bag-carousel.tsx → desktop-bag-carousel.tsx} +0 -0
@@ -15,7 +15,7 @@ import { useDebounceCallback } from 'usehooks-ts'
15
15
  import { preset as twConfig } from '@hanzo/ui/tailwind'
16
16
  import { useCommerce } from '@hanzo/commerce'
17
17
 
18
- import type { CommerceDrawer, SelectAndBuy, RecentActivity } from './store'
18
+ import type { CommerceDrawer, SelectAndBuy } from './store'
19
19
  import { CommerceUIStore } from './store'
20
20
  import conf from './conf'
21
21
 
@@ -39,10 +39,6 @@ const useSelectAndBuy = (): SelectAndBuy => {
39
39
  return useContext(CommerceUIContext) as SelectAndBuy
40
40
  }
41
41
 
42
- const useRecentActivity = (): RecentActivity => {
43
- return useContext(CommerceUIContext) as RecentActivity
44
- }
45
-
46
42
  const CommerceUIProvider: React.FC<PropsWithChildren> = ({
47
43
  children,
48
44
  }) => {
@@ -78,6 +74,7 @@ const CommerceUIProvider: React.FC<PropsWithChildren> = ({
78
74
  storeRef.current.initialize()
79
75
  onResize()
80
76
  window.addEventListener('resize', onResize_debounced);
77
+
81
78
  return () => {
82
79
  window.removeEventListener('resize', onResize_debounced)
83
80
  storeRef.current.dispose()
@@ -104,8 +101,9 @@ const CommerceUIProvider: React.FC<PropsWithChildren> = ({
104
101
  &&
105
102
  prevPathRef.current !== pathname
106
103
  ) {
107
- storeRef.current.reset()
104
+ storeRef.current.newRoute()
108
105
  prevPathRef.current = pathname
106
+ log("ROUTE CHANGE: " + pathname + ": " + storeRef.current._routeChangedTime)
109
107
  }
110
108
  }, [pathname])
111
109
 
@@ -120,7 +118,6 @@ const CommerceUIProvider: React.FC<PropsWithChildren> = ({
120
118
  export {
121
119
  useCommerceDrawer,
122
120
  useSelectAndBuy,
123
- useRecentActivity,
124
121
  CommerceUIProvider
125
122
  }
126
123
 
@@ -8,10 +8,9 @@ import {
8
8
  type IReactionDisposer,
9
9
  } from 'mobx'
10
10
 
11
- import type { CommerceService, LineItem, ObsLineItemRef } from '@hanzo/commerce/types'
11
+ import type { CommerceService } from '@hanzo/commerce/types'
12
12
 
13
13
  const LOG = false ////////////////////
14
-
15
14
  const log = (s: string) => {
16
15
  if (LOG) {
17
16
  console.log('COMMERCE_UI ' + s)
@@ -32,14 +31,12 @@ type SnapPointsConfig = {
32
31
 
33
32
  type DrawerState = 'closed' | 'micro' | 'full'
34
33
 
35
- interface RecentActivity extends ObsLineItemRef {
36
- quantityChanged(sku: string, val: number, prevVal: number): void
37
- }
38
-
39
34
  interface SelectAndBuy {
40
35
  showVariants: (skuPath: string) => void
36
+ showRecentVariants: () => void
41
37
  hideVariants: () => void
42
38
  get currentSkuPath(): string | undefined
39
+ newRoute: () => void
43
40
  }
44
41
 
45
42
  interface CommerceDrawer {
@@ -54,7 +51,7 @@ interface CommerceDrawer {
54
51
  // Called by UI Gesture
55
52
  onActivePointChanged: (p: SnapPoint | null) => void
56
53
  get showCheckout(): boolean
57
- get showAdded(): boolean
54
+ get showRecent(): boolean
58
55
  get showBuy(): boolean
59
56
 
60
57
  get microHeight(): SnapPoint
@@ -63,11 +60,11 @@ interface CommerceDrawer {
63
60
  }
64
61
 
65
62
  class CommerceUIStore implements
66
- RecentActivity,
67
63
  SelectAndBuy,
68
64
  CommerceDrawer
69
65
  {
70
66
  _vHeight: number = 0
67
+ _routeChangedTime = 0
71
68
 
72
69
  _currentSkuPath: string | undefined = undefined
73
70
  _closedByUser: boolean = false
@@ -75,7 +72,6 @@ class CommerceUIStore implements
75
72
  _ignoreStateChange: boolean = false
76
73
  _activePoint: SnapPoint | null = null
77
74
 
78
- _activeItem: LineItem | undefined = undefined
79
75
  _reactionDisposers: IReactionDisposer[] = []
80
76
  _service: CommerceService
81
77
  _pointsConfig: SnapPointsConfig
@@ -88,32 +84,31 @@ class CommerceUIStore implements
88
84
 
89
85
  makeObservable(this, {
90
86
  _currentSkuPath: observable,
91
- _activeItem: observable.ref,
92
87
  _closedByUser: observable,
93
88
  _checkingOut: observable,
94
89
  _activePoint: observable,
95
90
  _points: observable.ref,
96
91
  _vHeight: observable,
92
+ _routeChangedTime: observable,
97
93
 
98
94
  showVariants: action,
95
+ showRecentVariants: action,
99
96
  hideVariants: action,
100
- quantityChanged: action,
101
97
  setClosedByUser: action,
102
98
  setCheckingOut: action,
103
99
  setActivePoint: action,
104
100
  setMobile: action,
105
101
  setViewportHeight: action,
106
- clearActiveItem: action,
102
+ setRouteChangedTime: action,
107
103
 
108
104
  activePoint: computed,
109
105
  checkingOut: computed,
110
106
  closedByUser: computed,
111
107
  currentSkuPath: computed,
112
- item: computed,
113
108
  microHeight: computed,
114
109
  modal: computed,
115
110
  points: computed,
116
- showAdded: computed,
111
+ showRecent: computed,
117
112
  showBuy: computed,
118
113
  showCheckout: computed,
119
114
  snapPointPx: computed,
@@ -138,36 +133,38 @@ class CommerceUIStore implements
138
133
  }
139
134
  }
140
135
  ))
136
+ /*
141
137
  this._reactionDisposers.push(autorun(() => {
142
138
  log('AUTORUN: OPEN: ' + this.open)
143
139
  log('AUTORUN:' + // ===============
144
140
  '[showCheckout: ' + this.showCheckout +
145
- '], [showAdded: ' + this.showAdded +
141
+ '], [showRecent: ' + this.showRecent +
146
142
  '], [showBuy: ' + this.showBuy +
147
143
  '], [closedByUser: ' + this._closedByUser +
148
144
  '], [checkingOut: ' + this._checkingOut + ']'
149
145
  ) // ===========
150
146
  }))
147
+ */
151
148
  }
152
149
 
153
- reset = () => {
150
+ newRoute = () => {
151
+ this.setRouteChangedTime(new Date().getTime())
154
152
  this.hideVariants()
155
153
  this.setClosedByUser(false)
156
- this.clearActiveItem()
157
154
  // DO NOT reset _checkingOut!
158
155
  }
159
156
 
160
- onActivePointChanged = (pt: SnapPoint | null): void => {
161
- log("ON onActivePointChanged: " + pt) // ===========
162
- if (pt === this._points.micro && this.activePoint === this._points.full) {
157
+ onActivePointChanged = (newPoint: SnapPoint | null): void => {
158
+ log("ON onActivePointChanged: " + newPoint) // ===========
159
+ if (newPoint === this._points.micro && this.activePoint === this._points.full) {
163
160
  this.setIgnoreStateChange(true)
164
161
  this.hideVariants()
165
162
  }
166
- else if (pt === this._points.full && this.activePoint === this._points.micro) {
163
+ else if (newPoint === this._points.full && this.activePoint === this._points.micro) {
167
164
  this.setIgnoreStateChange(true)
168
- this.showVariants(this.item?.sku ?? '')
165
+ this.showRecentVariants()
169
166
  }
170
- this.setActivePoint(pt)
167
+ this.setActivePoint(newPoint)
171
168
  }
172
169
 
173
170
  showVariants = (skuPath: string): void => {
@@ -176,27 +173,17 @@ class CommerceUIStore implements
176
173
  this._closedByUser = false
177
174
  }
178
175
 
179
- hideVariants = (): void => { this._currentSkuPath = undefined }
180
-
181
- get currentSkuPath(): string | undefined { return this._currentSkuPath }
182
-
183
- quantityChanged = (sku: string, val: number, oldVal: number): void => {
184
-
185
- if (val === 0) {
186
- if (this._activeItem?.sku === sku) {
187
- this._activeItem = undefined
188
- }
189
- // otherwise ignore
190
- }
191
- else {
192
- if (!this._activeItem || this._activeItem.sku !== sku) {
193
- this._activeItem = this._service.getItemBySku(sku)
194
- }
176
+ showRecentVariants = (): void => {
177
+ const recentItemInfo = this._service.recentItem
178
+ if (recentItemInfo) {
179
+ this._service.setCurrentItem(undefined)
180
+ this._currentSkuPath = recentItemInfo.item.sku
181
+ this._closedByUser = false
195
182
  }
196
183
  }
197
184
 
198
- get item(): LineItem | undefined { return this._activeItem }
199
- clearActiveItem = (): void => { this._activeItem = undefined }
185
+ hideVariants = (): void => { this._currentSkuPath = undefined }
186
+ get currentSkuPath(): string | undefined { return this._currentSkuPath }
200
187
 
201
188
  get closedByUser(): boolean { return this._closedByUser }
202
189
  setClosedByUser = (b: boolean): void => { this._closedByUser = b}
@@ -210,13 +197,9 @@ class CommerceUIStore implements
210
197
  get activePoint(): SnapPoint | null { return this._activePoint }
211
198
  setActivePoint = (pt: SnapPoint | null): void => { this._activePoint = pt}
212
199
 
200
+ setRouteChangedTime = (t: number): void => {this._routeChangedTime = t}
201
+
213
202
  get points(): SnapPoint[] {
214
- if (this.showBuy && !(this.showAdded || this.showCheckout)) {
215
- return [this._points.full]
216
- }
217
- else if (!this.showBuy && !this.showAdded && this.showCheckout) {
218
- return [this._points.micro]
219
- }
220
203
  return [this._points.micro, this._points.full]
221
204
  }
222
205
 
@@ -234,12 +217,10 @@ class CommerceUIStore implements
234
217
 
235
218
  log('open():' + // ===============
236
219
  ' showCheckout: ' + this.showCheckout +
237
- ' showAdded: ' + this.showAdded +
220
+ ' showRecent: ' + this.showRecent +
238
221
  ' showBuy: ' + this.showBuy
239
222
  ) // ===========
240
223
 
241
-
242
-
243
224
  return (
244
225
  this._checkingOut !== undefined
245
226
  &&
@@ -247,7 +228,7 @@ class CommerceUIStore implements
247
228
  &&
248
229
  !this.closedByUser
249
230
  &&
250
- (this.showCheckout || this.showAdded || this.showBuy)
231
+ (this.showCheckout || this.showRecent || this.showBuy)
251
232
  )
252
233
  }
253
234
 
@@ -256,15 +237,20 @@ class CommerceUIStore implements
256
237
  if (this.showBuy) {
257
238
  return 'full'
258
239
  }
259
- else if (this.showAdded || this.showCheckout) {
240
+ else if (this.showRecent || this.showCheckout) {
260
241
  return 'micro'
261
242
  }
262
243
  }
263
244
  return 'closed'
264
245
  }
265
246
 
247
+ get showRecent(): boolean {
248
+
249
+ const recentInfo = this._service.recentItem
250
+ return !!recentInfo && recentInfo.modified > this._routeChangedTime
251
+ }
252
+
266
253
  get showBuy(): boolean {return !!this.currentSkuPath}
267
- get showAdded(): boolean { return !!this.item}
268
254
  get showCheckout(): boolean { return !this._service.cartEmpty}
269
255
  get modal(): boolean { return this.state !== 'micro'}
270
256
 
@@ -297,7 +283,6 @@ class CommerceUIStore implements
297
283
  export {
298
284
  CommerceUIStore,
299
285
  type CommerceDrawer,
300
- type RecentActivity,
301
286
  type SelectAndBuy,
302
287
  type SnapPointsConfig,
303
288
  type SnapPoints,
@@ -15,6 +15,7 @@ import type { VariantProps } from '@hanzo/ui/util'
15
15
  const BackButton: React.FC<{
16
16
  variant?: VariantProps<typeof buttonVariants>['variant']
17
17
  size?: VariantProps<typeof buttonVariants>['size']
18
+ onBack?: () => void
18
19
  clx?: string
19
20
  iconClx?: string
20
21
  }> = ({
@@ -22,10 +23,16 @@ const BackButton: React.FC<{
22
23
  size='default',
23
24
  clx='',
24
25
  iconClx='',
26
+ onBack
25
27
  }) => {
26
28
 
27
29
  const router = useRouter()
28
- const back = () => {router.back()}
30
+ const back = () => {
31
+ if (onBack) {
32
+ onBack()
33
+ }
34
+ router.back()
35
+ }
29
36
 
30
37
  return (
31
38
  <Button
@@ -9,8 +9,6 @@ import { useStepAnimation } from '@hanzo/ui/util-client'
9
9
 
10
10
  import { Image } from '@hanzo/ui/primitives'
11
11
 
12
- import { useCommerceDrawer, useRecentActivity } from '../../../commerce/ui/context'
13
-
14
12
  import CheckoutButton from '../checkout-button'
15
13
  import useAnimationClxSet from './use-anim-clx-set'
16
14
  import CONST from './const'
@@ -111,8 +109,6 @@ const CheckoutWidget: React.FC<{
111
109
  const isCheckout = usePathname() === '/checkout'
112
110
  const clxSet = useAnimationClxSet(isCheckout)
113
111
 
114
- const recentActivity = useRecentActivity()
115
-
116
112
  // for rendering content after recentActivity.item() would return false
117
113
  const persistentRef = useRef<LineItem | undefined>(undefined)
118
114
 
@@ -0,0 +1,66 @@
1
+ 'use client'
2
+ import React from 'react'
3
+ import { observer } from 'mobx-react-lite'
4
+
5
+ import { ChevronRight } from 'lucide-react'
6
+
7
+ import {
8
+ Accordion,
9
+ AccordionContent,
10
+ AccordionItem,
11
+ AccordionTrigger,
12
+ } from '@hanzo/ui/primitives'
13
+ import { cn } from '@hanzo/ui/util'
14
+
15
+ import { useCommerce, CartPanel, formatCurrencyValue } from '@hanzo/commerce'
16
+
17
+ const CartAccordian: React.FC<{
18
+ icon?: React.ReactNode
19
+ clx?: string
20
+ triggerClx?: string
21
+ panelClx?: string
22
+ scrollAfter: number
23
+ scrollHeightClx: string
24
+ }> = observer(({
25
+ icon,
26
+ clx='',
27
+ panelClx='',
28
+ triggerClx='',
29
+ scrollAfter,
30
+ scrollHeightClx
31
+ }) => {
32
+ const cmmc = useCommerce()
33
+ return (
34
+ <Accordion type="single" collapsible className={clx}>
35
+ <AccordionItem value="cart" className='w-full border-b-0'>
36
+ <AccordionTrigger className={'!no-underline group flex justify-between '} headerClx={ triggerClx}>
37
+ <div className='flex gap-0 items-center'>
38
+ {icon}
39
+ <h5 className='text-sm sm:text-xl grow'>
40
+ <span className='group-data-[state=open]:hidden' >Order Total:</span>
41
+ <span className='group-data-[state=closed]:hidden' >Your Order</span>
42
+ </h5>
43
+ </div>
44
+ <div className='flex gap-1 items-center'>
45
+ <h5 className='text-sm sm:text-xl grow truncate'>{formatCurrencyValue(cmmc.promoAppliedCartTotal)}</h5>
46
+ <ChevronRight className="h-5 w-5 -mr-2 shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-90" />
47
+ </div>
48
+ </AccordionTrigger>
49
+ <AccordionContent className='data-[state=open]:mb-4'>
50
+ <CartPanel
51
+ className={cn('w-full', panelClx)}
52
+ scrollAfter={scrollAfter}
53
+ scrollHeightClx={scrollHeightClx}
54
+ listClx='mt-0'
55
+ itemClx='mt-0.5 mb-0'
56
+ totalClx='sticky px-1 pr-2 border-t -bottom-[1px] bg-background'
57
+ showShipping
58
+ showPromoCode
59
+ />
60
+ </AccordionContent>
61
+ </AccordionItem>
62
+ </Accordion>
63
+ )
64
+ })
65
+
66
+ export default CartAccordian
@@ -0,0 +1,10 @@
1
+ interface CheckoutPanelProps {
2
+ step: number
3
+ stepNames: string[]
4
+ onLeave:() => void
5
+ clx?: string
6
+ }
7
+
8
+ export {
9
+ type CheckoutPanelProps as default
10
+ }
@@ -0,0 +1,83 @@
1
+ 'use client'
2
+ import React, { type PropsWithChildren } from 'react'
3
+ import { observer } from 'mobx-react-lite'
4
+
5
+ import { ScrollArea, StepIndicator } from '@hanzo/ui/primitives'
6
+ import { AuthWidget } from '@hanzo/auth/components'
7
+ import { CartPanel, useCommerce } from '@hanzo/commerce'
8
+ import { cn } from '@hanzo/ui/util'
9
+
10
+ import { BackButton, Logo, Tooltip } from '../..'
11
+ import DesktopBagCarousel from './desktop-bag-carousel'
12
+ import LinksRow from './policy-links'
13
+ import type CheckoutPanelProps from './checkout-panel-props'
14
+
15
+ const DesktopCheckoutPanel: React.FC<PropsWithChildren & CheckoutPanelProps> = observer(({
16
+ step,
17
+ stepNames,
18
+ onLeave,
19
+ clx='',
20
+ children
21
+ }) => {
22
+
23
+ const cmmc = useCommerce()
24
+ return (
25
+ <div /* id='CHECKOUT_PANEL' */ className={cn('grid grid-cols-2', clx)}>
26
+ <div key={1} className='w-full h-full bg-background flex flex-row items-start justify-end'>
27
+ <div className='w-full h-full max-w-[750px] relative flex flex-col items-stretch justify-start px-8 pb-8'>
28
+ <div key={1} className='h-[80px] grow-0 flex flex-row items-center z-10' >
29
+ <Logo size='md' href='/' onClick={onLeave} variant='text-only' outerClx='logo-outer-tooltip-class' />
30
+ <Tooltip select='.logo-outer-tooltip-class' text='home' position='right' offset={6}/>
31
+ </div>
32
+ <BackButton
33
+ size='sm'
34
+ clx={
35
+ 'z-10 absolute top-14 left-6 !px-0 aspect-square ' +
36
+ 'rounded-full hover:!bg-level-3 ' +
37
+ 'back-button-tooltip-class '
38
+ }
39
+ onBack={onLeave}
40
+ />
41
+ <Tooltip select='.back-button-tooltip-class' text='back' position='right' offset={5}/>
42
+ <div key={2} className={cn(
43
+ 'w-full grow min-h-0 max-w-[550px] mx-auto flex flex-col gap-3',
44
+ (cmmc.cartItems.length > 4 ? 'justify-between' : 'justify-start gap-10 pt-10')
45
+ )}>
46
+ <DesktopBagCarousel className='grow-0 h-[260px] w-[360px] lg:w-[420px] mx-auto -mt-8' constrainTo={{w: 250, h: 250}}/>
47
+ <CartPanel
48
+ className='w-full border-none p-0'
49
+ itemClx='mb-2'
50
+ totalClx='sticky bottom-0 bg-background'
51
+ listClx='pr-3'
52
+ scrollAfter={4}
53
+ scrollHeightClx='min-h-[50vh] grow'
54
+ showPromoCode
55
+ showShipping
56
+ selectItems
57
+ />
58
+ </div>
59
+ </div>
60
+ </div>
61
+ <div key={2} className='w-full h-full flex flex-col bg-level-1 min-h-screen justify-between'>
62
+ <ScrollArea className='w-full flex flex-row items-start justify-start overflow-y-auto'>
63
+ <div className='h-full w-full max-w-[750px] relative flex flex-col items-center px-8 pt-0'>
64
+ <div key={1} className='bg-level-1 sticky h-[80px] bg-[#aaaaff] w-full top-0 flex justify-center items-end'>
65
+ <AuthWidget noLogin className='hidden md:flex absolute top-4 right-4 '/>
66
+ <StepIndicator dotSizeRem={1.35} steps={stepNames} currentStep={step} className='gap-2 text-base w-pr-70' />
67
+ </div>
68
+ <div key={2} className='w-full max-w-[550px] mx-auto py-8'>
69
+ {children}
70
+ </div>
71
+ </div>
72
+ </ScrollArea>
73
+ <div className='w-full max-w-[750px] relative flex flex-col items-center px-8 pt-0'>
74
+ <div className='w-full max-w-[550px] mx-auto flex flex-col items-center'>
75
+ <LinksRow clx='w-full' />
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ )
81
+ })
82
+
83
+ export default DesktopCheckoutPanel
@@ -26,15 +26,13 @@ const STEPS = [
26
26
 
27
27
  const STEP_NAMES = STEPS.map((s) => (s.label ? s.label : capitalize(s.name)))
28
28
 
29
- import DesktopCP from './dt-checkout-panel'
30
- import MobileCP from './mb-checkout-panel'
29
+ import DesktopCP from './desktop-cp'
30
+ import MobileCP from './mobile-cp'
31
31
 
32
32
  const CheckoutPanel: React.FC<{
33
- close: () => void
34
- className?: string
33
+ clx?: string
35
34
  }> = ({
36
- close,
37
- className=''
35
+ clx=''
38
36
  }) => {
39
37
 
40
38
  const cmmc = useCommerce()
@@ -78,16 +76,15 @@ const CheckoutPanel: React.FC<{
78
76
 
79
77
  const _close = () => {
80
78
  setStep('first')
81
- close()
82
79
  }
83
80
 
84
- // Determine if mobile or desktop based on visibility of desktopElement
85
- // https://stackoverflow.com/a/21696585/11378853
81
+ // Determine if mobile or desktop layout based on visibility of desktopElement
82
+ // This prevents issues with multiple instances of 3rd party e-commerce widgets
83
+ // from ever being in the DOM.
84
+ // https://stackoverflow.com/a/21696585/11378853
86
85
  const desktopElement = useRef<HTMLDivElement | null>(null)
87
- const [layout, setLayout] = useState<'mobile' | 'desktop' | undefined>()
86
+ const [layout, setLayout] = useState<'mobile' | 'desktop' | undefined>(undefined)
88
87
 
89
- // TODO :aa I assume it's becase we don't want two instance of the Square plugin....
90
- // ... wondering if there is a simpler way.
91
88
  useLayoutEffect(() => {
92
89
  const checkLayout = () => {
93
90
  setLayout(!!desktopElement.current?.offsetParent ? 'desktop' : 'mobile')
@@ -106,19 +103,19 @@ const CheckoutPanel: React.FC<{
106
103
 
107
104
  return (<>
108
105
  <DesktopCP
109
- className={cn('h-full', className, 'hidden md:flex')}
110
- close={_close}
111
- index={stepIndex}
106
+ clx={cn('h-full', clx, 'hidden md:flex')}
107
+ onLeave={_close}
108
+ step={stepIndex}
112
109
  stepNames={STEP_NAMES}
113
110
  >
114
- {/* Element required to determine if DesktopCP is visible */}
111
+ {/* Element required to determine if DesktopCP is visible. See above. */}
115
112
  <div ref={desktopElement}/>
116
113
  {layout === 'desktop' && <StepToRender onDone={() => {setStep('next')}} orderId={orderId} setOrderId={setOrderId}/>}
117
114
  </DesktopCP>
118
115
  <MobileCP
119
- className={cn('h-full overflow-y-auto', className, 'md:hidden' )}
120
- close={_close}
121
- index={stepIndex}
116
+ clx={cn('w-full h-full overflow-y-auto', clx, 'md:hidden' )}
117
+ onLeave={_close}
118
+ step={stepIndex}
122
119
  stepNames={STEP_NAMES}
123
120
  >
124
121
  {layout === 'mobile' && <StepToRender onDone={() => {setStep('next')}} orderId={orderId} setOrderId={setOrderId}/>}
@@ -0,0 +1,67 @@
1
+ 'use client'
2
+ import React, { type PropsWithChildren } from 'react'
3
+
4
+ import { StepIndicator } from '@hanzo/ui/primitives'
5
+ import { cn } from '@hanzo/ui/util'
6
+ import { AuthWidget } from '@hanzo/auth/components'
7
+
8
+ import { BackButton, Logo } from '../..'
9
+ import BagButton from '../bag-button'
10
+ import PolicyLinks from './policy-links'
11
+ import CartAccordian from './cart-accordian'
12
+ import type CheckoutPanelProps from './checkout-panel-props'
13
+
14
+
15
+ const MobileCheckoutPanel: React.FC<PropsWithChildren & CheckoutPanelProps> = ({
16
+ step,
17
+ stepNames,
18
+ onLeave,
19
+ clx='',
20
+ children
21
+ }) => (
22
+
23
+ <div /* id='MOBILE_GRID' */ className={cn('bg-background flex flex-col justify-start px-4 pt-[101px]', clx)}>
24
+ <div className='fixed z-11 top-0 h-[45px] w-full flex justify-between items-stretch bg-background'>
25
+ <div className='flex items-stretch gap-1 grow-0'>
26
+ <BackButton
27
+ size='sm'
28
+ clx={
29
+ '-ml-5 !px-0 aspect-square h-full ' +
30
+ 'rounded-full active:!bg-level-3 '
31
+ }
32
+ onBack={onLeave}
33
+ />
34
+ <Logo size='xs' variant='text-only' href='/' onClick={onLeave} outerClx='-ml-2'/>
35
+ </div>
36
+ <StepIndicator
37
+ dotSizeRem={1}
38
+ steps={stepNames}
39
+ currentStep={step}
40
+ className='relative grow mx-2 top-[14px] text-xs font-semibold w-full'
41
+ />
42
+
43
+ {/* 72px by observation (for centering). Need wrapper div since 'noLogin' returns null if no logged in user */}
44
+ <div className='w-[72px] grow-0 shrink-0 flex items-center justify-center'><AuthWidget noLogin className=''/></div>
45
+ </div>
46
+ <CartAccordian
47
+ icon={
48
+ <BagButton
49
+ animateOnHover={false}
50
+ showIfEmpty
51
+ size='sm'
52
+ className='mr-1 relative w-5 h-6 sm:w-6 sm:h-7'
53
+ iconClx='fill-foreground'
54
+ />
55
+ }
56
+ clx='flex items-center justify-center w-full'
57
+ triggerClx='bg-background fixed z-11 top-[45px] left-0 right-0 !m-0 px-4'
58
+ panelClx='!py-0'
59
+ scrollAfter={3}
60
+ scrollHeightClx='h-[385px]'
61
+ />
62
+ {children}
63
+ <PolicyLinks clx='mt-auto mb-3 pt-2' />
64
+ </div>
65
+ )
66
+
67
+ export default MobileCheckoutPanel
@@ -0,0 +1,29 @@
1
+ import React from 'react'
2
+ import Link from 'next/link'
3
+
4
+ import { Separator, buttonVariants } from '@hanzo/ui/primitives'
5
+ import { cn } from '@hanzo/ui/util'
6
+
7
+
8
+ const linkClx = buttonVariants({
9
+ variant: 'linkMuted',
10
+ size: 'link',
11
+ rounded: 'none',
12
+ })
13
+
14
+ const PolicyLinks: React.FC<{
15
+ clx?: string
16
+ }> = ({
17
+ clx=''
18
+ }) => (
19
+ <div className={cn('flex flex-col items-center', clx)}>
20
+ <Separator/>
21
+ <div className='flex gap-4 py-2 text-sm'>
22
+ {/* TODO: add Refund policy and Privacy policy links */}
23
+ <Link className={linkClx} href=''>refund policy</Link>
24
+ <Link className={linkClx} href=''>privacy policy</Link>
25
+ </div>
26
+ </div>
27
+ )
28
+
29
+ export default PolicyLinks
@@ -8,7 +8,6 @@ import { CarouselBuyCard } from '@hanzo/commerce'
8
8
  import {
9
9
  useSelectAndBuy,
10
10
  useCommerceDrawer,
11
- useRecentActivity
12
11
  } from '../../../commerce/ui/context'
13
12
 
14
13
  import CommerceDrawer from './shell'
@@ -19,33 +18,24 @@ const CommerceUIComponent: React.FC = observer(() => {
19
18
 
20
19
  const buy = useSelectAndBuy()
21
20
  const drawer = useCommerceDrawer()
22
- const recent = useRecentActivity()
23
21
  const router = useRouter()
24
-
25
22
 
26
23
  const handleCheckout = (): void => {
27
24
  router.push('/checkout')
28
25
  }
29
26
 
30
-
31
27
  const handleHandleClicked = (): void => {
32
28
 
33
29
  if (drawer.state === 'full') {
34
30
  buy.hideVariants()
35
31
  }
36
32
  else if (drawer.state === 'micro') {
37
- if (drawer.showAdded) {
38
- buy.showVariants(recent.item?.sku ?? '')
39
- }
40
- // checkout only
41
- else {
42
- drawer.setClosedByUser(true)
43
- }
33
+ buy.showRecentVariants()
44
34
  }
45
35
  }
46
36
 
47
37
  const handleItemClicked = () => {
48
- buy.showVariants(recent.item?.sku ?? '')
38
+ buy.showRecentVariants()
49
39
  }
50
40
 
51
41
  const handleCloseGesture = (): boolean => {
@@ -76,7 +66,6 @@ const CommerceUIComponent: React.FC = observer(() => {
76
66
  className='w-full min-w-[160px] sm:max-w-[320px]'
77
67
  />
78
68
  }
79
- onQuantityChanged={recent.quantityChanged.bind(recent)}
80
69
  clx='justify-between h-full pb-3 gap-8'
81
70
  addBtnClx='w-full min-w-[160px] sm:max-w-[320px]'
82
71
  buttonsAreaClx='grow-0 shrink-0 mt-0'
@@ -8,7 +8,7 @@ import type { LineItem } from '@hanzo/commerce/types'
8
8
  import { useCommerce, formatCurrencyValue } from '@hanzo/commerce'
9
9
 
10
10
  import CheckoutButton from '../checkout-button'
11
- import { useCommerceDrawer, useRecentActivity } from '../../../commerce/ui/context'
11
+ import { useCommerceDrawer } from '../../../commerce/ui/context'
12
12
 
13
13
  const CN = {
14
14
  // h: mind padding!
@@ -67,17 +67,16 @@ const Micro: React.FC<{
67
67
  }) => {
68
68
 
69
69
  const drawer = useCommerceDrawer()
70
- const recent = useRecentActivity()
71
- const mobile = drawer.isMobile
70
+ const cmmc = useCommerce()
72
71
 
73
72
  return (
74
73
  <div className={cn(
75
- (drawer.showAdded ? 'grid grid-cols-2' : 'flex justify-center items-center '),
76
- (drawer.showAdded ? ((drawer.isMobile) ? '-mt-3' : '-mt-3') : ''),
74
+ (drawer.showRecent ? 'grid grid-cols-2' : 'flex justify-center items-center '),
75
+ (drawer.showRecent ? ((drawer.isMobile) ? '-mt-3' : '-mt-3') : ''),
77
76
  'gap-2 md:gap-3 relative',
78
77
  clx
79
78
  )}>
80
- {drawer.showAdded && (
79
+ {drawer.showRecent && (
81
80
  <div className={'flex flex-col items-stretch ' + (drawer.isMobile ? 'justify-start' : 'group')}>
82
81
  <p className={'relative text-muted text-xxs md:text-xs leading-none pl-1 self-start ' + (drawer.isMobile ? 'top-[3px]' : 'top-[1px]')}>
83
82
  <span className='invisible'>scrictly for layout</span>
@@ -91,7 +90,7 @@ const Micro: React.FC<{
91
90
  <Button
92
91
  variant='ghost'
93
92
  rounded={drawer.isMobile ? 'md' : 'lg'}
94
- size={drawer.isMobile ? 'default' : 'lg'}
93
+ size={drawer.isMobile ? 'sm' : 'lg'}
95
94
  onClick={handleItemClicked}
96
95
  className={cn(
97
96
  'box-content',
@@ -103,14 +102,14 @@ const Micro: React.FC<{
103
102
  'group-hover:!bg-transparent '
104
103
  )}
105
104
  >
106
- {recent.item?.img && (<>
107
- <Image def={recent.item.img} constrainTo={CN.mobile} preload className='sm:hidden grow-0 shrink-0'/>
108
- <Image def={recent.item.img} constrainTo={CN.sm} preload className='hidden sm:block md:hidden grow-0 shrink-0'/>
109
- <Image def={recent.item.img} constrainTo={CN.desktop} preload className='hidden md:block grow-0 shrink-0'/>
105
+ {cmmc.recentItem?.item.img && (<>
106
+ <Image def={cmmc.recentItem.item.img} constrainTo={CN.mobile} preload className='sm:hidden grow-0 shrink-0'/>
107
+ <Image def={cmmc.recentItem.item.img} constrainTo={CN.sm} preload className='hidden sm:block md:hidden grow-0 shrink-0'/>
108
+ <Image def={cmmc.recentItem.item.img} constrainTo={CN.desktop} preload className='hidden md:block grow-0 shrink-0'/>
110
109
  </>)}
111
- {recent.item && (
110
+ {cmmc.recentItem && (
112
111
  <div className='grow w-full'>
113
- <Info item={recent.item} clx='w-full'/>
112
+ <Info item={cmmc.recentItem.item} clx='w-full'/>
114
113
  </div>
115
114
  )}
116
115
  </Button>
@@ -119,20 +118,21 @@ const Micro: React.FC<{
119
118
  {drawer.showCheckout && (
120
119
  <div className={cn(
121
120
  'flex flex-col w-full',
122
- (drawer.showAdded ? 'items-stretch' : 'items-center' ),
121
+ (drawer.showRecent ? 'items-stretch' : 'items-center' ),
123
122
  (drawer.isMobile ? 'justify-start' : 'justify-center')
124
123
  )}>
125
- {drawer.showAdded && <p className='invisible text-muted text-xxs md:text-xs leading-none pl-1 self-start'>for layout</p>}
124
+ {drawer.showRecent && <p className='invisible text-muted text-xxs md:text-xs leading-none pl-1 self-start'>for layout</p>}
126
125
  <CheckoutButton
127
126
  handleCheckout={handleCheckout}
128
127
  variant='primary'
129
- size={drawer.isMobile ? 'default' : 'lg'}
128
+ size={drawer.isMobile ? 'xs' : 'lg'}
130
129
  rounded={drawer.isMobile ? 'md' : 'lg'}
131
- centerText={drawer.isMobile ? !drawer.showAdded : true}
130
+ centerText={drawer.isMobile ? !drawer.showRecent : true}
132
131
  className={cn(drawer.isMobile ?
133
- (drawer.showAdded ? 'pl-3.5 pr-2.5' : 'min-w-[320px]')
132
+ (drawer.showRecent ? 'pl-3.5 pr-2.5' : 'min-w-[320px]')
134
133
  :
135
- (drawer.showAdded ? '' : 'w-[320px]')
134
+ (drawer.showRecent ? '' : 'w-[320px]'),
135
+ 'text-sm font-semibold'
136
136
  )}
137
137
  />
138
138
  </div>
@@ -1,7 +1,6 @@
1
1
  'use client'
2
2
  import React, { useState } from 'react'
3
3
  import { ArrowRight, Plus } from 'lucide-react'
4
- import { Search } from '../icons'
5
4
  import { Button, Card } from '@hanzo/ui/primitives'
6
5
  import { Logo } from '..'
7
6
 
@@ -11,14 +11,12 @@ export { default as MiniChart } from './mini-chart'
11
11
  export { default as NotFound } from './not-found'
12
12
 
13
13
  export { default as AuthListener } from './auth/auth-listener'
14
- export { default as AddWidget } from './commerce/add-widget'
15
14
  export { default as BackButton } from './back-button'
16
15
  export { default as BuyDrawer } from './commerce/drawer'
17
16
  export { default as DrawerMargin } from './drawer-margin'
18
17
  export { default as BuyButton } from './commerce/buy-button'
19
18
  export { default as CheckoutButton } from './commerce/checkout-button'
20
19
  export { default as CheckoutPanel } from './commerce/checkout-panel'
21
- export { default as CheckoutWidget } from './commerce/checkout-widget'
22
20
  export { default as LoginPanel } from './auth/login-panel'
23
21
  export { default as Scripts } from './scripts'
24
22
  export { default as Tooltip } from './tooltip'
@@ -39,7 +39,7 @@ const MiniChart: React.FC<MiniChartProps> = ({
39
39
  iframe.style.colorScheme = 'normal'
40
40
  setTimeout(() => {
41
41
  const value = document.querySelector('#mini-symbol-overview-ticker')
42
- console.log("TICKER: " + value)
42
+ //console.log("TICKER: " + value)
43
43
  }, 1200) // from experimentation
44
44
 
45
45
 
@@ -47,7 +47,7 @@ const MiniChart: React.FC<MiniChartProps> = ({
47
47
 
48
48
  const copyDiv = document.querySelector('.tradingview-widget-copyright')
49
49
  if (copyDiv) {
50
- console.log("COPY: " + copyDiv)
50
+ //console.log("COPY: " + copyDiv)
51
51
  setTimeout(() => {
52
52
  copyDiv.classList.remove('invisible')
53
53
  }, 1200) // from experimentation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luxfi/core",
3
- "version": "5.2.13",
3
+ "version": "5.3.0",
4
4
  "description": "Library that contains shared UI primitives, support for a common design system, and other boilerplate support.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
@@ -44,7 +44,7 @@ const viewport = {
44
44
  We cannot have these on body tag for scroll-snap to work on iOS!
45
45
  */
46
46
  const bodyClasses =
47
- 'bg-background text-foreground flex flex-col min-h-full overflow-x-hidden ' +
47
+ 'bg-background text-foreground flex flex-col min-h-full ' +
48
48
  getAppRouterBodyFontClasses()
49
49
 
50
50
  async function RootLayout({
package/tsconfig.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "extends": "../tsconfig.modules.base.json",
3
3
  "include": [
4
4
  "**/*.ts",
5
- "**/*.tsx",
5
+ "**/*.tsx", "components/commerce/_to_deprecate_checkout-widget/index.tsx_",
6
6
  ],
7
7
  "exclude": [
8
8
  "node_modules",
@@ -1,20 +0,0 @@
1
- 'use client'
2
- import React from 'react'
3
-
4
- import type { LineItem } from '@hanzo/commerce/types'
5
- import { AddToCartWidget } from '@hanzo/commerce'
6
-
7
- import { useRecentActivity } from '../../commerce/ui/context'
8
-
9
- const AddWidget: React.FC<{
10
- item: LineItem
11
- disabled?: boolean
12
- className?: string
13
- buttonClx?: string
14
- variant?: 'minimal' | 'primary' | 'outline'
15
- }> = (props) => {
16
- const l = useRecentActivity()
17
- return <AddToCartWidget {...props} onQuantityChanged={l.quantityChanged.bind(l)}/>
18
- }
19
-
20
- export default AddWidget
@@ -1,85 +0,0 @@
1
- 'use client'
2
- import React, { type PropsWithChildren } from 'react'
3
- import { observer } from 'mobx-react-lite'
4
-
5
- import { ScrollArea, StepIndicator } from '@hanzo/ui/primitives'
6
- import { AuthWidget } from '@hanzo/auth/components'
7
- import { CartPanel, useCommerce } from '@hanzo/commerce'
8
- import { cn } from '@hanzo/ui/util'
9
-
10
- import { BackButton, Logo, Tooltip } from '../..'
11
- import DesktopBagCarousel from './dt-bag-carousel'
12
- import LinksRow from './links-row'
13
-
14
- const DesktopCheckoutPanel: React.FC<PropsWithChildren & {
15
- index: number
16
- stepNames: string[]
17
- close: () => void
18
- className?: string
19
- }> = observer(({
20
- index,
21
- stepNames,
22
- close,
23
- className='',
24
- children
25
- }) => {
26
-
27
- const cmmc = useCommerce()
28
-
29
- return (
30
- <div /* id='CHECKOUT_PANEL' */ className={cn('grid grid-cols-2', className)}>
31
- <div key={1} className='w-full h-full bg-background flex flex-row items-start justify-end'>
32
- <div className='w-full h-full max-w-[750px] relative flex flex-col items-stretch justify-start px-8 pb-8'>
33
- <div key={1} className='h-[80px] grow-0 flex flex-row items-center z-10' >
34
- <Logo onClick={close} size='md' href='/' variant='text-only' outerClx='logo-outer-tooltip-class' />
35
- <Tooltip select='.logo-outer-tooltip-class' text='home' position='right' offset={6}/>
36
- </div>
37
- <BackButton size='sm' clx={
38
- 'z-10 absolute top-14 left-6 !px-0 aspect-square ' +
39
- 'rounded-full hover:!bg-level-3 ' +
40
- //'border border-transparent hover:border-muted-2 ' +
41
- 'back-button-tooltip-class '
42
- }/>
43
- <Tooltip select='.back-button-tooltip-class' text='back' position='right' offset={5}/>
44
- <div key={2} className={cn(
45
- 'w-full grow min-h-0 max-w-[550px] mx-auto flex flex-col gap-3',
46
- (cmmc.cartItems.length > 4 ? 'justify-between' : 'justify-start gap-10 pt-10')
47
- )}>
48
- <DesktopBagCarousel className='grow-0 h-[260px] w-[360px] lg:w-[420px] mx-auto -mt-8' constrainTo={{w: 250, h: 250}}/>
49
- <CartPanel
50
- className='w-full border-none p-0'
51
- itemClx='mb-2'
52
- totalClx='sticky bottom-0 bg-background'
53
- listClx='pr-3'
54
- scrollAfter={5}
55
- scrollHeightClx='min-h-[50vh] grow'
56
- showPromoCode
57
- showShipping
58
- selectItems
59
- />
60
- </div>
61
- </div>
62
- </div>
63
- <div key={2} className='w-full h-full flex flex-col bg-level-1 min-h-screen justify-between'>
64
- <ScrollArea className='w-full flex flex-row items-start justify-start overflow-y-auto'>
65
- <div className='h-full w-full max-w-[750px] relative flex flex-col items-center px-8 pt-0'>
66
- <div key={1} className='bg-level-1 sticky h-30 pb-8 w-full top-0 flex justify-center items-end'>
67
- <AuthWidget noLogin className='hidden md:flex absolute top-4 right-4 '/>
68
- <StepIndicator dotSizeRem={1.5} steps={stepNames} currentStep={index} className='gap-2 text-base w-pr-70' />
69
- </div>
70
- <div key={2} className='w-full max-w-[550px] mx-auto pb-10'>
71
- {children}
72
- </div>
73
- </div>
74
- </ScrollArea>
75
- <div className='w-full max-w-[750px] relative flex flex-col items-center px-8 pt-0'>
76
- <div className='w-full max-w-[550px] mx-auto flex flex-col items-center'>
77
- <LinksRow className='w-full' />
78
- </div>
79
- </div>
80
- </div>
81
- </div>
82
- )
83
- })
84
-
85
- export default DesktopCheckoutPanel
@@ -1,21 +0,0 @@
1
- import Link from 'next/link'
2
-
3
- import { Separator } from '@hanzo/ui/primitives'
4
- import { cn } from '@hanzo/ui/util'
5
-
6
- const LinksRow: React.FC<{
7
- className?: string
8
- }> = ({
9
- className=''
10
- }) => (
11
- <div className={cn('flex flex-col', className)}>
12
- <Separator/>
13
- <div className='flex gap-4 text-sm py-2'>
14
- {/* TODO: add Refund policy and Privacy policy links */}
15
- <Link href=''>Refund policy</Link>
16
- <Link href=''>Privacy policy</Link>
17
- </div>
18
- </div>
19
- )
20
-
21
- export default LinksRow
@@ -1,55 +0,0 @@
1
- 'use client'
2
- import React, { type PropsWithChildren } from 'react'
3
-
4
- import { StepIndicator } from '@hanzo/ui/primitives'
5
- import { cn } from '@hanzo/ui/util'
6
- import { AuthWidget } from '@hanzo/auth/components'
7
- import { CartAccordian } from '@hanzo/commerce'
8
-
9
- import { Logo } from '../..'
10
- import BagButton from '../bag-button'
11
- import LinksRow from './links-row'
12
-
13
- const MobileCheckoutPanel: React.FC<PropsWithChildren & {
14
- index: number
15
- stepNames: string[]
16
- close:() => void
17
- className?: string
18
- }> = ({
19
- index,
20
- stepNames,
21
- close,
22
- className='',
23
- children
24
- }) => (
25
-
26
- <div /* id='MOBILE_GRID' */ className={cn('bg-background flex flex-col justify-start px-4', className)}>
27
- <div className='sticky top-0 w-full flex flex-row justify-between items-center bg-background'>
28
- <Logo onClick={close} size='xs' href='/' />
29
- {/* Need wrapper div since 'noLogin' returns null if no logged in user */}
30
- <div className='w-10 h-10 flex items-center justify-center'><AuthWidget noLogin className=''/></div>
31
- </div>
32
- <CartAccordian
33
- icon={
34
- <BagButton
35
- animateOnHover={false}
36
- showIfEmpty
37
- size='sm'
38
- className='mr-1 relative w-5 h-6 sm:w-6 sm:h-7'
39
- iconClx='fill-foreground'
40
- />
41
- }
42
- className='flex items-center justify-center w-full'
43
- />
44
- <StepIndicator
45
- dotSizeRem={1}
46
- steps={stepNames}
47
- currentStep={index}
48
- className='text-xs font-semibold w-full pb-3'
49
- />
50
- {children}
51
- <LinksRow className='mt-auto mb-3 pt-2' />
52
- </div>
53
- )
54
-
55
- export default MobileCheckoutPanel