@liquidcommerce/elements-sdk 2.4.0 → 2.4.1
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/README.md +25 -21
- package/dist/index.esm.js +8401 -8342
- package/dist/types/core/client/client-action.service.d.ts +2 -2
- package/dist/types/core/pubsub/interfaces/cart.interface.d.ts +1 -0
- package/dist/types/core/pubsub/interfaces/checkout.interface.d.ts +44 -6
- package/dist/types/core/pubsub/interfaces/product.interface.d.ts +43 -1
- package/dist/types/core/store/interfaces/cart.interface.d.ts +1 -0
- package/dist/types/core/store/interfaces/product.interface.d.ts +18 -6
- package/dist/types/interfaces/cloud/product.interface.d.ts +2 -0
- package/docs/ACTIONS.md +49 -47
- package/docs/EVENTS.md +270 -37
- package/docs/TROUBLESHOOTING.md +1 -1
- package/package.json +4 -4
- package/umd/elements.js +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IBaseCartEventData, IBaseProductEventData,
|
|
1
|
+
import type { IBaseCartEventData, IBaseProductEventData, ICheckoutDetailsEventData } from '@/core/pubsub';
|
|
2
2
|
import { type FulfillmentType } from '@/enums';
|
|
3
3
|
import type { IAddress, ICoords } from '@/interfaces/cloud';
|
|
4
4
|
import type { IAddressData } from '@/modules/address';
|
|
@@ -42,7 +42,7 @@ export interface ICheckoutActions {
|
|
|
42
42
|
updateCustomerInfo: (params: Record<CustomerFieldName, string>) => void;
|
|
43
43
|
updateBillingInfo: (params: Record<BillingFieldName, string>) => void;
|
|
44
44
|
updateGiftInfo: (params: Record<GiftFieldName, string>) => void;
|
|
45
|
-
getDetails: () =>
|
|
45
|
+
getDetails: () => ICheckoutDetailsEventData;
|
|
46
46
|
}
|
|
47
47
|
export declare class ClientActionService {
|
|
48
48
|
private readonly pubSub;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { ICheckoutTotalAmounts } from '@/interfaces/cloud';
|
|
1
|
+
import type { ICartItemAttributes, ICheckoutTotalAmounts } from '@/interfaces/cloud';
|
|
3
2
|
export interface IBaseCheckoutEventData {
|
|
4
3
|
cartId: string;
|
|
5
4
|
}
|
|
@@ -72,13 +71,52 @@ export interface ICheckoutProductAddFailedEventData {
|
|
|
72
71
|
identifiers: string[];
|
|
73
72
|
error: string;
|
|
74
73
|
}
|
|
75
|
-
export interface
|
|
74
|
+
export interface ICheckoutItemEventData {
|
|
75
|
+
liquidId: string;
|
|
76
|
+
variantId: string;
|
|
77
|
+
cartItemId: string;
|
|
78
|
+
retailerId: string;
|
|
79
|
+
fulfillmentId: string;
|
|
80
|
+
salsifyGrouping: string;
|
|
81
|
+
name: string;
|
|
82
|
+
catPath: string;
|
|
83
|
+
volume: string;
|
|
84
|
+
uom: string;
|
|
85
|
+
proof: string;
|
|
86
|
+
abv: string;
|
|
87
|
+
containerType: string;
|
|
88
|
+
container: string;
|
|
89
|
+
size: string;
|
|
90
|
+
pack: boolean;
|
|
91
|
+
packDesc: string;
|
|
92
|
+
mainImage: string;
|
|
93
|
+
brand: string;
|
|
94
|
+
partNumber: string;
|
|
95
|
+
upc: string;
|
|
96
|
+
sku: string;
|
|
97
|
+
price: number;
|
|
98
|
+
unitPrice: number;
|
|
99
|
+
quantity: number;
|
|
100
|
+
unitTax: number;
|
|
101
|
+
bottleDeposits: number;
|
|
102
|
+
attributes: ICartItemAttributes;
|
|
103
|
+
retailerName: string;
|
|
104
|
+
expectationDetail: string;
|
|
105
|
+
}
|
|
106
|
+
export interface ICheckoutDetailsEventData {
|
|
76
107
|
cartId: string;
|
|
77
|
-
|
|
78
|
-
items: Record<string, Omit<ICheckoutItemStore, 'attributes'>>;
|
|
79
|
-
isGift: boolean;
|
|
108
|
+
acceptedAccountCreation: boolean;
|
|
80
109
|
hasAgeVerify: boolean;
|
|
110
|
+
hasSubstitutionPolicy: boolean;
|
|
111
|
+
isGift: boolean;
|
|
112
|
+
billingSameAsShipping: boolean;
|
|
113
|
+
marketingPreferences: {
|
|
114
|
+
canEmail: boolean;
|
|
115
|
+
canSms: boolean;
|
|
116
|
+
};
|
|
81
117
|
hasPromoCode: boolean;
|
|
82
118
|
hasGiftCards: boolean;
|
|
119
|
+
amounts: ICheckoutTotalAmounts;
|
|
83
120
|
itemCount: number;
|
|
121
|
+
items: Record<string, ICheckoutItemEventData>;
|
|
84
122
|
}
|
|
@@ -9,6 +9,8 @@ export interface IElementsClientIsReadyEventData {
|
|
|
9
9
|
export interface IBaseProductFulfillmentEventData {
|
|
10
10
|
price: number;
|
|
11
11
|
partNumber: string;
|
|
12
|
+
stock: number;
|
|
13
|
+
isEngravable: boolean;
|
|
12
14
|
fulfillmentId: string;
|
|
13
15
|
fulfillmentType: FulfillmentType;
|
|
14
16
|
modalities: FulfillmentType[];
|
|
@@ -17,6 +19,23 @@ export interface IBaseProductFulfillmentEventData {
|
|
|
17
19
|
retailerAddress: (IAddress & ICoords) | null;
|
|
18
20
|
retailerTimezone: string;
|
|
19
21
|
}
|
|
22
|
+
export interface IBaseProductSizeAttributesEventData {
|
|
23
|
+
engraving?: {
|
|
24
|
+
status: boolean;
|
|
25
|
+
maxLines: number;
|
|
26
|
+
maxCharsPerLine: number;
|
|
27
|
+
fee: number;
|
|
28
|
+
location: string;
|
|
29
|
+
};
|
|
30
|
+
presale?: {
|
|
31
|
+
canPurchaseOn: null | string;
|
|
32
|
+
estimatedShipBy: null | string;
|
|
33
|
+
isActive: boolean;
|
|
34
|
+
language: string;
|
|
35
|
+
presaleLimit: number;
|
|
36
|
+
price: number;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
20
39
|
export interface IBaseProductSizeEventData {
|
|
21
40
|
id: string;
|
|
22
41
|
upc: string;
|
|
@@ -29,17 +48,40 @@ export interface IBaseProductSizeEventData {
|
|
|
29
48
|
image: string;
|
|
30
49
|
uom: string;
|
|
31
50
|
volume: string;
|
|
51
|
+
attributes: IBaseProductSizeAttributesEventData;
|
|
32
52
|
shippingFulfillments: Record<string, IBaseProductFulfillmentEventData>;
|
|
33
53
|
onDemandFulfillments: Record<string, IBaseProductFulfillmentEventData>;
|
|
34
54
|
}
|
|
35
55
|
export interface IBaseProductEventData {
|
|
36
56
|
identifier: string;
|
|
57
|
+
selectedSizeId: string | null;
|
|
58
|
+
selectedFulfillmentId: string | null;
|
|
59
|
+
selectedFulfillmentType: FulfillmentType;
|
|
37
60
|
id: string;
|
|
38
61
|
name: string;
|
|
39
62
|
brand: string;
|
|
40
|
-
category: string;
|
|
41
63
|
catPath: string;
|
|
64
|
+
category: string;
|
|
42
65
|
classification: string;
|
|
66
|
+
type: string;
|
|
67
|
+
salsifyGrouping: string;
|
|
68
|
+
subType: string;
|
|
69
|
+
mainImage: string | null;
|
|
70
|
+
images: string[];
|
|
71
|
+
region: string;
|
|
72
|
+
country: string;
|
|
73
|
+
material: string;
|
|
74
|
+
abv: string;
|
|
75
|
+
proof: string;
|
|
76
|
+
age: string;
|
|
77
|
+
color: string;
|
|
78
|
+
flavor: string;
|
|
79
|
+
variety: string;
|
|
80
|
+
appellation: string;
|
|
81
|
+
vintage: string;
|
|
82
|
+
description: string;
|
|
83
|
+
htmlDescription: string;
|
|
84
|
+
tastingNotes: string;
|
|
43
85
|
priceInfo: {
|
|
44
86
|
min: number;
|
|
45
87
|
max: number;
|
|
@@ -49,20 +49,33 @@ export interface IProductStore {
|
|
|
49
49
|
id: string;
|
|
50
50
|
name: string;
|
|
51
51
|
brand: string;
|
|
52
|
-
category: string;
|
|
53
52
|
catPath: string;
|
|
53
|
+
category: string;
|
|
54
54
|
classification: string;
|
|
55
55
|
type: string;
|
|
56
|
-
subType: string;
|
|
57
56
|
salsifyGrouping: string;
|
|
57
|
+
subType: string;
|
|
58
|
+
mainImage: string | null;
|
|
59
|
+
images: string[];
|
|
60
|
+
region: string;
|
|
61
|
+
country: string;
|
|
62
|
+
material: string;
|
|
63
|
+
abv: string;
|
|
64
|
+
proof: string;
|
|
65
|
+
age: string;
|
|
66
|
+
color: string;
|
|
67
|
+
flavor: string;
|
|
68
|
+
variety: string;
|
|
69
|
+
appellation: string;
|
|
70
|
+
vintage: string;
|
|
71
|
+
description: string;
|
|
72
|
+
htmlDescription: string;
|
|
73
|
+
tastingNotes: string;
|
|
58
74
|
priceInfo?: {
|
|
59
75
|
min: number;
|
|
60
76
|
max: number;
|
|
61
77
|
avg: number;
|
|
62
78
|
};
|
|
63
|
-
description: string;
|
|
64
|
-
htmlDescription: string;
|
|
65
|
-
images: string[];
|
|
66
79
|
quantity: number;
|
|
67
80
|
sizes: Record<string, IProductSizeStore>;
|
|
68
81
|
productHasAvailability: boolean;
|
|
@@ -76,5 +89,4 @@ export interface IProductStore {
|
|
|
76
89
|
error: string | null;
|
|
77
90
|
drawer: IProductDrawerStore;
|
|
78
91
|
rerender: boolean;
|
|
79
|
-
mainImage: string | null;
|
|
80
92
|
}
|
package/docs/ACTIONS.md
CHANGED
|
@@ -65,16 +65,19 @@ Events **never expose sensitive information** like promo codes, gift card codes,
|
|
|
65
65
|
// Check product info before making decisions
|
|
66
66
|
const product = actions.product.getDetails('product-123');
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
// Use product attributes for recommendations
|
|
69
|
+
if (product.variety === 'Cabernet Sauvignon' && product.region === 'Napa Valley') {
|
|
70
|
+
showSimilarNapaWines();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Pricing and availability
|
|
74
|
+
if (product.priceInfo && product.priceInfo.avg > 100) {
|
|
70
75
|
showPremiumSupport();
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
if (product.
|
|
74
|
-
// Enable add to cart
|
|
78
|
+
if (product.sizes && Object.keys(product.sizes).length > 0) {
|
|
75
79
|
enableAddToCart();
|
|
76
80
|
} else {
|
|
77
|
-
// Show waitlist signup
|
|
78
81
|
showWaitlistSignup();
|
|
79
82
|
}
|
|
80
83
|
```
|
|
@@ -382,13 +385,11 @@ window.addEventListener('lce:actions.cart_product_add_failed', function(event) {
|
|
|
382
385
|
// See what's in the cart to make smart decisions
|
|
383
386
|
const cart = actions.cart.getDetails();
|
|
384
387
|
|
|
385
|
-
if (cart.total > 100) {
|
|
386
|
-
// Offer free shipping
|
|
388
|
+
if (cart.amounts.total > 100) {
|
|
387
389
|
showFreeShippingBanner();
|
|
388
390
|
}
|
|
389
391
|
|
|
390
|
-
if (cart.
|
|
391
|
-
// Cart is empty - show recommendations
|
|
392
|
+
if (cart.itemCount === 0) {
|
|
392
393
|
showPopularProducts();
|
|
393
394
|
}
|
|
394
395
|
```
|
|
@@ -499,7 +500,7 @@ actions.checkout.toggleCheckout();
|
|
|
499
500
|
|
|
500
501
|
// Example: Open checkout automatically for high-value carts
|
|
501
502
|
const cart = actions.cart.getDetails();
|
|
502
|
-
if (cart.total > 500) {
|
|
503
|
+
if (cart.amounts.total > 500) {
|
|
503
504
|
actions.checkout.openCheckout(); // VIP checkout experience
|
|
504
505
|
}
|
|
505
506
|
```
|
|
@@ -625,14 +626,6 @@ if (customer.billingAddress === customer.shippingAddress) {
|
|
|
625
626
|
// Get safe, non-sensitive checkout information
|
|
626
627
|
const checkout = actions.checkout.getDetails();
|
|
627
628
|
|
|
628
|
-
// Check checkout status and totals
|
|
629
|
-
console.log('Checkout total:', checkout.amounts.total);
|
|
630
|
-
console.log('Items in checkout:', checkout.itemCount);
|
|
631
|
-
console.log('Is gift order:', checkout.isGift);
|
|
632
|
-
console.log('Has age verification:', checkout.hasAgeVerify);
|
|
633
|
-
console.log('Has promo code applied:', checkout.hasPromoCode);
|
|
634
|
-
console.log('Has gift cards applied:', checkout.hasGiftCards);
|
|
635
|
-
|
|
636
629
|
// Make business decisions based on checkout state
|
|
637
630
|
if (checkout.amounts.total > 1000) {
|
|
638
631
|
// High-value order - offer white glove service
|
|
@@ -700,24 +693,28 @@ async function handleVIPCustomer(customer) {
|
|
|
700
693
|
|
|
701
694
|
### 🛍️ Scenario 2: Smart Bundle Sales
|
|
702
695
|
```javascript
|
|
703
|
-
// Automatically add complementary products
|
|
696
|
+
// Automatically add complementary products based on specific product identifiers
|
|
704
697
|
window.addEventListener('lce:actions.product_add_to_cart', async function(event) {
|
|
705
|
-
const
|
|
698
|
+
const data = event.detail.data;
|
|
699
|
+
|
|
700
|
+
// Define cross-sell rules by identifier
|
|
701
|
+
const crossSellMap = {
|
|
702
|
+
'laptop-001': ['laptop-case-123', 'wireless-mouse-456'],
|
|
703
|
+
'camera-001': ['camera-bag-789', 'sd-card-512gb']
|
|
704
|
+
};
|
|
706
705
|
|
|
707
|
-
//
|
|
708
|
-
if (
|
|
709
|
-
const
|
|
710
|
-
|
|
706
|
+
// Check if this product has recommended accessories
|
|
707
|
+
if (crossSellMap[data.identifier]) {
|
|
708
|
+
const accessories = crossSellMap[data.identifier];
|
|
709
|
+
await actions.cart.addProduct(
|
|
710
|
+
accessories.map(id => ({
|
|
711
|
+
identifier: id,
|
|
712
|
+
fulfillmentType: 'shipping',
|
|
713
|
+
quantity: 1
|
|
714
|
+
}))
|
|
715
|
+
);
|
|
711
716
|
|
|
712
|
-
|
|
713
|
-
// Add recommended accessories bundle
|
|
714
|
-
await actions.cart.addProduct([
|
|
715
|
-
{ identifier: 'laptop-case-123', fulfillmentType: 'shipping', quantity: 1 },
|
|
716
|
-
{ identifier: 'wireless-mouse-456', fulfillmentType: 'shipping', quantity: 1 }
|
|
717
|
-
]);
|
|
718
|
-
|
|
719
|
-
showMessage("We've added recommended accessories to your cart!");
|
|
720
|
-
}
|
|
717
|
+
showMessage("We've added recommended accessories to your cart!");
|
|
721
718
|
}
|
|
722
719
|
});
|
|
723
720
|
```
|
|
@@ -767,7 +764,7 @@ async function optimizeCheckout() {
|
|
|
767
764
|
];
|
|
768
765
|
|
|
769
766
|
for (const strategy of discountStrategies) {
|
|
770
|
-
if (strategy.minTotal && cart.total >= strategy.minTotal) {
|
|
767
|
+
if (strategy.minTotal && cart.amounts.total >= strategy.minTotal) {
|
|
771
768
|
try {
|
|
772
769
|
await actions.checkout.applyPromoCode(strategy.code);
|
|
773
770
|
break; // Success, stop trying
|
|
@@ -1023,15 +1020,20 @@ window.addEventListener('lce:actions.product_add_to_cart', async function(event)
|
|
|
1023
1020
|
const product = event.detail.data;
|
|
1024
1021
|
|
|
1025
1022
|
// Your business logic here
|
|
1026
|
-
if (product.
|
|
1023
|
+
if (product.priceInfo && product.priceInfo.avg > 100) {
|
|
1027
1024
|
// High-value product - offer premium support
|
|
1028
1025
|
showPremiumSupportOffer();
|
|
1029
1026
|
}
|
|
1030
1027
|
|
|
1031
|
-
// Maybe add complementary products
|
|
1032
|
-
|
|
1028
|
+
// Maybe add complementary products based on identifier
|
|
1029
|
+
const crossSellMap = {
|
|
1030
|
+
'phone-001': 'phone-case-recommended',
|
|
1031
|
+
'laptop-001': 'laptop-case-recommended'
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
if (crossSellMap[product.identifier]) {
|
|
1033
1035
|
await actions.cart.addProduct([{
|
|
1034
|
-
identifier:
|
|
1036
|
+
identifier: crossSellMap[product.identifier],
|
|
1035
1037
|
fulfillmentType: 'shipping',
|
|
1036
1038
|
quantity: 1
|
|
1037
1039
|
}]);
|
|
@@ -1054,7 +1056,7 @@ window.addEventListener('lce:actions.cart_opened', function() {
|
|
|
1054
1056
|
const cart = actions.cart.getDetails();
|
|
1055
1057
|
|
|
1056
1058
|
// If cart value is close to free shipping threshold
|
|
1057
|
-
if (cart.total > 45 && cart.total < 50) {
|
|
1059
|
+
if (cart.amounts.total > 45 && cart.amounts.total < 50) {
|
|
1058
1060
|
showFreeShippingUpsell();
|
|
1059
1061
|
}
|
|
1060
1062
|
});
|
|
@@ -1136,16 +1138,16 @@ if (timeOnPage > 60 && pageViewCount > 3) {
|
|
|
1136
1138
|
|
|
1137
1139
|
### 🛍️ **Pattern 2: Cross-Sell Automation**
|
|
1138
1140
|
```javascript
|
|
1139
|
-
// Automatic product recommendations
|
|
1141
|
+
// Automatic product recommendations based on identifier
|
|
1140
1142
|
const crossSellRules = {
|
|
1141
|
-
'laptop': ['laptop-case', 'wireless-mouse', 'usb-hub'],
|
|
1142
|
-
'phone': ['phone-case', 'screen-protector', 'wireless-charger'],
|
|
1143
|
-
'camera': ['memory-card', 'camera-bag', 'tripod']
|
|
1143
|
+
'laptop-001': ['laptop-case', 'wireless-mouse', 'usb-hub'],
|
|
1144
|
+
'phone-001': ['phone-case', 'screen-protector', 'wireless-charger'],
|
|
1145
|
+
'camera-001': ['memory-card', 'camera-bag', 'tripod']
|
|
1144
1146
|
};
|
|
1145
1147
|
|
|
1146
1148
|
window.addEventListener('lce:actions.product_add_to_cart', async function(event) {
|
|
1147
|
-
const
|
|
1148
|
-
const recommendations = crossSellRules[
|
|
1149
|
+
const data = event.detail.data;
|
|
1150
|
+
const recommendations = crossSellRules[data.identifier];
|
|
1149
1151
|
|
|
1150
1152
|
if (recommendations) {
|
|
1151
1153
|
// Add first recommendation automatically
|
|
@@ -1155,7 +1157,7 @@ window.addEventListener('lce:actions.product_add_to_cart', async function(event)
|
|
|
1155
1157
|
quantity: 1
|
|
1156
1158
|
}]);
|
|
1157
1159
|
|
|
1158
|
-
showMessage(`We've added ${recommendations[0]} - customers
|
|
1160
|
+
showMessage(`We've added ${recommendations[0]} - customers love this combo!`);
|
|
1159
1161
|
}
|
|
1160
1162
|
});
|
|
1161
1163
|
```
|
|
@@ -1174,7 +1176,7 @@ async function optimizePricing() {
|
|
|
1174
1176
|
}
|
|
1175
1177
|
|
|
1176
1178
|
// Volume discounts
|
|
1177
|
-
else if (cart.total > 200) {
|
|
1179
|
+
else if (cart.amounts.total > 200) {
|
|
1178
1180
|
await actions.cart.applyPromoCode('BULK20');
|
|
1179
1181
|
}
|
|
1180
1182
|
|