@luxfi/core 5.0.2 → 5.0.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.
@@ -0,0 +1,34 @@
1
+ [
2
+ {
3
+ "id": "LXM-AG-B",
4
+ "title": "Minted Bar",
5
+ "parentTitle": "Lux Silver",
6
+ "desc": "Get unprecedented access to silver with 1:1 asset-backed Lux Silver NFTs, sovereign ownership of physical silver without management fees, and mine-direct discount pricing.",
7
+ "img": {
8
+ "src": "/assets/commerce/silver/product/silver-bar-pt-800x800.png",
9
+ "dim": {
10
+ "w": 800,
11
+ "h": 800
12
+ }
13
+ },
14
+ "products": [
15
+ {
16
+ "id": "fce17569-a86c-4f69-bc61-ab435ed0c46f",
17
+ "sku": "LXM-AG-B-1_OZ",
18
+ "fullTitle": "Lux Silver, 1oz Minted Bar",
19
+ "optionLabel": "1oz",
20
+ "familyTitle": "Minted Bar",
21
+ "familyId": "LXM-AG-B",
22
+ "desc": "Get unprecedented access to silver with 1:1 asset-backed Lux Silver NFTs, sovereign ownership of physical silver without management fees, and mine-direct discount pricing.",
23
+ "price": 0,
24
+ "img": {
25
+ "src": "/assets/commerce/silver/product/silver-bar-pt-800x800.png",
26
+ "dim": {
27
+ "w": 800,
28
+ "h": 800
29
+ }
30
+ }
31
+ }
32
+ ]
33
+ }
34
+ ]
@@ -0,0 +1,12 @@
1
+ // updated manually apr 29, 2024
2
+
3
+ export default {
4
+ au: {
5
+ market1oz: 2336.50,
6
+ discount: 0.01
7
+ },
8
+ ag: {
9
+ market1oz: 27.143,
10
+ discount: 0.10
11
+ },
12
+ }
@@ -0,0 +1,50 @@
1
+ import type { Family } from '@hanzo/commerce/types'
2
+
3
+ import prices from './EDIT-ME-bullion-market-prices'
4
+
5
+ const sep = {
6
+ tok: '-',
7
+ subTok: '_',
8
+ decimal: '.'
9
+ }
10
+
11
+ const GRAMS_PER_OZ = 28.3495
12
+
13
+ const tree: any = {}
14
+ for (let key in prices) {
15
+ const values = prices[key as keyof typeof prices]
16
+ tree[key] = {
17
+ oz: values.market1oz * (1 - values.discount),
18
+ g: values.market1oz * (1 - values.discount) / GRAMS_PER_OZ
19
+ }
20
+ }
21
+
22
+ // LXB-AU-B-1_OZ, LXB-AU-B-2.5_g
23
+ const priceFromSKU = (
24
+ sku: string
25
+ ) => {
26
+ const tokens = sku.split(sep.tok)
27
+ const type_ = tokens[1].toLowerCase()
28
+
29
+ const quanAndUnit = tokens[tokens.length - 1]
30
+ const quanAndUnitToks = quanAndUnit.split(sep.subTok)
31
+ let quantity = quanAndUnitToks[0].includes(sep.decimal) ? parseFloat(quanAndUnitToks[0].split(sep.decimal).join('.')) : parseInt(quanAndUnitToks[0])
32
+ let unit = quanAndUnitToks[1].toLowerCase()
33
+ if (unit === 'kg') {
34
+ quantity *= 1000
35
+ unit = 'g'
36
+ }
37
+ else if (unit === 'lb') {
38
+ quantity *= 16
39
+ unit = 'oz'
40
+ }
41
+
42
+ return tree[type_][unit] * quantity
43
+ }
44
+
45
+ export default (c: Family): Family => {
46
+ for (let prod of c.products) {
47
+ prod.price = priceFromSKU(prod.sku)
48
+ }
49
+ return c
50
+ }
@@ -0,0 +1,14 @@
1
+ import type { VideoDef } from '@hanzo/ui/types'
2
+ import type { Family } from '@hanzo/commerce/types'
3
+
4
+ export default (fam: Family, map: Map<string, VideoDef>): Family => {
5
+ if (fam.parentTitle) {
6
+ for (let prod of fam.products) {
7
+ const video = map.get(fam.parentTitle)
8
+ if (video) {
9
+ prod.video = video
10
+ }
11
+ }
12
+ }
13
+ return fam
14
+ }
@@ -0,0 +1,5 @@
1
+ import PRICES from './EDIT-ME-bullion-market-prices'
2
+
3
+ export default (type_: keyof typeof PRICES): number => (
4
+ PRICES[type_].market1oz * (1 - PRICES[type_].discount)
5
+ )
@@ -0,0 +1,18 @@
1
+ import type { VideoDef } from '@hanzo/ui/types'
2
+
3
+ import bullionByFamily from './AUTO-GEN-bullion-by-family.json'
4
+
5
+ import assignPrices from './assign-prices'
6
+ import assignVideosByFamilyGroup from './assign-videos-by-family-group'
7
+
8
+ export const getBullionFamilies = (videoMap: Map<string, VideoDef>) => (
9
+ bullionByFamily.map(
10
+ (fam) => (assignPrices(fam))).map(
11
+ (fam) => (assignVideosByFamilyGroup(fam, videoMap)
12
+ )
13
+ )
14
+ )
15
+
16
+ export { default as serviceOptions } from './lux-service-options'
17
+ export { default as bullionPrice1oz } from './bullion-price-1oz'
18
+
@@ -0,0 +1,6 @@
1
+ import type { ServiceOptions } from '@hanzo/commerce'
2
+
3
+ export default {
4
+ dbName: 'lux-commerce',
5
+ ordersTable: 'orders'
6
+ } satisfies ServiceOptions
@@ -2,9 +2,10 @@
2
2
  import React from 'react'
