@hanzo/commerce 7.1.33 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/components/index.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export { default as AddToCartWidget } from './add-to-cart-widget'
|
|
2
2
|
export { default as CarouselBuyCard } from './buy/carousel-buy-card'
|
|
3
3
|
|
|
4
|
-
export { default as CartAccordian } from './cart/cart-accordian'
|
|
5
4
|
export { default as CartPanel } from './cart/cart-panel'
|
|
6
5
|
|
|
7
6
|
export { default as Icons } from './Icons'
|
package/package.json
CHANGED
|
@@ -15,13 +15,13 @@ interface ActualLineItemSnapshot {
|
|
|
15
15
|
title: string
|
|
16
16
|
price: number
|
|
17
17
|
quantity: number
|
|
18
|
-
timeAdded: number
|
|
18
|
+
timeAdded: number
|
|
19
|
+
timeModified: number
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
class ActualLineItem
|
|
22
23
|
implements LineItem
|
|
23
24
|
{
|
|
24
|
-
|
|
25
25
|
qu: number = 0
|
|
26
26
|
|
|
27
27
|
id: string
|
|
@@ -39,7 +39,9 @@ class ActualLineItem
|
|
|
39
39
|
animation?: string
|
|
40
40
|
mediaTransform?: MediaTransform
|
|
41
41
|
optionImg?: ImageDef
|
|
42
|
-
|
|
42
|
+
|
|
43
|
+
timeAdded: number = 0 // Timestamp when added
|
|
44
|
+
timeModified: number = 0 // Timestamp quantity last modified (0 if not in cart)
|
|
43
45
|
|
|
44
46
|
constructor(prod: Product, snap?: ActualLineItemSnapshot) {
|
|
45
47
|
this.id = prod.id
|
|
@@ -61,11 +63,13 @@ class ActualLineItem
|
|
|
61
63
|
if (snap) {
|
|
62
64
|
this.qu = snap.quantity
|
|
63
65
|
this.timeAdded = snap.timeAdded
|
|
66
|
+
this.timeModified = snap.timeModified
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
makeObservable(this, {
|
|
67
70
|
qu: observable,
|
|
68
71
|
timeAdded: observable,
|
|
72
|
+
timeModified: observable,
|
|
69
73
|
canDecrement: computed,
|
|
70
74
|
isInCart: computed,
|
|
71
75
|
title: computed,
|
|
@@ -91,7 +95,8 @@ class ActualLineItem
|
|
|
91
95
|
title,
|
|
92
96
|
price: this.price,
|
|
93
97
|
quantity: this.qu,
|
|
94
|
-
timeAdded: this.timeAdded
|
|
98
|
+
timeAdded: this.timeAdded,
|
|
99
|
+
timeModified: this.timeModified
|
|
95
100
|
} satisfies ActualLineItemSnapshot)
|
|
96
101
|
}
|
|
97
102
|
|
|
@@ -102,6 +107,10 @@ class ActualLineItem
|
|
|
102
107
|
increment(): void {
|
|
103
108
|
if (this.qu === 0) {
|
|
104
109
|
this.timeAdded = new Date().getTime()
|
|
110
|
+
this.timeModified = this.timeAdded
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
this.timeModified = new Date().getTime()
|
|
105
114
|
}
|
|
106
115
|
this.qu++
|
|
107
116
|
}
|
|
@@ -111,6 +120,10 @@ class ActualLineItem
|
|
|
111
120
|
this.qu--
|
|
112
121
|
if (this.qu === 0) {
|
|
113
122
|
this.timeAdded = 0
|
|
123
|
+
this.timeModified = 0
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
this.timeModified = new Date().getTime()
|
|
114
127
|
}
|
|
115
128
|
}
|
|
116
129
|
}
|
|
@@ -39,7 +39,6 @@ interface StandaloneServiceSnapshot {
|
|
|
39
39
|
items: ActualLineItemSnapshot[]
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
43
42
|
class StandaloneService
|
|
44
43
|
implements CommerceService
|
|
45
44
|
{
|
|
@@ -80,16 +79,25 @@ class StandaloneService
|
|
|
80
79
|
'_selectedPaths' |
|
|
81
80
|
'_currentItem' |
|
|
82
81
|
'_currentFamily' |
|
|
83
|
-
'_promo'
|
|
82
|
+
'_promo' |
|
|
83
|
+
'_cartItems'
|
|
84
84
|
>(this, {
|
|
85
85
|
_selectedPaths : observable.deep,
|
|
86
86
|
_currentItem: observable.shallow,
|
|
87
87
|
_currentFamily: observable.shallow,
|
|
88
88
|
_promo: observable,
|
|
89
|
+
_cartItems: computed
|
|
89
90
|
})
|
|
90
91
|
|
|
91
92
|
makeObservable(this, {
|
|
93
|
+
|
|
94
|
+
setCurrentItem: action,
|
|
95
|
+
setCurrentFamily: action,
|
|
96
|
+
setAppliedPromo: action,
|
|
97
|
+
/* NOT selectPaths. It implements it's action mechanism */
|
|
98
|
+
|
|
92
99
|
cartItems: computed,
|
|
100
|
+
recentItem: computed,
|
|
93
101
|
cartQuantity: computed,
|
|
94
102
|
cartTotal: computed,
|
|
95
103
|
promoAppliedCartTotal: computed,
|
|
@@ -97,16 +105,12 @@ class StandaloneService
|
|
|
97
105
|
selectedItems: computed,
|
|
98
106
|
selectedFamilies: computed,
|
|
99
107
|
hasSelection: computed,
|
|
100
|
-
setCurrentItem: action,
|
|
101
|
-
setCurrentFamily: action,
|
|
102
108
|
currentItem: computed,
|
|
103
109
|
currentFamily: computed,
|
|
104
110
|
item: computed,
|
|
105
111
|
family: computed,
|
|
106
112
|
selectedPaths: computed,
|
|
107
113
|
appliedPromo: computed,
|
|
108
|
-
setAppliedPromo: action,
|
|
109
|
-
/* NOT selectPaths. It implements it's action mechanism */
|
|
110
114
|
})
|
|
111
115
|
}
|
|
112
116
|
|
|
@@ -270,25 +274,45 @@ class StandaloneService
|
|
|
270
274
|
async updateOrderPaymentInfo(orderId: string, paymentInfo: any): Promise<void> {
|
|
271
275
|
updateOrderPaymentInfoHelper(orderId, paymentInfo, this._options)
|
|
272
276
|
}
|
|
273
|
-
|
|
277
|
+
// Might as well use the ordered set.
|
|
274
278
|
takeSnapshot = (): StandaloneServiceSnapshot => ({
|
|
275
279
|
items : (this.cartItems as ActualLineItem[]).map((it) => (it.takeSnapshot(this)))
|
|
276
280
|
})
|
|
277
281
|
|
|
278
|
-
|
|
282
|
+
// last cartItem whose quantity was modified (undefined if cartEmpty)
|
|
283
|
+
get recentItem(): { item: LineItem, modified: number} | undefined {
|
|
284
|
+
|
|
285
|
+
if (this.cartEmpty) return undefined;
|
|
286
|
+
|
|
287
|
+
const mostRecent = this._cartItems.reduce(
|
|
288
|
+
(newest, item) => ((!newest) ? item : (
|
|
289
|
+
(item as ActualLineItem).timeModified > (newest as ActualLineItem).timeModified) ? item : newest
|
|
290
|
+
),
|
|
291
|
+
undefined as LineItem | undefined
|
|
292
|
+
)
|
|
293
|
+
return { item: mostRecent!, modified: (mostRecent! as ActualLineItem).timeModified }
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
private get _cartItems(): LineItem[] {
|
|
279
297
|
let result: LineItem[] = []
|
|
280
298
|
this._familyMap.forEach((fam) => {
|
|
281
299
|
result = [...result, ...(fam.products as LineItem[]).filter((item) => (item.isInCart))]
|
|
282
300
|
})
|
|
283
|
-
return result
|
|
301
|
+
return result
|
|
284
302
|
}
|
|
285
303
|
|
|
304
|
+
get cartItems(): LineItem[] {
|
|
305
|
+
return this._cartItems.sort((it1, it2) => ((it1 as ActualLineItem).timeAdded - (it2 as ActualLineItem).timeAdded))
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
|
|
286
310
|
get cartEmpty(): boolean {
|
|
287
|
-
return this.
|
|
311
|
+
return this._cartItems.length === 0
|
|
288
312
|
}
|
|
289
313
|
|
|
290
314
|
get cartTotal(): number {
|
|
291
|
-
return this.
|
|
315
|
+
return this._cartItems.reduce(
|
|
292
316
|
(total, item) => (total + item.price * item.quantity),
|
|
293
317
|
0
|
|
294
318
|
)
|
|
@@ -308,7 +332,7 @@ class StandaloneService
|
|
|
308
332
|
if (!this._promo.skus) {
|
|
309
333
|
return this._promoValue_unsafe(this.cartTotal)
|
|
310
334
|
}
|
|
311
|
-
let total = this.
|
|
335
|
+
let total = this._cartItems.reduce(
|
|
312
336
|
(total, item) => {
|
|
313
337
|
const itemPrice = this._promo!.skus!.includes(item.sku) ?
|
|
314
338
|
this._promoValue_unsafe(item.price)
|
|
@@ -13,6 +13,12 @@ interface CommerceService extends ObsLineItemRef, ObsFamilyRef {
|
|
|
13
13
|
/** Total of all prices x quantities of items in cart */
|
|
14
14
|
get cartTotal(): number
|
|
15
15
|
|
|
16
|
+
/** cartItem whose quantity was modified most recently
|
|
17
|
+
* item: LineItem
|
|
18
|
+
* modified: number (timestamp)
|
|
19
|
+
* (undefined if cartEmpty)
|
|
20
|
+
*/
|
|
21
|
+
get recentItem(): { item: LineItem, modified: number } | undefined
|
|
16
22
|
get promoAppliedCartTotal(): number
|
|
17
23
|
|
|
18
24
|
get cartEmpty(): boolean
|
|
@@ -1,69 +0,0 @@
|
|
|
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 { formatCurrencyValue } from '../../util'
|
|
16
|
-
import { useCommerce } from '../../context'
|
|
17
|
-
|
|
18
|
-
import CartPanel from './cart-panel'
|
|
19
|
-
|
|
20
|
-
const CartAccordian: React.FC<{
|
|
21
|
-
icon?: React.ReactNode
|
|
22
|
-
clx?: string
|
|
23
|
-
triggerClx?: string
|
|
24
|
-
panelClx?: string
|
|
25
|
-
scrollAfter: number
|
|
26
|
-
scrollHeightClx: string
|
|
27
|
-
}> = observer(({
|
|
28
|
-
icon,
|
|
29
|
-
clx='',
|
|
30
|
-
panelClx='',
|
|
31
|
-
triggerClx='',
|
|
32
|
-
scrollAfter,
|
|
33
|
-
scrollHeightClx
|
|
34
|
-
}) => {
|
|
35
|
-
const cmmc = useCommerce()
|
|
36
|
-
return (
|
|
37
|
-
<Accordion type="single" collapsible className={clx}>
|
|
38
|
-
<AccordionItem value="cart" className='w-full border-b-0'>
|
|
39
|
-
<AccordionTrigger className={'!no-underline group flex justify-between '} headerClx={ triggerClx}>
|
|
40
|
-
<div className='flex gap-0 items-center'>
|
|
41
|
-
{icon}
|
|
42
|
-
<h5 className='text-sm sm:text-xl grow'>
|
|
43
|
-
<span className='group-data-[state=open]:hidden' >Order Total:</span>
|
|
44
|
-
<span className='group-data-[state=closed]:hidden' >Your Order</span>
|
|
45
|
-
</h5>
|
|
46
|
-
</div>
|
|
47
|
-
<div className='flex gap-1 items-center'>
|
|
48
|
-
<h5 className='text-sm sm:text-xl grow truncate'>{formatCurrencyValue(cmmc.promoAppliedCartTotal)}</h5>
|
|
49
|
-
<ChevronRight className="h-5 w-5 -mr-2 shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-90" />
|
|
50
|
-
</div>
|
|
51
|
-
</AccordionTrigger>
|
|
52
|
-
<AccordionContent className='data-[state=open]:mb-4'>
|
|
53
|
-
<CartPanel
|
|
54
|
-
className={cn('w-full', panelClx)}
|
|
55
|
-
scrollAfter={scrollAfter}
|
|
56
|
-
scrollHeightClx={scrollHeightClx}
|
|
57
|
-
listClx='mt-0'
|
|
58
|
-
itemClx='mt-1'
|
|
59
|
-
totalClx='sticky px-1 pr-2 border-t -bottom-[1px] bg-background'
|
|
60
|
-
showShipping
|
|
61
|
-
showPromoCode
|
|
62
|
-
/>
|
|
63
|
-
</AccordionContent>
|
|
64
|
-
</AccordionItem>
|
|
65
|
-
</Accordion>
|
|
66
|
-
)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
export default CartAccordian
|