@liquidcommerce/elements-sdk 2.2.0-beta.29 → 2.2.0-beta.30

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.
@@ -1,4 +1,4 @@
1
- import type { IBaseCartEventData, IBaseProductEventData, ICheckoutDetails } from '@/core/pubsub';
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: () => ICheckoutDetails;
45
+ getDetails: () => ICheckoutDetailsEventData;
46
46
  }
47
47
  export declare class ClientActionService {
48
48
  private readonly pubSub;
@@ -55,6 +55,7 @@ export interface IBaseCartEventData {
55
55
  subtotal: number;
56
56
  total: number;
57
57
  };
58
+ itemCount: number;
58
59
  updatedAt: string;
59
60
  createdAt: string;
60
61
  }
@@ -1,5 +1,4 @@
1
- import type { ICheckoutItemStore } from '@/core/store';
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 ICheckoutDetails {
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
- amounts: ICheckoutTotalAmounts;
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;
@@ -36,6 +36,7 @@ export interface ICartTotalsStore {
36
36
  total: number;
37
37
  shippingFee: number;
38
38
  platformFee: number;
39
+ giftCardTotal: number;
39
40
  engravingFee: number;
40
41
  deliveryFee: number;
41
42
  discounts: 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
  }
@@ -153,4 +153,6 @@ export interface IProductPresale {
153
153
  estimatedShipBy: null | string;
154
154
  isActive: boolean;
155
155
  language: string;
156
+ presaleLimit: number;
157
+ price: number;
156
158
  }
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
- if (product.price > 100) {
69
- // Show premium support option
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.isAvailable) {
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.items.length === 0) {
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 product = event.detail.data;
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
- // If they bought a laptop, add accessories
708
- if (product.category === 'laptops') {
709
- const cart = actions.cart.getDetails();
710
- const hasAccessories = cart.items.some(item => item.category === 'accessories');
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
- if (!hasAccessories) {
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.price > 100) {
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
- if (product.category === 'phones') {
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: 'phone-case-recommended',
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 product = event.detail.data;
1148
- const recommendations = crossSellRules[product.category];
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 who bought ${product.name} love this combo!`);
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