@liquidcommerce/elements-sdk 2.7.0 → 2.7.2

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.
Files changed (81) hide show
  1. package/README.md +83 -2750
  2. package/dist/index.checkout.esm.js +6898 -6837
  3. package/dist/index.esm.js +11463 -10993
  4. package/dist/types/auto-initialize/shared-utils.d.ts +5 -0
  5. package/dist/types/constants/core.constant.d.ts +0 -4
  6. package/dist/types/core/base-component.service.d.ts +2 -1
  7. package/dist/types/core/pubsub/interfaces/checkout.interface.d.ts +1 -0
  8. package/dist/types/enums/core.enum.d.ts +11 -0
  9. package/dist/types/interfaces/configs/product-list.interface.d.ts +2 -2
  10. package/dist/types/interfaces/core.interface.d.ts +5 -4
  11. package/dist/types/modules/address/address-input.component.d.ts +11 -0
  12. package/dist/types/modules/checkout/components/checkout-stripe-form.component.d.ts +2 -1
  13. package/dist/types/modules/product-list/components/card-components/index.d.ts +3 -0
  14. package/dist/types/modules/product-list/components/card-components/product-badge.d.ts +8 -0
  15. package/dist/types/modules/product-list/components/card-components/product-fulfillments.d.ts +2 -0
  16. package/dist/types/modules/product-list/components/card-components/product-price-and-personalization.d.ts +13 -0
  17. package/dist/types/modules/product-list/components/card-components/product-title.d.ts +6 -0
  18. package/dist/types/modules/product-list/components/index.d.ts +1 -0
  19. package/dist/types/modules/product-list/components/product-list-engraving.component.d.ts +5 -1
  20. package/dist/types/modules/product-list/components/product-list-product-pre-cart.component.d.ts +28 -0
  21. package/dist/types/modules/product-list/components/product-list-retailers.component.d.ts +10 -2
  22. package/dist/types/modules/product-list/product-list-card.component.d.ts +0 -5
  23. package/dist/types/modules/product-list/product-list.commands.d.ts +11 -2
  24. package/dist/types/modules/product-list/product-list.interface.d.ts +1 -0
  25. package/dist/types/modules/ui-components/engraving/engraving-form.component.d.ts +11 -2
  26. package/dist/types/modules/ui-components/lce-element/lce-element.component.d.ts +2 -1
  27. package/dist/types/utils/dom-compat.d.ts +2 -0
  28. package/docs/gitbook/actions.md +964 -0
  29. package/docs/gitbook/address.md +48 -0
  30. package/docs/gitbook/cart.md +65 -0
  31. package/docs/gitbook/checkout.md +131 -0
  32. package/docs/gitbook/events.md +1765 -0
  33. package/docs/gitbook/overview.md +166 -0
  34. package/docs/gitbook/product.md +64 -0
  35. package/docs/gitbook/quick-start-guide.md +393 -0
  36. package/docs/v1/README.md +210 -0
  37. package/docs/v1/api/actions/address-actions.md +281 -0
  38. package/docs/v1/api/actions/cart-actions.md +337 -0
  39. package/docs/v1/api/actions/checkout-actions.md +387 -0
  40. package/docs/v1/api/actions/product-actions.md +115 -0
  41. package/docs/v1/api/client.md +482 -0
  42. package/docs/v1/api/configuration.md +1 -0
  43. package/docs/v1/api/injection-methods.md +247 -0
  44. package/docs/v1/api/typescript-types.md +1 -0
  45. package/docs/v1/api/ui-helpers.md +200 -0
  46. package/docs/v1/examples/advanced-patterns.md +96 -0
  47. package/docs/v1/examples/checkout-flow.md +91 -0
  48. package/docs/v1/examples/custom-theming.md +63 -0
  49. package/docs/v1/examples/multi-product-page.md +90 -0
  50. package/docs/v1/examples/simple-product-page.md +89 -0
  51. package/docs/v1/getting-started/concepts.md +507 -0
  52. package/docs/v1/getting-started/installation.md +328 -0
  53. package/docs/v1/getting-started/quick-start.md +405 -0
  54. package/docs/v1/guides/address-component.md +431 -0
  55. package/docs/v1/guides/best-practices.md +324 -0
  56. package/docs/v1/guides/cart-component.md +737 -0
  57. package/docs/v1/guides/checkout-component.md +672 -0
  58. package/docs/v1/guides/events.md +926 -0
  59. package/docs/v1/guides/product-component.md +686 -0
  60. package/docs/v1/guides/product-list-component.md +598 -0
  61. package/docs/v1/guides/theming.md +216 -0
  62. package/docs/v1/integration/angular.md +39 -0
  63. package/docs/v1/integration/laravel.md +41 -0
  64. package/docs/v1/integration/nextjs.md +60 -0
  65. package/docs/v1/integration/proxy-setup.md +89 -0
  66. package/docs/v1/integration/react.md +64 -0
  67. package/docs/v1/integration/vanilla-js.md +84 -0
  68. package/docs/v1/integration/vue.md +34 -0
  69. package/docs/v1/reference/browser-support.md +44 -0
  70. package/docs/v1/reference/error-handling.md +70 -0
  71. package/docs/v1/reference/performance.md +54 -0
  72. package/docs/v1/reference/troubleshooting.md +64 -0
  73. package/package.json +1 -1
  74. package/docs/ACTIONS.md +0 -1301
  75. package/docs/BROWSER_SUPPORT.md +0 -279
  76. package/docs/CONFIGURATION.md +0 -997
  77. package/docs/DOCUMENTATION_INDEX.md +0 -319
  78. package/docs/EVENTS.md +0 -798
  79. package/docs/PROXY.md +0 -228
  80. package/docs/THEMING.md +0 -681
  81. package/docs/TROUBLESHOOTING.md +0 -793