3
3
 
4
4
  import { Button, Card } from '@hanzo/ui/primitives'
5
+ import { cn } from '@hanzo/ui/util'
5
6
 
6
7
  import LuxLogo from './icons/lux-logo'
7
- import { cn } from '@hanzo/ui/util'
8
+ import type { ChatbotSuggestedQuestion } from '../types'
8
9
 
9
10
  const ChatWidget: React.FC<{
10
11
  title: string,
@@ -12,6 +13,7 @@ const ChatWidget: React.FC<{
12
13
  subtitle?: string,
13
14
  question?: string,
14
15
  /*
16
+ ChatBotSuggestQuestion.icon
15
17
  Currently supports these icons from remix icons (https://remixicon.com/):
16
18
  GlobalLineIcon,
17
19
  ShieldFlashLineIcon,
@@ -19,7 +21,7 @@ const ChatWidget: React.FC<{
19
21
  GroupLineIcon,
20
22
  QuestionnaireLineIcon
21
23
  */
22
- suggestedQuestions?: { heading: string, message: string, icon?: string }[]
24
+ suggestedQuestions?: ChatbotSuggestedQuestion[]
23
25
  }> = ({
24
26
  title,
25
27
  chatbotUrl,
@@ -1,109 +1,17 @@
1
1
  'use client'
2
- import React, { useEffect, useRef } from 'react'
3
- import { createPortal } from 'react-dom'
4
- import { useRouter, usePathname } from 'next/navigation'
5
- import { ObservableSet, observable, reaction, type IReactionDisposer, runInAction} from 'mobx'
2
+ import React from 'react'
3
+ import { useRouter } from 'next/navigation'
6
4
  import { observer } from 'mobx-react-lite'
7
5
 
8
- import { cn } from '@hanzo/ui/util'
9
- import { Image } from '@hanzo/ui/primitives'
10
-
11
- import { useCommerce, useCommerceUI, CarouselBuyCard, LineItemRef } from '@hanzo/commerce'
12
- import type { LineItem } from '@hanzo/commerce/types'
6
+ import { useCommerceUI, CarouselBuyCard } from '@hanzo/commerce'
13
7
 
14
8
  import CommerceDrawer from './drawer'
15
9
  import CheckoutButton from '../checkout-button'
16
10
 
17
- const DEF_IMG_CONSTRAINT={w: 40, h: 24}
18
- const CO_ANIM_DURATION = 400
19
- const CO_ANIM_TIMING_FN = 'cubic-bezier(0.4, 0, 0.2, 1)'
20
- const CO_WIDGET_W_CLX = {
21
- checkout: 'w-pr-40',
22
- itemInfo: 'w-pr-60'
23
- }
24
-
25
- const CO_WIDGET_SHADOW_STYLE = {
26
- border: '1px solid rgb(100 100 100)',
27
- boxShadow: '2px 4px 4px -3px rgb(125 125 125 / 0.7), 4px -4px 8px -4px rgb(125 125 125 / 0.7)'
28
- }
29
-
30
11
  const CommerceUIComponent: React.FC = observer(() => {
31
12
 
32
13
  const ui = useCommerceUI()
33
- const cmmc = useCommerce()
34
14
  const router = useRouter()
35
- const isCheckout = usePathname() === '/checkout'
36
-
37
- const animClxRef = useRef<ObservableSet<string>>(observable.set(new Set<string>(
38
- (cmmc.cartEmpty || ui.buyOptionsSkuPath || isCheckout) ? ['hidden'] : []
39
- )))
40
-
41
- // a ref that is synced to ui.activeItem, but persists for CO_ANIM_DURATION longer
42
- // so ui does not jump while animating "out"
43
- const laggingActiveItemRef = useRef<LineItemRef>(new LineItemRef())
44
- const disposersRef = useRef<IReactionDisposer[]>([])
45
-
46
- useEffect(() => {
47
- disposersRef.current.push(
48
- reaction(
49
- () => (ui.activeItem),
50
- (item: LineItem | undefined) => {
51
- if (item) {
52
- laggingActiveItemRef.current.set(item)
53
- }
54
- else {
55
- setTimeout(() => { laggingActiveItemRef.current.set(undefined) }, CO_ANIM_DURATION)
56
- }
57
- },
58
- {equals: (val, prev) => (val?.sku === prev?.sku)}
59
- )
60
- )
61
-
62
- disposersRef.current.push(
63
- reaction(
64
- () => ({
65
- microOpen: !(cmmc.cartEmpty || !!ui.buyOptionsSkuPath || isCheckout),
66
- buyOpen: !!ui.buyOptionsSkuPath
67
- }),
68
- (val, prev) => {
69
-
70
- runInAction(() => {
71
- if (!val.microOpen && prev.microOpen) {
72
- animClxRef.current.add('checkout-widget-disappears')
73
- }
74
- else if (val.microOpen && !prev.microOpen) {
75
- animClxRef.current.delete('hidden')
76
- animClxRef.current.add('checkout-widget-appears')
77
- }
78
- if (!val.buyOpen && prev.buyOpen) {
79
- animClxRef.current.add('checkout-widget-appears-after-buy-drawer-closes')
80
- }
81
- else {
82
- animClxRef.current.delete('checkout-widget-appears-after-buy-drawer-closes')
83
- }
84
- })
85
-
86
- setTimeout(() => {runInAction(() => {
87
- animClxRef.current.delete('checkout-widget-appears')
88
- animClxRef.current.delete('checkout-widget-appears-after-buy-drawer-closes')
89
- if (animClxRef.current.has('checkout-widget-disappears') ) {
90
- animClxRef.current.delete('checkout-widget-disappears')
91
- animClxRef.current.add('hidden')
92
- }
93
- })}, 800)
94
- },
95
- {equals: (val, prev) => (
96
- val.microOpen === prev.microOpen
97
- &&
98
- val.buyOpen === prev.buyOpen
99
- )}
100
- )
101
- )
102
-
103
- return () => {
104
- disposersRef.current.forEach((d) => {d()})
105
- }
106
- }, [])
107
15
 
108
16
  const handleCheckout = () => {
109
17
  router.push('/checkout')
@@ -116,11 +24,10 @@ const CommerceUIComponent: React.FC = observer(() => {
116
24
  }
117
25
  }
118
26
 
119
- return (<>
27
+ return (
120
28
  <CommerceDrawer
121
29
  open={!!ui.buyOptionsSkuPath}
122
30
  setOpen={reallyOnlyCloseDrawer}
123
- modal={true}
124
31
  drawerClx={'w-full md:max-w-[550px] md:mx-auto lg:max-w-[50vw]'}
125
32
  >
126
33
  <CarouselBuyCard
@@ -133,58 +40,7 @@ const CommerceUIComponent: React.FC = observer(() => {
133
40
  selectorClx='max-w-[475px]'
134
41
  />
135
42
  </CommerceDrawer>
136
- {globalThis?.document?.body && createPortal(
137
- <div
138
- className={cn(
139
- 'min-w-[160px] sm:max-w-[320px] w-[calc(100%-72px)] ml-2 !h-10',
140
- 'z-below-modal-2 fixed bottom-[20px] left-0 right-0',
141
- 'rounded-lg bg-background',
142
- 'flex',
143
- ui.activeItem ? 'gap-2' : '',
144
- Array.from(animClxRef.current).join(' ')
145
- )}
146
- style={laggingActiveItemRef.current.item ? {} : CO_WIDGET_SHADOW_STYLE}
147
- >
148
- <div
149
- className={cn(
150
- 'flex flex-row justify-between items-center',
151
- ui.activeItem ? CO_WIDGET_W_CLX.itemInfo : 'w-0',
152
- laggingActiveItemRef.current.item ? 'px-3 border rounded-lg border-muted-3' : ''
153
- )}
154
- style={{
155
- transitionProperty: 'width',
156
- transitionTimingFunction: CO_ANIM_TIMING_FN,
157
- transitionDuration: `${CO_ANIM_DURATION}ms`
158
- }}
159
- >
160
- {laggingActiveItemRef.current.item?.img ? (
161
- <Image def={laggingActiveItemRef.current.item.img} constrainTo={DEF_IMG_CONSTRAINT} preload className='grow-0 shrink-0'/>
162
- ) : ( // placeholder so things align
163
- <div style={{height: DEF_IMG_CONSTRAINT.h, width: DEF_IMG_CONSTRAINT.w}} className='bg-level-3 grow-0 shrink-0'/>
164
- )}
165
-
166
- <div className='text-muted grow ml-1'>
167
- {laggingActiveItemRef.current.item && (<>
168
- <p className='whitespace-nowrap text-sm'>{laggingActiveItemRef.current.item.title}</p>
169
- <p className='whitespace-nowrap text-xxs' >recently added...</p>
170
- </>)}
171
- </div>
172
- </div>
173
- <CheckoutButton
174
- handleCheckout={handleCheckout}
175
- centerText={!!!ui.activeItem}
176
- variant='primary' rounded='lg'
177
- className={cn(ui.activeItem ? CO_WIDGET_W_CLX.checkout : 'w-full')}
178
- style={{
179
- transitionProperty: 'width',
180
- transitionTimingFunction: CO_ANIM_TIMING_FN,
181
- transitionDuration: `${CO_ANIM_DURATION}ms`
182
- }}
183
- />
184
- </div>,
185
- globalThis?.document?.body
186
- )}
187
- </>)
43
+ )
188
44
  })
189
45
 
190
46
  export default CommerceUIComponent
@@ -0,0 +1,13 @@
1
+ export default {
2
+ itemImgConstraint: { w: 40, h: 24 },
3
+ animDurationMs: 400,
4
+ animTimingFn: 'cubic-bezier(0.4, 0, 0.2, 1)',
5
+ compWidthClx: {
6
+ checkout: 'w-pr-40',
7
+ itemInfo: 'w-pr-60'
8
+ },
9
+ shadowStyle: {
10
+ border: '1px solid rgb(100 100 100)',
11
+ boxShadow: '2px 4px 4px -3px rgb(125 125 125 / 0.7), 4px -4px 8px -4px rgb(125 125 125 / 0.7)'
12
+ }
13
+ }
@@ -0,0 +1,86 @@
1
+ 'use client'
2
+ import React from 'react'
3
+ import { createPortal } from 'react-dom'
4
+ import { usePathname, useRouter } from 'next/navigation'
5
+ import { observer } from 'mobx-react-lite'
6
+
7
+ import { cn } from '@hanzo/ui/util'
8
+ import { Image } from '@hanzo/ui/primitives'
9
+
10
+ import { useCommerceUI } from '@hanzo/commerce'
11
+
12
+ import CheckoutButton from '../checkout-button'
13
+ import useAnimationClxSet from './use-anim-clx-set'
14
+ import useLaggingItemRef from './use-lagging-item-ref'
15
+ import CONST from './const'
16
+
17
+ const CheckoutWidget: React.FC<{
18
+ clx?: string
19
+ }> = observer(({
20
+ clx=''
21
+ }) => {
22
+
23
+ const router = useRouter()
24
+
25
+ const isCheckout = usePathname() === '/checkout'
26
+ const clxSet = useAnimationClxSet(isCheckout)
27
+
28
+ const itemRef = useCommerceUI()
29
+ const laggingRef = useLaggingItemRef(itemRef, CONST.animDurationMs)
30
+
31
+ const handleCheckout = () => { router.push('/checkout')}
32
+
33
+ return globalThis?.document?.body && createPortal(
34
+ (<div
35
+ className={cn(
36
+ 'min-w-[160px] sm:max-w-[320px] w-[calc(100%-72px)] ml-2 !h-10',
37
+ 'z-below-modal-2 fixed bottom-[20px] left-0 right-0',
38
+ 'rounded-lg bg-background',
39
+ 'flex',
40
+ itemRef.item ? 'gap-2' : '',
41
+ clxSet.asArray.join(' ')
42
+ )}
43
+ style={laggingRef.item ? {} : CONST.shadowStyle}
44
+ >
45
+ <div
46
+ className={cn(
47
+ 'flex flex-row justify-between items-center',
48
+ itemRef.item ? CONST.compWidthClx.itemInfo : 'w-0',
49
+ laggingRef.item ? 'px-3 border rounded-lg border-muted-3' : ''
50
+ )}
51
+ style={{
52
+ transitionProperty: 'width',
53
+ transitionTimingFunction: CONST.animTimingFn,
54
+ transitionDuration: `${CONST.animDurationMs}ms`
55
+ }}
56
+ >
57
+ {laggingRef.item?.img ? (
58
+ <Image def={laggingRef.item.img} constrainTo={CONST.itemImgConstraint} preload className='grow-0 shrink-0'/>
59
+ ) : ( // placeholder so things align
60
+ <div style={{height: CONST.itemImgConstraint.h, width: CONST.itemImgConstraint.w}} className='bg-level-3 grow-0 shrink-0'/>
61
+ )}
62
+
63
+ <div className='text-muted grow ml-1'>
64
+ {laggingRef.item && (<>
65
+ <p className='whitespace-nowrap text-sm'>{laggingRef.item.title}</p>
66
+ <p className='whitespace-nowrap text-xxs' >recently added...</p>
67
+ </>)}
68
+ </div>
69
+ </div>
70
+ <CheckoutButton
71
+ handleCheckout={handleCheckout}
72
+ centerText={!!!itemRef.item}
73
+ variant='primary' rounded='lg'
74
+ className={cn(itemRef.item ? CONST.compWidthClx.checkout : 'w-full')}
75
+ style={{
76
+ transitionProperty: 'width',
77
+ transitionTimingFunction: CONST.animTimingFn,
78
+ transitionDuration: `${CONST.animDurationMs}ms`
79
+ }}
80
+ />
81
+ </div>),
82
+ globalThis?.document?.body
83
+ )
84
+ })
85
+
86
+ export default CheckoutWidget
@@ -0,0 +1,48 @@
1
+ import {
2
+ action,
3
+ computed,
4
+ makeObservable,
5
+ observable
6
+ } from 'mobx'
7
+
8
+ class ObsStringSet {
9
+
10
+ private _set = observable.set(new Set<string>())
11
+
12
+ constructor(initial: string[] = []) {
13
+ initial.forEach((el) => {this._set.add(el)})
14
+ makeObservable(this, {
15
+ add: action,
16
+ remove: action,
17
+ asArray: computed
18
+ })
19
+ }
20
+
21
+ add = (v: string | string[]): void => {
22
+ if (Array.isArray(v)) {
23
+ v.forEach((el) => {this._set.add(el)})
24
+ }
25
+ else {
26
+ this._set.add(v)
27
+ }
28
+ }
29
+
30
+ remove = (v: string | string[]): void => {
31
+ if (Array.isArray(v)) {
32
+ v.forEach((el) => {this._set.delete(el)})
33
+ }
34
+ else {
35
+ this._set.delete(v)
36
+ }
37
+ }
38
+
39
+ has = (v: string): boolean => (
40
+ this._set.has(v)
41
+ )
42
+
43
+ get asArray() {
44
+ return Array.from(this._set)
45
+ }
46
+ }
47
+
48
+ export default ObsStringSet
@@ -0,0 +1,57 @@
1
+ import { useEffect, useRef } from 'react'
2
+ import { reaction, runInAction} from 'mobx'
3
+
4
+ import ObsStringSet from './obs-string-set'
5
+ import { useCommerce, useCommerceUI } from '@hanzo/commerce'
6
+
7
+ export default (isCheckout: boolean): ObsStringSet => {
8
+
9
+ const ui = useCommerceUI()
10
+ const cmmc = useCommerce()
11
+
12
+ const clxSetRef = useRef<ObsStringSet>(new ObsStringSet(
13
+ (cmmc.cartEmpty || ui.buyOptionsSkuPath || isCheckout) ? ['hidden'] : []
14
+ ))
15
+
16
+ useEffect(() => (
17
+ reaction(
18
+ () => ({
19
+ microOpen: !(cmmc.cartEmpty || !!ui.buyOptionsSkuPath || isCheckout),
20
+ buyOpen: !!ui.buyOptionsSkuPath
21
+ }),
22
+ (val, prev) => {
23
+
24
+ runInAction(() => {
25
+ if (!val.microOpen && prev.microOpen) {
26
+ clxSetRef.current.add('checkout-widget-disappears')
27
+ }
28
+ else if (val.microOpen && !prev.microOpen) {
29
+ clxSetRef.current.remove('hidden')
30
+ clxSetRef.current.add('checkout-widget-appears')
31
+ }
32
+ if (!val.buyOpen && prev.buyOpen) {
33
+ clxSetRef.current.add('checkout-widget-appears-after-buy-drawer-closes')
34
+ }
35
+ else {
36
+ clxSetRef.current.remove('checkout-widget-appears-after-buy-drawer-closes')
37
+ }
38
+ })
39
+
40
+ setTimeout(() => {runInAction(() => {
41
+ clxSetRef.current.remove(['checkout-widget-appears', 'checkout-widget-appears-after-buy-drawer-closes'])
42
+ if (clxSetRef.current.has('checkout-widget-disappears') ) {
43
+ clxSetRef.current.remove('checkout-widget-disappears')
44
+ clxSetRef.current.add('hidden')
45
+ }
46
+ })}, 800)
47
+ },
48
+ {equals: (val, prev) => (
49
+ val.microOpen === prev.microOpen
50
+ &&
51
+ val.buyOpen === prev.buyOpen
52
+ )}
53
+ )
54
+ ), [isCheckout])
55
+
56
+ return clxSetRef.current
57
+ }
@@ -0,0 +1,30 @@
1
+ import { useEffect, useRef } from 'react'
2
+ import { reaction } from 'mobx'
3
+
4
+ import type { LineItem, ObsLineItemRef } from "@hanzo/commerce/types"
5
+ import { LineItemRef } from '@hanzo/commerce'
6
+
7
+ export default (orig: ObsLineItemRef, lagMs: number): ObsLineItemRef => {
8
+
9
+ // a ref that is synced to 'orig', but persists for lagMs longer
10
+ // so ui does not jump while animating out.
11
+ // (Fascilitates for start and end states in animation)
12
+ const laggingRef = useRef<LineItemRef>(new LineItemRef())
13
+
14
+ useEffect(() => (
15
+ reaction(
16
+ () => (orig.item),
17
+ (item: LineItem | undefined) => {
18
+ if (item) {
19
+ laggingRef.current.set(item)
20
+ }
21
+ else {
22
+ setTimeout(() => { laggingRef.current.set(undefined) }, lagMs)
23
+ }
24
+ },
25
+ {equals: (val, prev) => (val?.sku === prev?.sku)}
26
+ )
27
+ ), [])
28
+
29
+ return laggingRef.current
30
+ }
@@ -9,13 +9,12 @@ export { default as Logo } from './logo'
9
9
  export { default as MiniChart } from './mini-chart'
10
10
  export { default as NotFound } from './not-found'
11
11
 
12
-
13
-
12
+ export { default as AuthListener } from './auth/auth-listener'
14
13
  export { default as BuyDrawer } from './commerce/buy-drawer'
15
- export { default as CheckoutPanel } from './commerce/checkout-panel'
16
14
  export { default as CheckoutButton } from './commerce/checkout-button'
15
+ export { default as CheckoutPanel } from './commerce/checkout-panel'
16
+ export { default as CheckoutWidget } from './commerce/checkout-widget'
17
17
  export { default as LoginPanel } from './auth/login-panel'
18
- export { default as AuthListener } from './auth/auth-listener'
19
18
  export { default as Scripts } from './scripts'
20
19
 
21
20
 
package/next/index.ts CHANGED
@@ -1 +1 @@
1
- export { default as determineDeviceMW } from './determine-device-mw'
1
+ export { default as determineDeviceMW } from './middleware/determine-device-mw'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luxfi/core",
3
- "version": "5.0.2",
3
+ "version": "5.0.4",
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/",
@@ -27,6 +27,7 @@
27
27
  },
28
28
  "exports": {
29
29
  ".": "./components/index.ts",
30
+ "./commerce": "./commerce/index.ts",
30
31
  "./root-layout": "./root-layout/index.tsx",
31
32
  "./server-actions": "./server-actions/index.ts",
32
33
  "./next": "./next/index.ts",
@@ -36,6 +37,9 @@
36
37
  "./conf": "./conf/index.ts"
37
38
  },
38
39
  "dependencies": {
40
+ "@hanzo/auth": "2.4.6",
41
+ "@hanzo/commerce": "7.0.1",
42
+ "@hanzo/ui": "3.7.0",
39
43
  "@next/third-parties": "^14.1.0",
40
44
  "cookies-next": "^4.1.1",
41
45
  "date-fns": "^3.6.0",
@@ -44,9 +48,6 @@
44
48
  "react-social-icons": "^6.4.0"
45
49
  },
46
50
  "peerDependencies": {
47
- "@hanzo/auth": "2.4.6",
48
- "@hanzo/commerce": "7.0.0",
49
- "@hanzo/ui": "3.7.0",
50
51
  "@hookform/resolvers": "^3.3.2",
51
52
  "lucide-react": "^0.344.0",
52
53
  "next": "14.1.3",
@@ -12,9 +12,10 @@ import { FacebookPixelHead } from '../next/analytics/pixel-analytics'
12
12
 
13
13
  import { AuthListener, ChatWidget, Header, Scripts } from '../components'
14
14
  import BuyDrawer from '../components/commerce/buy-drawer'
15
+ import CheckoutWidget from '../components/commerce/checkout-widget'
15
16
 
16
17
  import { selectionUISpecifiers } from '../conf'
17
- import type SiteDef from '../site-def/site-def'
18
+ import type SiteDef from '../types/site-def'
18
19
 
19
20
  import '../style/lux-global.css'
20
21
  import '../style/cart-animation.css'
@@ -58,7 +59,6 @@ const RootLayout: React.FC<PropsWithChildren & {
58
59
  }) => {
59
60
 
60
61
  const currentUser = await getUserServerSide()
61
- const usingCommerce = siteDef?.ext?.commerce && siteDef.ext.commerce.rootNode && siteDef.ext.commerce.families
62
62
 
63
63
  const Guts: React.FC = () => (<>
64
64
  {showHeader && <Header siteDef={siteDef}/>}
@@ -68,7 +68,7 @@ const RootLayout: React.FC<PropsWithChildren & {
68
68
  title='LUX'
69
69
  subtitle='AI'
70
70
  chatbotUrl='https://lux.chat/iframe'
71
- suggestedQuestions={siteDef.ext?.chatBot?.suggestedQuestions ?? []}
71
+ suggestedQuestions={siteDef.chatbot?.suggestedQuestions ?? []}
72
72
  />
73
73
  )}
74
74
  </>)
@@ -92,15 +92,16 @@ const RootLayout: React.FC<PropsWithChildren & {
92
92
  }}>
93
93
  <Scripts/>
94
94
  <AuthServiceProvider user={currentUser} conf={{} as AuthServiceConf}>
95
- {usingCommerce ? (
95
+ {siteDef?.commerce ? (
96
96
  <CommerceProvider
97
- rootNode={siteDef.ext.commerce.rootNode}
98
- families={siteDef.ext.commerce.families}
99
- options={siteDef.ext.commerce.options}
97
+ rootNode={siteDef.commerce!.rootNode}
98
+ families={siteDef.commerce!.families}
99
+ options={siteDef.commerce!.options}
100
100
  uiSpecs={selectionUISpecifiers}
101
101
  >
102
102
  <Guts />
103
103
  <BuyDrawer />
104
+ <CheckoutWidget />
104
105
  </CommerceProvider>
105
106
  ) : (
106
107
  <Guts />
package/site-def/index.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * as footer from './footer' // so footer.standard, footer.community, etc
2
2
  export { default as mainNav } from './main-nav'
3
- export type { default as SiteDef } from './site-def'
3
+ export type { SiteDef } from '../types'
package/tsconfig.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "extends": "../tsconfig.hanzo-modules.base.json",
2
+ "extends": "../tsconfig.lux.base.json",
3
3
  "include": [
4
4
  "**/*.ts",
5
5
  "**/*.tsx",
@@ -0,0 +1,7 @@
1
+ import type ChatbotSuggestQuestion from './chatbot-suggested-question'
2
+
3
+ interface ChatbotConfig {
4
+ suggestedQuestions?: ChatbotSuggestQuestion[]
5
+ }
6
+
7
+ export { type ChatbotConfig as default }
@@ -0,0 +1,7 @@
1
+ interface ChatbotSuggestedQuestion {
2
+ heading: string
3
+ message: string
4
+ icon?: string
5
+ }
6
+
7
+ export { type ChatbotSuggestedQuestion as default }
@@ -0,0 +1,10 @@
1
+ import type { ServiceOptions } from '@hanzo/commerce'
2
+ import type { CategoryNode, Family } from '@hanzo/commerce/types'
3
+
4
+ interface CommerceConfig {
5
+ families: Family[]
6
+ rootNode: CategoryNode
7
+ options?: ServiceOptions
8
+ }
9
+
10
+ export { type CommerceConfig as default }
package/types/index.ts CHANGED
@@ -1 +1,5 @@
1
- export type { ContactInfo, ContactInfoFields } from './contact-info'
1
+ export type { ContactInfo, ContactInfoFields } from './contact-info'
2
+ export type { default as SiteDef } from './site-def'
3
+ export type { default as ChatbotSuggestedQuestion } from './chatbot-suggested-question'
4
+ export type { default as ChatbotConfig } from './chatbot-config'
5
+ export type { default as CommerceConfig } from './commerce-config'
@@ -1,9 +1,15 @@
1
1
  import React from 'react'
2
+
2
3
  import type { LinkDef } from '@hanzo/ui/types'
3
4
 
5
+ import type CommerceConfig from './commerce-config'
6
+ import type ChatbotConfig from './chatbot-config'
7
+
4
8
  interface SiteDef {
9
+
5
10
  /** url of this site. All nav links in the system will show it in 'current' state */
6
11
  currentAs?: string
12
+
7
13
  nav: {
8
14
  /** common elements (will auto-select currentAs if it's provide) */
9
15
  /** optional feature element. right-most after 'elements' (any min-w is ignored) */
@@ -25,13 +31,15 @@ interface SiteDef {
25
31
  */
26
32
  footer: LinkDef[][]
27
33
 
28
- /** optional override of default 'above copyright' horizantal links */
29
- /** default (undefined or absent): @ui/sideDef/footer/legal are rendered */
30
- /** [] renders nothing above the copyright */
34
+ /**
35
+ * optional override of default 'above copyright' horizantal links
36
+ default (undefined / absent): links in side-def/footer/legal are rendered
37
+ [] renders nothing above the copyright
38
+ */
31
39
  aboveCopyright?: LinkDef[]
32
40
 
33
- /** any site-specific stuff we'd like access to (link urls, etc) */
34
- ext?: any
41
+ commerce?: CommerceConfig
42
+ chatbot?: ChatbotConfig
35
43
  }
36
44
 
37
- export { type SiteDef as default }
45
+ export { type SiteDef as default }
@@ -1,4 +0,0 @@
1
- <svg viewBox="0 0 32 40" >
2
- <path d="M27.724,27.85a3.4,3.4,0,0,0,.825-2.672l-1.8-14.4A3.405,3.405,0,0,0,23.375,7.8h-.521a5.173,5.173,0,0,0-10.32,0H3.894a1,1,0,0,0,0,2H8.929a3.316,3.316,0,0,0-.29.978l-.382,3.055a.889.889,0,0,0-.163-.033h-3a1,1,0,0,0,0,2H8.011L6.839,25.178A3.4,3.4,0,0,0,10.212,29H25.175A3.4,3.4,0,0,0,27.724,27.85ZM17.694,5a3.2,3.2,0,0,1,3.16,2.8h-6.32A3.194,3.194,0,0,1,17.694,5ZM9.163,26.526a1.384,1.384,0,0,1-.34-1.1l1.8-14.4A1.4,1.4,0,0,1,12.013,9.8h.481V13a1,1,0,0,0,2,0V9.8h6.4V13a1,1,0,0,0,2,0V9.8h.481a1.4,1.4,0,0,1,1.39,1.226l1.8,14.4A1.4,1.4,0,0,1,25.175,27H10.212A1.38,1.38,0,0,1,9.163,26.526Z"/>
3
- <path d="M7.894,11.8a1,1,0,0,0-1-1h-3a1,1,0,0,0,0,2h3A1,1,0,0,0,7.894,11.8Z"/>
4
- </svg>