@luxfi/core 5.3.1 → 5.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) 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/copyright.tsx +3 -3
  15. package/components/index.ts +0 -2
  16. package/components/mini-chart/mini-chart.tsx +2 -2
  17. package/package.json +1 -1
  18. package/root-layout/index.tsx +1 -1
  19. package/tsconfig.json +1 -1
  20. package/components/commerce/add-widget.tsx +0 -20
  21. package/components/commerce/checkout-panel/dt-checkout-panel.tsx +0 -85
  22. package/components/commerce/checkout-panel/links-row.tsx +0 -21
  23. package/components/commerce/checkout-panel/mb-checkout-panel.tsx +0 -55
  24. /package/components/commerce/{checkout-widget → _to_deprecate_checkout-widget}/const.ts +0 -0
  25. /package/components/commerce/{checkout-widget → _to_deprecate_checkout-widget}/obs-string-set.ts +0 -0
  26. /package/components/commerce/{checkout-widget → _to_deprecate_checkout-widget}/use-anim-clx-set.ts +0 -0
  27. /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
 
@@ -5,7 +5,7 @@ const FIRST = 2020
5
5
  const Copyright: React.FC<{
6
6
  className?: string
7
7
  }> = ({
8
- className=''
8
+ className=''
9
9
  }) => {
10
10
 
11
11
  const year = new Date().getFullYear()
@@ -13,8 +13,8 @@ const Copyright: React.FC<{
13
13
 
14
14
  return (
15
15
  <div className={className}>
16
- {`Copyright © ${yearString}`}&nbsp;<br className='sm:hidden'/>Lux Partners Ltd.&nbsp;<br className='md:hidden'/>&nbsp;All rights reserved.
17
- </div>
16
+ {`Copyright © ${yearString}`}&nbsp;<br className='sm:hidden'/>Lux Partners Limited.&nbsp;<br className='md:hidden'/>&nbsp;All rights reserved.
17
+ </div>
18
18
  )
19
19
  }
20
20
 
@@ -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.3.1",
3
+ "version": "5.3.2",
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