package/docs/ACTIONS.md DELETED
@@ -1,1301 +0,0 @@
1
- # Elements SDK Actions - Partner Control Guide
2
-
3
- > **Browser Support**: This SDK supports 2018+ browsers (Chrome 66+, Firefox 60+, Safari 12+) with comprehensive polyfills. See `docs/BROWSER_SUPPORT.md` for details.
4
-
5
- ## What Are Actions and Why Use Them?
6
-
7
- Actions let you control the LiquidCommerce components programmatically - like having a remote control for your e-commerce experience. Instead of waiting for customers to click buttons, you can make things happen automatically based on your business logic.
8
-
9
- **Business Benefits:**
10
- - **Automate User Flow**: Guide customers through the purchase process
11
- - **Custom Experiences**: Build unique checkout flows that match your brand
12
- - **Reduce Cart Abandonment**: Pre-fill information and remove friction
13
- - **Increase Conversions**: Trigger actions at the perfect moment
14
- - **Integrate with Existing Systems**: Connect to your CRM, inventory, etc.
15
-
16
- ## How It Works & Getting Feedback
17
-
18
- Actions are **fire-and-forget** methods that return `void` or `Promise<void>`. Instead of return values, **all feedback comes through events** - this is by design for security and flexibility.
19
-
20
- ```javascript
21
- // Actions are available globally
22
- const actions = window.elements.actions;
23
-
24
- // 1. Fire the action (simple, clean)
25
- await actions.cart.applyPromoCode('SAVE20');
26
-
27
- // 2. Listen for success/failure feedback via events
28
- window.addEventListener('lce:actions.cart_promo_code_applied', function(event) {
29
- const { discount, newTotal } = event.detail.data;
30
- showSuccessMessage(`🎉 Promo applied! You saved $${discount}!`);
31
- updateCartDisplay(newTotal);
32
- });
33
-
34
- window.addEventListener('lce:actions.cart_promo_code_failed', function(event) {
35
- const { error } = event.detail.data;
36
- showErrorMessage('Promo code could not be applied. Please try again.');
37
- });
38
- ```
39
-
40
- ### 🔒 **Security-First Design**
41
-
42
- Events **never expose sensitive information** like promo codes, gift card codes, or balance details that could be intercepted by malicious scripts. You get all the feedback you need without security risks.
43
-
44
- **✅ Safe Data in Events:**
45
- - Success/failure status
46
- - Discount amounts (already visible in UI)
47
- - Total amounts (already visible in UI)
48
- - Item counts and identifiers
49
- - Generic error messages
50
-
51
- **🚫 Never Exposed:**
52
- - Promo codes or gift card codes
53
- - Gift card balances or details
54
- - Specific error messages that reveal codes
55
- - Any sensitive financial information
56
-
57
- ## Your Action Toolkit
58
-
59
- ### 🛍️ Product Control (`actions.product`)
60
-
61
- **What it does**: Get information about products to make smart business decisions
62
-
63
- #### Get Product Details
64
- ```javascript
65
- // Check product info before making decisions
66
- const product = actions.product.getDetails('product-123');
67
-
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) {
75
- showPremiumSupport();
76
- }
77
-
78
- if (product.sizes && Object.keys(product.sizes).length > 0) {
79
- enableAddToCart();
80
- } else {
81
- showWaitlistSignup();
82
- }
83
- ```
84
-
85
- **Real Business Uses:**
86
- - **Dynamic Pricing**: Show different offers based on product price
87
- - **Inventory Management**: Hide out-of-stock items or show alternatives
88
- - **Personalization**: Recommend accessories based on main product
89
- - **A/B Testing**: Show different CTAs for different product categories
90
-
91
- ### 📍 Address Control (`actions.address`)
92
-
93
- **What it does**: Manage shipping addresses to reduce checkout friction
94
-
95
- #### Set Address by Google Places ID
96
- ```javascript
97
- // Set address using Google Places ID - fastest way to capture accurate addresses
98
- try {
99
- await actions.address.setAddressByPlacesId('ChIJ0SRjyK5ZwokRp1TwT8dJSv8');
100
- showMessage("Address set successfully!");
101
- } catch (error) {
102
- showMessage("Address not found. Please try again.");
103
- }
104
-
105
- // Real-world example: Let customers pick from their recent locations
106
- const recentPlacesIds = getCustomerRecentPlaces();
107
- if (recentPlacesIds.length > 0) {
108
- // Use their most recent address automatically
109
- await actions.address.setAddressByPlacesId(recentPlacesIds[0]);
110
- }
111
- ```
112
-
113
- **Find Google Places IDs**: Use the [Google Places ID Finder](https://developers.google.com/maps/documentation/places/web-service/place-id#find-id) to get Place IDs for any location.
114
-
115
- #### Set Address Manually
116
- ```javascript
117
- // Set address manually without Google Places - perfect for custom address forms
118
- try {
119
- await actions.address.setAddressManually(
120
- {
121
- one: '123 Main St',
122
- two: 'Apt 4B', // Optional apartment/suite
123
- city: 'New York',
124
- state: 'NY',
125
- zip: '10001',
126
- country: 'United States' // Optional, will be included in formatted address
127
- },
128
- {
129
- lat: 40.7505045, // Latitude coordinate
130
- long: -73.9934387 // Longitude coordinate
131
- }
132
- );
133
- showMessage("Manual address set successfully!");
134
- } catch (error) {
135
- showMessage("Invalid address or coordinates. Please check and try again.");
136
- }
137
-
138
- // Real-world example: Custom address form integration
139
- function handleCustomAddressSubmit(formData) {
140
- const addressData = {
141
- one: formData.streetAddress,
142
- two: formData.apartment || '', // Optional
143
- city: formData.city,
144
- state: formData.state,
145
- zip: formData.zipCode,
146
- country: formData.country || 'United States'
147
- };
148
-
149
- const coordinates = {
150
- lat: parseFloat(formData.latitude),
151
- long: parseFloat(formData.longitude)
152
- };
153
-
154
- // Validate coordinates before setting
155
- if (coordinates.lat >= -90 && coordinates.lat <= 90 &&
156
- coordinates.long >= -180 && coordinates.long <= 180) {
157
- await actions.address.setAddressManually(addressData, coordinates);
158
- } else {
159
- showMessage("Invalid coordinates provided");
160
- }
161
- }
162
-
163
- // Integration with geocoding services
164
- async function setAddressWithGeocoding(streetAddress, city, state, zip) {
165
- try {
166
- // Use your preferred geocoding service to get coordinates
167
- const coordinates = await geocodeAddress(`${streetAddress}, ${city}, ${state} ${zip}`);
168
-
169
- await actions.address.setAddressManually(
170
- {
171
- one: streetAddress,
172
- two: '',
173
- city: city,
174
- state: state,
175
- zip: zip,
176
- country: 'United States'
177
- },
178
- coordinates
179
- );
180
-
181
- showMessage("Address geocoded and set successfully!");
182
- } catch (error) {
183
- showMessage("Could not geocode address. Please verify the address.");
184
- }
185
- }
186
- ```
187
-
188
- **Key Features:**
189
- - **Automatic Formatting**: Generates Google Places API-formatted address strings automatically
190
- - **Empty Places ID**: Places ID is set to empty string (perfect for non-Google Places addresses)
191
- - **Flexible Input**: Works with any address structure and coordinate source
192
- - **Validation**: Built-in validation for required fields and coordinate ranges
193
- - **Same Events**: Triggers the same success/failure events as Google Places addresses
194
-
195
- #### Check Address
196
- ```javascript
197
- // See if customer has an address saved
198
- const address = actions.address.getDetails();
199
-
200
- if (address) {
201
- // Address is saved - express checkout available!
202
- showExpressCheckout();
203
- } else {
204
- // No address - guide them through address entry
205
- highlightAddressForm();
206
- }
207
- ```
208
-
209
- #### Clear Address
210
- ```javascript
211
- // Clear address (useful for guest checkout option)
212
- actions.address.clear();
213
- ```
214
-
215
- **Complete Reset Behavior:**
216
- The `actions.address.clear()` action performs a comprehensive reset of the user's address and shopping session:
217
-
218
- **What gets cleared:**
219
- - ✅ **Address Data**: All saved address information (street, city, state, zip, coordinates, Places ID)
220
- - ✅ **Cart Contents**: Complete cart reset (removes all items, totals, promo codes, retailers)
221
- - ✅ **Local Storage**: Completely removes the localStorage entry and its value
222
- - ✅ **Database**: Deletes the persisted store from the server database
223
- - ✅ **Checkout State**: Resets any pending checkout information
224
-
225
- **Why the cart is reset:**
226
- When an address is cleared, the cart must be reset because:
227
- - Cart items have location-specific pricing and availability
228
- - Fulfillment options are tied to specific addresses
229
- - Delivery fees and shipping costs depend on location
230
- - Without a valid address, cart operations would fail or show incorrect data
231
-
232
- **Events fired:**
233
- - `lce:actions.address_cleared` - Address successfully cleared
234
- - `lce:actions.cart_reset` - Cart successfully reset
235
-
236
- **Use cases:**
237
- - Guest checkout option (clear previous user's data)
238
- - Location change (start fresh with new address)
239
- - Privacy compliance (complete data removal)
240
- - Testing/development (reset to clean state)
241
-
242
- **Real Business Uses:**
243
- - **One-Click Address**: Let customers select from saved Google Places
244
- - **Custom Address Forms**: Build your own address input forms with full control
245
- - **Third-Party Integration**: Connect with non-Google geocoding services
246
- - **Legacy System Migration**: Import addresses from existing customer databases
247
- - **International Addresses**: Handle addresses that may not be in Google Places
248
- - **Location-Based Services**: Auto-detect customer location and set address
249
- - **Express Checkout**: Skip address forms for returning customers
250
- - **Shipping Calculator**: Calculate shipping costs before checkout
251
- - **Local Pickup**: Show pickup options based on their address
252
- - **Tax Calculation**: Display accurate taxes before purchase
253
-
254
- ## 📡 **Complete Action Feedback Events Reference**
255
-
256
- All actions provide feedback through events. Here are all available success/failure events:
257
-
258
- ### **Cart Action Events**
259
- ```javascript
260
- // Product management
261
- 'lce:actions.cart_product_add_success' // { itemsAdded: number, identifiers: string[] }
262
- 'lce:actions.cart_product_add_failed' // { identifiers: string[], error: string }
263
-
264
- // Promo code management
265
- 'lce:actions.cart_promo_code_applied' // { discount?: number, newTotal?: number }
266
- 'lce:actions.cart_promo_code_removed' // { newTotal?: number }
267
- 'lce:actions.cart_promo_code_failed' // { error: string }
268
- ```
269
-
270
- ### **Checkout Action Events**
271
- ```javascript
272
- // Product management
273
- 'lce:actions.checkout_product_add_success' // { itemsAdded: number, identifiers: string[], isPresale?: boolean }
274
- 'lce:actions.checkout_product_add_failed' // { identifiers: string[], error: string, isPresale?: boolean }
275
-
276
- // Promo code management
277
- 'lce:actions.checkout_promo_code_applied' // { discount?: number, newTotal?: number }
278
- 'lce:actions.checkout_promo_code_removed' // { newTotal?: number }
279
- 'lce:actions.checkout_promo_code_failed' // { error: string }
280
-
281
- // Gift card management
282
- 'lce:actions.checkout_gift_card_applied' // { newTotal?: number }
283
- 'lce:actions.checkout_gift_card_removed' // { newTotal?: number }
284
- 'lce:actions.checkout_gift_card_failed' // { error: string }
285
- ```
286
-
287
- ### **Address Action Events**
288
- ```javascript
289
- // Address management (already available)
290
- 'lce:actions.address_updated' // { googlePlacesId: string, formattedAddress: string, address: {...}, coordinates: {...} }
291
- 'lce:actions.address_failed' // { error: string, googlePlacesId?: string }
292
- 'lce:actions.address_cleared' // boolean
293
- ```
294
-
295
- ### **Event Handling Best Practices**
296
-
297
- #### **1. Set Up Listeners Before Actions**
298
- ```javascript
299
- // ✅ Good: Set up listener first
300
- window.addEventListener('lce:actions.cart_promo_code_applied', handleSuccess);
301
- await actions.cart.applyPromoCode('SAVE20');
302
-
303
- // ❌ Bad: Listener after action (might miss event)
304
- await actions.cart.applyPromoCode('SAVE20');
305
- window.addEventListener('lce:actions.cart_promo_code_applied', handleSuccess);
306
- ```
307
-
308
- #### **2. Handle Both Success and Failure**
309
- ```javascript
310
- // ✅ Always handle both outcomes
311
- window.addEventListener('lce:actions.cart_promo_code_applied', handleSuccess);
312
- window.addEventListener('lce:actions.cart_promo_code_failed', handleFailure);
313
- await actions.cart.applyPromoCode('SAVE20');
314
- ```
315
-
316
- #### **3. Use Event Data Effectively**
317
- ```javascript
318
- // ✅ Use all available event data
319
- window.addEventListener('lce:actions.cart_product_add_success', function(event) {
320
- const { itemsAdded, identifiers } = event.detail.data;
321
-
322
- // Show success message
323
- showMessage(`Added ${itemsAdded} items to cart`);
324
-
325
- // Track analytics
326
- analytics.track('Products Added', { items: identifiers, count: itemsAdded });
327
-
328
- // Update UI
329
- updateCartCount();
330
- showUpsellRecommendations(identifiers);
331
- });
332
- ```
333
-
334
- #### **4. Create Reusable Event Handlers**
335
- ```javascript
336
- // ✅ Create reusable handlers
337
- const handlePromoSuccess = (event) => {
338
- const { discount, newTotal } = event.detail.data;
339
- showSuccessMessage(`Discount applied! Saved: $${discount}`);
340
- updatePriceDisplay(newTotal);
341
- trackPromoSuccess(discount);
342
- };
343
-
344
- const handlePromoFailure = (event) => {
345
- const { error } = event.detail.data;
346
- showErrorMessage('Promo code could not be applied');
347
- trackPromoFailure();
348
- };
349
-
350
- // Use for both cart and checkout
351
- window.addEventListener('lce:actions.cart_promo_code_applied', handlePromoSuccess);
352
- window.addEventListener('lce:actions.checkout_promo_code_applied', handlePromoSuccess);
353
- window.addEventListener('lce:actions.cart_promo_code_failed', handlePromoFailure);
354
- window.addEventListener('lce:actions.checkout_promo_code_failed', handlePromoFailure);
355
- ```
356
-
357
- ### 🛒 Cart Control (`actions.cart`)
358
-
359
- **What it does**: Control the shopping cart to optimize conversions
360
-
361
- #### Show/Hide Cart
362
- ```javascript
363
- // Show cart at strategic moments
364
- actions.cart.openCart(); // Open cart
365
- actions.cart.closeCart(); // Close cart
366
- actions.cart.toggleCart(); // Toggle visibility
367
-
368
- // Example: Open cart automatically after second product add
369
- let addToCartCount = 0;
370
- window.addEventListener('lce:actions.product_add_to_cart', function() {
371
- addToCartCount++;
372
- if (addToCartCount === 2) {
373
- actions.cart.openCart(); // "Look what you've got!"
374
- }
375
- });
376
- ```
377
-
378
- #### Programmatically Add Products to Cart
379
- ```javascript
380
- // Add products directly to cart without product component
381
- await actions.cart.addProduct([
382
- {
383
- identifier: 'product-123', // Product UPC, ID, or Salsify grouping
384
- fulfillmentType: 'shipping', // or 'onDemand'
385
- quantity: 2
386
- },
387
- {
388
- identifier: 'product-456',
389
- fulfillmentType: 'onDemand',
390
- quantity: 1
391
- }
392
- ], true); // Optional: open cart after adding (default: false)
393
-
394
- // Listen for success/failure feedback
395
- window.addEventListener('lce:actions.cart_product_add_success', function(event) {
396
- const { itemsAdded, identifiers } = event.detail.data;
397
- console.log(`✅ Added ${itemsAdded} products:`, identifiers);
398
- showSuccessMessage('Products added to cart!');
399
- });
400
-
401
- window.addEventListener('lce:actions.cart_product_add_failed', function(event) {
402
- const { identifiers, error } = event.detail.data;
403
- console.log(`❌ Failed to add products:`, identifiers, error);
404
- showErrorMessage('Could not add products. Please try again.');
405
- });
406
- ```
407
-
408
- **Real Business Use**: Perfect for "Buy Now" buttons, quick add flows, bundle purchases, or any scenario where you want to add products without displaying the full product component first.
409
-
410
- #### Check Cart Contents
411
- ```javascript
412
- // See what's in the cart to make smart decisions
413
- const cart = actions.cart.getDetails();
414
-
415
- if (cart.amounts.total > 100) {
416
- showFreeShippingBanner();
417
- }
418
-
419
- if (cart.itemCount === 0) {
420
- showPopularProducts();
421
- }
422
- ```
423
-
424
- #### Add Products to Cart with Event Feedback
425
- ```javascript
426
- // Add products programmatically
427
- await actions.cart.addProduct([{
428
- identifier: 'product-123',
429
- fulfillmentType: 'shipping',
430
- quantity: 1
431
- }]);
432
-
433
- // Listen for success
434
- window.addEventListener('lce:actions.cart_product_add_success', function(event) {
435
- const { itemsAdded, identifiers } = event.detail.data;
436
- showMessage(`✅ Added ${itemsAdded} items to cart!`);
437
-
438
- // Track conversion
439
- analytics.track('Products Added to Cart', {
440
- items: identifiers,
441
- count: itemsAdded
442
- });
443
-
444
- // Maybe show related products
445
- showRelatedProducts(identifiers);
446
- });
447
-
448
- // Listen for failures
449
- window.addEventListener('lce:actions.cart_product_add_failed', function(event) {
450
- const { identifiers, error } = event.detail.data;
451
- showErrorMessage('Could not add some products. Please try again.');
452
-
453
- // Log for debugging
454
- console.error('Failed to add products:', identifiers, error);
455
-
456
- // Show alternatives
457
- showAlternativeProducts(identifiers);
458
- });
459
-
460
- // Add bundles or cross-sells
461
- await actions.cart.addProduct([
462
- { identifier: 'phone-123', fulfillmentType: 'shipping', quantity: 1 },
463
- { identifier: 'case-456', fulfillmentType: 'shipping', quantity: 1 },
464
- { identifier: 'charger-789', fulfillmentType: 'shipping', quantity: 1 }
465
- ]);
466
- ```
467
-
468
- #### Apply Discounts with Event Feedback
469
- ```javascript
470
- // Apply promo codes automatically
471
- await actions.cart.applyPromoCode('WELCOME10');
472
-
473
- // Listen for success
474
- window.addEventListener('lce:actions.cart_promo_code_applied', function(event) {
475
- const { discount, newTotal } = event.detail.data;
476
- showMessage(`Welcome discount applied! You saved $${discount}!`);
477
- updateCartDisplay(newTotal);
478
-
479
- // Track successful promo usage
480
- analytics.track('Promo Applied', { discount: discount });
481
- });
482
-
483
- // Listen for failure and try fallback
484
- window.addEventListener('lce:actions.cart_promo_code_failed', function(event) {
485
- const { error } = event.detail.data;
486
- console.log('First promo failed, trying backup promo');
487
-
488
- // Try another strategy
489
- actions.cart.applyPromoCode('FIRSTTIME');
490
- });
491
-
492
- // Remove promo code with feedback
493
- await actions.cart.removePromoCode();
494
-
495
- // Listen for removal confirmation
496
- window.addEventListener('lce:actions.cart_promo_code_removed', function(event) {
497
- const { newTotal } = event.detail.data;
498
- showMessage("Previous promo removed. Applying better discount...");
499
-
500
- // Apply better deal
501
- actions.cart.applyPromoCode('BETTER20');
502
- });
503
- ```
504
-
505
- #### Reset Cart
506
- ```javascript
507
- // Clear cart for fresh start
508
- await actions.cart.resetCart();
509
- ```
510
-
511
- **Real Business Uses:**
512
- - **Smart Cart Timing**: Open cart when customer is most likely to buy
513
- - **Bundle Sales**: Add complementary products automatically
514
- - **Discount Strategy**: Apply best available discount automatically
515
- - **Abandonment Prevention**: Show cart contents at right moment
516
-
517
- ### 💳 Checkout Control (`actions.checkout`)
518
-
519
- **What it does**: Streamline the checkout process to maximize conversions
520
-
521
- #### Control Checkout Flow
522
- ```javascript
523
- // Open checkout at the perfect moment
524
- actions.checkout.openCheckout();
525
- actions.checkout.closeCheckout();
526
- actions.checkout.toggleCheckout();
527
- actions.checkout.exitCheckout();
528
-
529
- // Example: Open checkout automatically for high-value carts
530
- const cart = actions.cart.getDetails();
531
- if (cart.amounts.total > 500) {
532
- actions.checkout.openCheckout(); // VIP checkout experience
533
- }
534
- ```
535
-
536
- #### Programmatically Add Products to Checkout
537
- ```javascript
538
- // Add products directly to checkout (bypasses cart, goes straight to checkout)
539
- await actions.checkout.addProduct([
540
- {
541
- identifier: 'product-123',
542
- fulfillmentType: 'shipping',
543
- quantity: 1
544
- }
545
- ], true); // Optional: open checkout after adding (default: false)
546
-
547
- // Listen for success/failure feedback
548
- window.addEventListener('lce:actions.checkout_product_add_success', function(event) {
549
- const { itemsAdded, identifiers } = event.detail.data;
550
- console.log(`✅ Added ${itemsAdded} products to checkout:`, identifiers);
551
- showSuccessMessage('Ready for checkout!');
552
- });
553
-
554
- window.addEventListener('lce:actions.checkout_product_add_failed', function(event) {
555
- const { identifiers, error } = event.detail.data;
556
- console.log(`❌ Failed to add products to checkout:`, identifiers, error);
557
- showErrorMessage('Could not proceed to checkout. Please try again.');
558
- });
559
- ```
560
-
561
- #### Add Presale Product to Checkout
562
- ```javascript
563
- // Add a single presale product directly to checkout (bypasses cart, always opens checkout drawer)
564
- // The method automatically validates product availability and fulfillment options
565
- await actions.checkout.addPresaleProduct({
566
- identifier: 'presale-product-123',
567
- fulfillmentType: 'shipping',
568
- quantity: 1
569
- });
570
-
571
- // Listen for success/failure feedback (same events as regular addProduct)
572
- window.addEventListener('lce:actions.checkout_product_add_success', function(event) {
573
- const { itemsAdded, identifiers, isPresale } = event.detail.data;
574
- if (isPresale) {
575
- console.log(`✅ Added ${itemsAdded} presale product to checkout:`, identifiers);
576
- showSuccessMessage('Presale item ready for checkout!');
577
- }
578
- });
579
-
580
- window.addEventListener('lce:actions.checkout_product_add_failed', function(event) {
581
- const { identifiers, error, isPresale } = event.detail.data;
582
- if (isPresale) {
583
- console.log(`❌ Failed to add presale product to checkout:`, identifiers, error);
584
- showErrorMessage('Could not proceed with presale checkout. Please try again.');
585
- }
586
- });
587
- ```
588
-
589
- **Key Features:**
590
- - **Product Availability Validation**: Automatically fetches and validates product data
591
- - **Fulfillment Type Support**: Checks if the requested fulfillment type is available
592
- - **Presale Verification**: Ensures the product is actually a presale item
593
- - **Always Opens Checkout**: Automatically opens checkout drawer after adding presale product
594
- - **Address Requirement**: Opens address input if location is not available
595
- - **Error Handling**: Comprehensive error handling with detailed feedback
596
-
597
- **Real Business Use**: Perfect for "Buy Now" buttons, one-click purchasing, express checkout flows, or any scenario where you want to skip the cart and go straight to checkout. The `addPresaleProduct` method is specifically designed for presale items that need to bypass the regular cart flow and go directly to checkout.
598
-
599
- #### Pre-fill Customer Information
600
- ```javascript
601
- // Speed up checkout by pre-filling known information
602
- actions.checkout.updateCustomerInfo({
603
- firstName: 'John',
604
- lastName: 'Doe',
605
- email: 'john@example.com',
606
- phone: '+1234567890'
607
- });
608
-
609
- // Pre-fill billing from your CRM
610
- const customerData = getCRMData(customerId);
611
- actions.checkout.updateBillingInfo({
612
- firstName: customerData.firstName,
613
- lastName: customerData.lastName,
614
- street1: customerData.address,
615
- city: customerData.city,
616
- state: customerData.state,
617
- zipCode: customerData.zip
618
- });
619
- ```
620
-
621
- #### Smart Discount Application with Event Feedback
622
- ```javascript
623
- // Apply the best available discount automatically
624
- const customer = getCurrentCustomer();
625
-
626
- // Set up event listeners first
627
- window.addEventListener('lce:actions.checkout_promo_code_applied', function(event) {
628
- const { discount, newTotal } = event.detail.data;
629
- showCheckoutSuccess(`Discount applied! You saved $${discount}`);
630
- updateCheckoutTotal(newTotal);
631
-
632
- // Track successful conversion optimization
633
- analytics.track('Checkout Discount Applied', { discount: discount });
634
- });
635
-
636
- window.addEventListener('lce:actions.checkout_promo_code_failed', function(event) {
637
- const { error } = event.detail.data;
638
- console.log('Promo code failed:', error);
639
-
640
- // Try fallback strategies or notify user
641
- showCheckoutError('Discount could not be applied');
642
- });
643
-
644
- // Apply gift card event listeners
645
- window.addEventListener('lce:actions.checkout_gift_card_applied', function(event) {
646
- const { newTotal } = event.detail.data;
647
- showCheckoutSuccess('Gift card applied to your order!');
648
- updateCheckoutTotal(newTotal);
649
- });
650
-
651
- window.addEventListener('lce:actions.checkout_gift_card_failed', function(event) {
652
- const { error } = event.detail.data;
653
- showCheckoutError('Gift card could not be applied. Please check and try again.');
654
- });
655
-
656
- // Now apply the discounts
657
- if (customer.isFirstTime) {
658
- await actions.checkout.applyPromoCode('WELCOME20');
659
- } else if (customer.isVIP) {
660
- await actions.checkout.applyPromoCode('VIP15');
661
- }
662
-
663
- // Apply gift cards automatically
664
- if (customer.hasGiftCard) {
665
- await actions.checkout.applyGiftCard(customer.giftCardCode);
666
- }
667
- ```
668
-
669
- #### Optimize Checkout Options
670
- ```javascript
671
- // Smart defaults based on customer behavior
672
- if (customer.prefersGifts) {
673
- await actions.checkout.toggleIsGift(true);
674
- }
675
-
676
- // Auto-enable marketing for engaged customers
677
- if (customer.engagementScore > 8) {
678
- actions.checkout.toggleMarketingPreferences('canEmail', true);
679
- actions.checkout.toggleMarketingPreferences('canSms', true);
680
- }
681
-
682
- // Smart billing address handling
683
- if (customer.billingAddress === customer.shippingAddress) {
684
- await actions.checkout.toggleBillingSameAsShipping(true);
685
- }
686
- ```
687
-
688
- #### Get Checkout Details
689
- ```javascript
690
- // Get safe, non-sensitive checkout information
691
- const checkout = actions.checkout.getDetails();
692
-
693
- // Make business decisions based on checkout state
694
- if (checkout.amounts.total > 1000) {
695
- // High-value order - offer white glove service
696
- showWhiteGloveService();
697
- }
698
-
699
- if (checkout.itemCount > 5) {
700
- // Large order - offer bulk discount
701
- await actions.checkout.applyPromoCode('BULK15');
702
- }
703
-
704
- if (checkout.isGift && checkout.hasAgeVerify) {
705
- // Gift order with age verification - show age verification requirements
706
- showAgeVerificationNotice();
707
- }
708
-
709
- if (!checkout.hasPromoCode) {
710
- // No promo code applied - suggest best available discount
711
- suggestBestPromoCode(checkout.amounts.total);
712
- }
713
-
714
- if (checkout.hasGiftCards && checkout.amounts.total < 50) {
715
- // Gift cards applied but low total - suggest adding more items
716
- showUpsellSuggestions();
717
- }
718
-
719
- // Available checkout details (all non-sensitive):
720
- // - amounts: { total, subtotal, shipping, discounts, tax, etc. }
721
- // - items: { [itemId]: { name, price, quantity, brand, etc. } }
722
- // - isGift: boolean, hasAgeVerify: boolean
723
- // - hasPromoCode: boolean, hasGiftCards: boolean
724
- // - itemCount: number
725
- ```
726
-
727
- **Real Business Uses:**
728
- - **Reduce Checkout Time**: Pre-fill known customer information
729
- - **Maximize Discounts**: Apply best available offer automatically
730
- - **VIP Experience**: Different checkout flow for high-value customers
731
- - **Gift Optimization**: Auto-enable gift options for gift buyers
732
-
733
- ## Real-World Business Scenarios
734
-
735
- ### 🎯 Scenario 1: VIP Customer Experience
736
- ```javascript
737
- // Detect VIP customers and give them special treatment
738
- async function handleVIPCustomer(customer) {
739
- if (customer.totalSpent > 5000) {
740
- // Pre-fill everything for express checkout
741
- actions.checkout.updateCustomerInfo(customer.profile);
742
- actions.checkout.updateBillingInfo(customer.billingAddress);
743
-
744
- // Apply VIP discount automatically
745
- await actions.checkout.applyPromoCode('VIP20');
746
-
747
- // Enable premium features
748
- actions.checkout.toggleMarketingPreferences('canEmail', true);
749
-
750
- // Open checkout immediately - no cart friction
751
- actions.checkout.openCheckout();
752
-
753
- showVIPMessage("Welcome back! Your VIP checkout is ready.");
754
- }
755
- }
756
- ```
757
-
758
- ### 🛍️ Scenario 2: Smart Bundle Sales
759
- ```javascript
760
- // Automatically add complementary products based on specific product identifiers
761
- window.addEventListener('lce:actions.product_add_to_cart', async function(event) {
762
- const data = event.detail.data;
763
-
764
- // Define cross-sell rules by identifier
765
- const crossSellMap = {
766
- 'laptop-001': ['laptop-case-123', 'wireless-mouse-456'],
767
- 'camera-001': ['camera-bag-789', 'sd-card-512gb']
768
- };
769
-
770
- // Check if this product has recommended accessories
771
- if (crossSellMap[data.identifier]) {
772
- const accessories = crossSellMap[data.identifier];
773
- await actions.cart.addProduct(
774
- accessories.map(id => ({
775
- identifier: id,
776
- fulfillmentType: 'shipping',
777
- quantity: 1
778
- }))
779
- );
780
-
781
- showMessage("We've added recommended accessories to your cart!");
782
- }
783
- });
784
- ```
785
-
786
- ### 📱 Scenario 3: Mobile-First Quick Checkout
787
- ```javascript
788
- // Streamlined mobile experience
789
- function mobileQuickCheckout() {
790
- if (isMobileDevice()) {
791
- // Get customer data from their last purchase
792
- const lastOrder = getLastOrder();
793
-
794
- if (lastOrder) {
795
- // Pre-fill everything
796
- actions.checkout.updateCustomerInfo(lastOrder.customer);
797
- actions.checkout.updateBillingInfo(lastOrder.billing);
798
-
799
- // Skip cart, go straight to checkout
800
- actions.checkout.openCheckout();
801
-
802
- showMessage("Express checkout ready! Same info as last time.");
803
- }
804
- }
805
- }
806
-
807
- // Trigger on Add to Cart for mobile users
808
- window.addEventListener('lce:actions.product_add_to_cart', function() {
809
- if (isMobileDevice() && isReturningCustomer()) {
810
- mobileQuickCheckout();
811
- }
812
- });
813
- ```
814
-
815
- ### 💰 Scenario 4: Dynamic Pricing & Promotions
816
- ```javascript
817
- // Apply the best available discount
818
- async function optimizeCheckout() {
819
- const cart = actions.cart.getDetails();
820
- const customer = getCurrentCustomer();
821
-
822
- // Try different discount strategies
823
- const discountStrategies = [
824
- { code: 'BULK25', minTotal: 200 },
825
- { code: 'RETURNING15', condition: customer.orderCount > 1 },
826
- { code: 'FIRSTTIME10', condition: customer.orderCount === 0 },
827
- { code: 'SEASONAL20', condition: isHolidaySeason() }
828
- ];
829
-
830
- for (const strategy of discountStrategies) {
831
- if (strategy.minTotal && cart.amounts.total >= strategy.minTotal) {
832
- try {
833
- await actions.checkout.applyPromoCode(strategy.code);
834
- break; // Success, stop trying
835
- } catch (error) {
836
- continue; // Try next strategy
837
- }
838
- } else if (strategy.condition) {
839
- try {
840
- await actions.checkout.applyPromoCode(strategy.code);
841
- break;
842
- } catch (error) {
843
- continue;
844
- }
845
- }
846
- }
847
- }
848
- ```
849
-
850
- ### 🎁 Scenario 5: Holiday Gift Flow
851
- ```javascript
852
- // Optimize for gift purchases during holidays
853
- async function holidayGiftOptimization() {
854
- if (isHolidaySeason()) {
855
- // Auto-enable gift features
856
- actions.checkout.toggleIsGift(true);
857
-
858
- // Pre-populate gift message templates
859
- const giftMessages = [
860
- "Happy Holidays!",
861
- "Merry Christmas!",
862
- "With love and best wishes"
863
- ];
864
-
865
- showGiftMessageSuggestions(giftMessages);
866
-
867
- // Suggest gift wrapping
868
- showGiftWrappingOption();
869
-
870
- // Apply holiday shipping discount
871
- await actions.checkout.applyPromoCode('FREEHOLIDAYSHIP');
872
- }
873
- }
874
-
875
- // Trigger during checkout
876
- window.addEventListener('lce:actions.checkout_opened', holidayGiftOptimization);
877
- ```
878
-
879
- ### 📍 Scenario 6: Smart Address Auto-Complete
880
- ```javascript
881
- // Use Google Places to streamline address entry
882
- async function smartAddressFlow() {
883
- const customer = getCurrentCustomer();
884
-
885
- // For returning customers, use their recent addresses
886
- if (customer.recentPlacesIds && customer.recentPlacesIds.length > 0) {
887
- try {
888
- // Auto-set their most recent address
889
- await actions.address.setAddressByPlacesId(customer.recentPlacesIds[0]);
890
-
891
- showMessage("We've set your address to your recent location. Change it if needed!");
892
-
893
- // Show other recent addresses as quick options
894
- showRecentAddressOptions(customer.recentPlacesIds.slice(1, 4));
895
-
896
- } catch (error) {
897
- // Fallback to manual entry
898
- showAddressForm();
899
- }
900
- }
901
-
902
- // For location-aware features
903
- if (customer.hasLocationPermission) {
904
- const nearbyBusinesses = await getNearbyBusinessPlaces();
905
-
906
- // If they're near a business location, suggest it
907
- if (nearbyBusinesses.length > 0) {
908
- showMessage("We found you're near our store location. Use it for pickup?");
909
-
910
- document.getElementById('use-store-address').onclick = async () => {
911
- await actions.address.setAddressByPlacesId(nearbyBusinesses[0].placeId);
912
- showMessage("Store pickup address set!");
913
- };
914
- }
915
- }
916
- }
917
-
918
- // Use when address is updated
919
- smartAddressFlow();
920
-
921
- // Quick address selection from saved places
922
- async function useQuickAddress(placeId, displayName) {
923
- try {
924
- await actions.address.setAddressByPlacesId(placeId);
925
- showMessage(`Address set to ${displayName}`);
926
-
927
- // Automatically proceed to shipping options
928
- showShippingOptionsForAddress();
929
-
930
- } catch (error) {
931
- showMessage("That address is no longer available. Please select another.");
932
- }
933
- }
934
- ```
935
-
936
- ### 🏢 Scenario 7: Custom Address Form Integration
937
- ```javascript
938
- // Integrate with your own address forms and geocoding services
939
- async function customAddressFormFlow() {
940
- const customer = getCurrentCustomer();
941
-
942
- // If customer has saved addresses in your database (not Google Places)
943
- if (customer.savedAddresses && customer.savedAddresses.length > 0) {
944
- showSavedAddressOptions(customer.savedAddresses);
945
- }
946
-
947
- // Handle custom form submission
948
- document.getElementById('custom-address-form').addEventListener('submit', async (event) => {
949
- event.preventDefault();
950
-
951
- const formData = new FormData(event.target);
952
- const addressData = {
953
- one: formData.get('street'),
954
- two: formData.get('apartment') || '',
955
- city: formData.get('city'),
956
- state: formData.get('state'),
957
- zip: formData.get('zip'),
958
- country: formData.get('country') || 'United States'
959
- };
960
-
961
- try {
962
- // Use your geocoding service to get coordinates
963
- const coordinates = await yourGeocodingService.geocode(
964
- `${addressData.one}, ${addressData.city}, ${addressData.state} ${addressData.zip}`
965
- );
966
-
967
- // Set the address manually
968
- await actions.address.setAddressManually(addressData, {
969
- lat: coordinates.latitude,
970
- long: coordinates.longitude
971
- });
972
-
973
- showMessage("Your address has been set successfully!");
974
-
975
- // Save to your database for future use
976
- saveCustomerAddress(customer.id, addressData, coordinates);
977
-
978
- } catch (geocodeError) {
979
- showError("Could not find coordinates for this address. Please verify and try again.");
980
- }
981
- });
982
-
983
- // Handle saved address selection
984
- async function useSavedAddress(savedAddress) {
985
- try {
986
- await actions.address.setAddressManually(
987
- {
988
- one: savedAddress.street,
989
- two: savedAddress.apartment || '',
990
- city: savedAddress.city,
991
- state: savedAddress.state,
992
- zip: savedAddress.zip,
993
- country: savedAddress.country || 'United States'
994
- },
995
- {
996
- lat: savedAddress.coordinates.lat,
997
- long: savedAddress.coordinates.long
998
- }
999
- );
1000
-
1001
- showMessage(`Address set to your saved location: ${savedAddress.nickname}`);
1002
-
1003
- } catch (error) {
1004
- showError("There was an issue with your saved address. Please try entering it again.");
1005
- }
1006
- }
1007
- }
1008
-
1009
- // Import addresses from legacy system
1010
- async function importLegacyAddresses() {
1011
- const legacyAddresses = await getLegacyCustomerAddresses();
1012
-
1013
- for (const address of legacyAddresses) {
1014
- try {
1015
- // Convert legacy format to Elements format
1016
- const elementsAddress = {
1017
- one: address.address_line_1,
1018
- two: address.address_line_2 || '',
1019
- city: address.city_name,
1020
- state: address.state_code,
1021
- zip: address.postal_code,
1022
- country: address.country_name || 'United States'
1023
- };
1024
-
1025
- const coordinates = {
1026
- lat: address.latitude,
1027
- long: address.longitude
1028
- };
1029
-
1030
- // Set address in Elements system
1031
- await actions.address.setAddressManually(elementsAddress, coordinates);
1032
-
1033
- console.log(`Successfully imported address for customer ${address.customer_id}`);
1034
-
1035
- } catch (error) {
1036
- console.error(`Failed to import address for customer ${address.customer_id}:`, error);
1037
- }
1038
- }
1039
- }
1040
-
1041
- // Handle international addresses that might not be in Google Places
1042
- async function handleInternationalAddress(internationalAddressData) {
1043
- try {
1044
- // Use an international geocoding service
1045
- const coordinates = await internationalGeocodingService.geocode(
1046
- internationalAddressData.fullAddress,
1047
- internationalAddressData.country
1048
- );
1049
-
1050
- await actions.address.setAddressManually(
1051
- {
1052
- one: internationalAddressData.addressLine1,
1053
- two: internationalAddressData.addressLine2 || '',
1054
- city: internationalAddressData.city,
1055
- state: internationalAddressData.region, // Province, state, etc.
1056
- zip: internationalAddressData.postalCode,
1057
- country: internationalAddressData.country
1058
- },
1059
- coordinates
1060
- );
1061
-
1062
- showMessage("International address set successfully!");
1063
-
1064
- } catch (error) {
1065
- showError("Could not process this international address. Please contact support.");
1066
- }
1067
- }
1068
- ```
1069
-
1070
- ## Implementation Strategy
1071
-
1072
- ### 🚀 Quick Start (5-Minute Setup)
1073
-
1074
- **Step 1: Choose Your Goal**
1075
- - Increase conversions? → Focus on cart and checkout actions
1076
- - Reduce abandonment? → Use pre-filling and automation
1077
- - Boost sales? → Implement bundle and upsell logic
1078
- - Improve UX? → Create smart defaults and express flows
1079
-
1080
- **Step 2: Start Simple**
1081
- ```javascript
1082
- // Copy this basic template and customize
1083
- window.addEventListener('lce:actions.product_add_to_cart', async function(event) {
1084
- const product = event.detail.data;
1085
-
1086
- // Your business logic here
1087
- if (product.priceInfo && product.priceInfo.avg > 100) {
1088
- // High-value product - offer premium support
1089
- showPremiumSupportOffer();
1090
- }
1091
-
1092
- // Maybe add complementary products based on identifier
1093
- const crossSellMap = {
1094
- 'phone-001': 'phone-case-recommended',
1095
- 'laptop-001': 'laptop-case-recommended'
1096
- };
1097
-
1098
- if (crossSellMap[product.identifier]) {
1099
- await actions.cart.addProduct([{
1100
- identifier: crossSellMap[product.identifier],
1101
- fulfillmentType: 'shipping',
1102
- quantity: 1
1103
- }]);
1104
- }
1105
- });
1106
- ```
1107
-
1108
- **Step 3: Test & Iterate**
1109
- 1. Add one action at a time
1110
- 2. Test with real user flows
1111
- 3. Monitor conversion impact
1112
- 4. Adjust based on results
1113
-
1114
- ### 💡 Pro Implementation Tips
1115
-
1116
- #### Combine Actions with Events
1117
- ```javascript
1118
- // Listen for events, respond with actions
1119
- window.addEventListener('lce:actions.cart_opened', function() {
1120
- const cart = actions.cart.getDetails();
1121
-
1122
- // If cart value is close to free shipping threshold
1123
- if (cart.amounts.total > 45 && cart.amounts.total < 50) {
1124
- showFreeShippingUpsell();
1125
- }
1126
- });
1127
-
1128
- // Pre-fill checkout for VIP customers
1129
- window.addEventListener('lce:actions.checkout_opened', async function() {
1130
- const customer = getCurrentCustomer();
1131
-
1132
- if (customer.isVIP) {
1133
- actions.checkout.updateCustomerInfo(customer.profile);
1134
- await actions.checkout.applyPromoCode('VIP20');
1135
- }
1136
- });
1137
- ```
1138
-
1139
- #### Chain Actions for Workflows
1140
- ```javascript
1141
- // Create complete automated flows
1142
- async function expressCheckoutFlow(productId, customerId) {
1143
- // 1. Add product to cart
1144
- await actions.cart.addProduct([{
1145
- identifier: productId,
1146
- fulfillmentType: 'shipping',
1147
- quantity: 1
1148
- }]);
1149
-
1150
- // 2. Pre-fill customer data
1151
- const customer = getCustomerData(customerId);
1152
- actions.checkout.updateCustomerInfo(customer);
1153
-
1154
- // 3. Apply best discount
1155
- await actions.checkout.applyPromoCode(getBestDiscountFor(customer));
1156
-
1157
- // 4. Open checkout
1158
- actions.checkout.openCheckout();
1159
-
1160
- showMessage("Express checkout ready! Review and complete your order.");
1161
- }
1162
- ```
1163
-
1164
- #### Smart Error Handling
1165
- ```javascript
1166
- // Graceful degradation
1167
- async function smartAddToCart(productId) {
1168
- try {
1169
- await actions.cart.addProduct([{
1170
- identifier: productId,
1171
- fulfillmentType: 'shipping',
1172
- quantity: 1
1173
- }]);
1174
-
1175
- showSuccessMessage("Added to cart!");
1176
- } catch (error) {
1177
- // Fallback - maybe the product is out of stock
1178
- showMessage("This item isn't available, but here are similar options:");
1179
- showAlternativeProducts(productId);
1180
- }
1181
- }
1182
- ```
1183
-
1184
- ## Common Integration Patterns
1185
-
1186
- ### 🎯 **Pattern 1: Behavioral Triggers**
1187
- ```javascript
1188
- // Trigger actions based on customer behavior
1189
- let pageViewCount = 0;
1190
- let timeOnPage = 0;
1191
-
1192
- // Track engagement
1193
- setInterval(() => timeOnPage++, 1000);
1194
-
1195
- // Act based on engagement
1196
- if (timeOnPage > 60 && pageViewCount > 3) {
1197
- // Engaged user - show special offer
1198
- await actions.cart.applyPromoCode('ENGAGED15');
1199
- showSpecialOffer();
1200
- }
1201
- ```
1202
-
1203
- ### 🛍️ **Pattern 2: Cross-Sell Automation**
1204
- ```javascript
1205
- // Automatic product recommendations based on identifier
1206
- const crossSellRules = {
1207
- 'laptop-001': ['laptop-case', 'wireless-mouse', 'usb-hub'],
1208
- 'phone-001': ['phone-case', 'screen-protector', 'wireless-charger'],
1209
- 'camera-001': ['memory-card', 'camera-bag', 'tripod']
1210
- };
1211
-
1212
- window.addEventListener('lce:actions.product_add_to_cart', async function(event) {
1213
- const data = event.detail.data;
1214
- const recommendations = crossSellRules[data.identifier];
1215
-
1216
- if (recommendations) {
1217
- // Add first recommendation automatically
1218
- await actions.cart.addProduct([{
1219
- identifier: recommendations[0],
1220
- fulfillmentType: 'shipping',
1221
- quantity: 1
1222
- }]);
1223
-
1224
- showMessage(`We've added ${recommendations[0]} - customers love this combo!`);
1225
- }
1226
- });
1227
- ```
1228
-
1229
- ### 💰 **Pattern 3: Dynamic Pricing**
1230
- ```javascript
1231
- // Apply best available discount automatically
1232
- async function optimizePricing() {
1233
- const cart = actions.cart.getDetails();
1234
- const customer = getCurrentCustomer();
1235
- const now = new Date();
1236
-
1237
- // Time-based discounts
1238
- if (now.getHours() < 10) {
1239
- await actions.cart.applyPromoCode('EARLYBIRD10');
1240
- }
1241
-
1242
- // Volume discounts
1243
- else if (cart.amounts.total > 200) {
1244
- await actions.cart.applyPromoCode('BULK20');
1245
- }
1246
-
1247
- // Customer-specific discounts
1248
- else if (customer.orderCount === 0) {
1249
- await actions.cart.applyPromoCode('WELCOME15');
1250
- }
1251
-
1252
- // Seasonal discounts
1253
- else if (isBlackFriday()) {
1254
- await actions.cart.applyPromoCode('BLACKFRIDAY25');
1255
- }
1256
- }
1257
- ```
1258
-
1259
- ## Business ROI Tracking
1260
-
1261
- Track the impact of your action implementations:
1262
-
1263
- ```javascript
1264
- // Track business metrics
1265
- const metrics = {
1266
- automatedDiscountsApplied: 0,
1267
- bundleSalesCreated: 0,
1268
- expressCheckoutsCompleted: 0,
1269
- cartAbandonmentsPrevented: 0
1270
- };
1271
-
1272
- // Track when actions create business value
1273
- window.addEventListener('lce:actions.cart_updated', function() {
1274
- if (wasDiscountAppliedAutomatically()) {
1275
- metrics.automatedDiscountsApplied++;
1276
- }
1277
- });
1278
-
1279
- window.addEventListener('lce:actions.checkout_submit_completed', function() {
1280
- if (wasExpressCheckout()) {
1281
- metrics.expressCheckoutsCompleted++;
1282
- }
1283
- });
1284
-
1285
- // Send metrics to your analytics
1286
- setInterval(() => {
1287
- sendBusinessMetrics(metrics);
1288
- }, 60000); // Every minute
1289
- ```
1290
-
1291
- ## Getting Started Today
1292
-
1293
- 1. **Pick ONE scenario** from the examples above that matches your biggest business need
1294
- 2. **Copy the code** and customize it for your products/customers
1295
- 3. **Test it** with a small group first
1296
- 4. **Measure the impact** on your conversion rates
1297
- 5. **Scale up** what works, iterate on what doesn't
1298
-
1299
- **Remember**: The power is in combining the right actions with the right business logic for YOUR specific use case. Start simple, then build more sophisticated flows as you see results!
1300
-
1301
- Need help implementing? The actions work automatically once LiquidCommerce Elements are installed - just add your business logic and watch conversions improve!