@mparticle/web-braze-kit 3.0.8 → 3.0.9

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 CHANGED
@@ -8,7 +8,7 @@ You can now select what version of the Braze SDK you want to use when setting up
8
8
  Please review the [Braze Changelog](https://www.braze.com/docs/developer_guide/platform_integration_guides/web/changelog#400) and [V4 migration guide](https://github.com/braze-inc/braze-web-sdk/blob/master/UPGRADE_GUIDE.md) to learn about the differences between V3 and V4 and what changes you will need to make in your code. The most significant breaking changes are the replacement of the `appboy` class name with `braze`, in addition to the removal and renaming of several APIs.
9
9
 
10
10
  You can opt into the latest major version of the Braze Web SDK whether you implement mParticle's Web SDK using npm or our snippet/CDN.
11
- * Customers who self-host mParticle via npm - You can use @mparticle/web-braze-kit version 4.0.0 in your package.json now! This has been available since 10/15/2022.
11
+ * Customers who self-host mParticle via npm - You should add @mparticle/web-braze-kit version 4.0.0 or greater in your package.json now! You must also select `Version 4` under `Braze Web SDK Version` in the Braze connection settings.
12
12
  * Customers who load mParticle via snippet/CDN - Opting in is available via the mParticle UI in your Braze connection settings.
13
13
 
14
14
  Note that the following is only one example. Everywhere you manually call `appboy` needs to be updated similar to the below. If you are using NPM, you can skip to step 3. Please be sure to test your site fully in development prior to releasing.
@@ -19,7 +19,7 @@ Note that the following is only one example. Everywhere you manually call `appb
19
19
  window.appboy.display.destroyFeed();
20
20
  ```
21
21
 
22
- Step 2: Roll out code changes to be used before February 15, 2023:
22
+ Step 2: Roll out code changes prior to opting in to V4
23
23
  ```javascript
24
24
  if (window.appboy) {
25
25
  window.appboy.display.destroyFeed();
@@ -27,16 +27,18 @@ if (window.appboy) {
27
27
  window.braze.destroyFeed();
28
28
  }
29
29
  ```
30
- Step 3: After February 1, 2023, you can simplify your code after the mParticle Braze Web kit, which includes Braze SDK V4, has been released to our CDN:
30
+ Step 3: Opt into Version 4. Simply navigate to your connection settings and selection `Version 4` from the new Braze Web SDK Version drop down.
31
+
32
+ Step 4: After you opt in, you can simplify your code. We recommend testing and waiting at least 24 hours between opting in and removing previous instances of `appboy` and doing thorough testing of your application in a development environment to ensure everything is working:
31
33
  ```javascript
32
34
  window.braze.destroyFeed();
33
35
  ```
34
36
 
35
- Step 4: Push Notifications via service-worker.js
36
- If you use Push Notifications, we have updated the `service-worker.js` file. In our testing, Braze’s push notifications work as expected regardless of what version of the service-worker is used, but we recommend updating this file to ensure future compatibility. In your `service-worker.js` file, update the code to reference `https://static.mparticle.com/sdk/js/braze/service-worker-4.2.0.js` instead of `https://static.mparticle.com/sdk/js/braze/service-worker-3.5.0.js`. Your `service-worker.js` file should now contain:
37
+ Step 5: Push Notifications via service-worker.js
38
+ If you use Push Notifications, we have updated the `service-worker.js` file. In our testing, Braze’s push notifications work as expected regardless of what version of the service-worker is used, but we recommend updating this file to ensure future compatibility. In your `service-worker.js` file, update the code to reference `https://static.mparticle.com/sdk/js/braze/service-worker-4.2.1.js` instead of `https://static.mparticle.com/sdk/js/braze/service-worker-3.5.0.js`. Your `service-worker.js` file should now contain:
37
39
 
38
40
  ```javascript
39
- self.imports('https://static.mparticle.com/sdk/js/braze/service-worker-4.2.0.js')
41
+ self.imports('https://static.mparticle.com/sdk/js/braze/service-worker-4.2.1.js')
40
42
  ```
41
43
 
42
44
  ### Transition from @mparticle/web-appboy-kit to @mparticle/web-braze-kit
@@ -306,12 +306,13 @@ window.appboy = appboy_min;
306
306
  var name = 'Appboy',
307
307
  suffix = 'v3',
308
308
  moduleId = 28,
309
- version = '3.0.8',
309
+ version = '3.0.9',
310
310
  MessageType = {
311
311
  PageView: 3,
312
312
  PageEvent: 4,
313
313
  Commerce: 16,
314
- };
314
+ },
315
+ CommerceEventType = mParticle.CommerceEventType;
315
316
 
316
317
  var clusterMapping = {
317
318
  '01': 'sdk.iad-01.braze.com',
@@ -357,32 +358,94 @@ var constructor = function () {
357
358
  dob: 'setDateOfBirth',
358
359
  };
359
360
 
361
+ var bundleCommerceEventData = false;
362
+
363
+ // A purchase event can either log a single event with all products
364
+ // or multiple purchase events (one per product)
360
365
  function logPurchaseEvent(event) {
361
366
  var reportEvent = false;
367
+
368
+ if (bundleCommerceEventData) {
369
+ reportEvent = logSinglePurchaseEventWithProducts(event);
370
+ } else {
371
+ reportEvent = logPurchaseEventPerProduct(event);
372
+ }
373
+ return reportEvent === true;
374
+ }
375
+
376
+ function logSinglePurchaseEventWithProducts(event) {
377
+ var quantity = 1;
378
+ var eventAttributes = mergeObjects(event.EventAttributes, {
379
+ products: [],
380
+ });
381
+ var eventName = getCommerceEventName(event.EventCategory);
382
+
383
+ // All commerce events except for promotion/impression events will have a
384
+ // ProductAction property, but if this ever changes in the future, this
385
+ // check will prevent errors
386
+ if (!event.ProductAction) {
387
+ return false;
388
+ }
389
+
390
+ if (event.ProductAction.TransactionId) {
391
+ eventAttributes['Transaction Id'] =
392
+ event.ProductAction.TransactionId;
393
+ }
394
+
395
+ if (
396
+ event.ProductAction.ProductList &&
397
+ event.ProductAction.ProductList.length
398
+ ) {
399
+ eventAttributes.products = addProducts(
400
+ event.ProductAction.ProductList
401
+ );
402
+ }
403
+
404
+ kitLogger(
405
+ 'appboy.logPurchase',
406
+ eventName,
407
+ event.ProductAction.TotalAmount,
408
+ event.CurrencyCode,
409
+ quantity,
410
+ eventAttributes
411
+ );
412
+
413
+ reportEvent = appboy.logPurchase(
414
+ eventName,
415
+ event.ProductAction.TotalAmount,
416
+ event.CurrencyCode,
417
+ quantity,
418
+ eventAttributes
419
+ );
420
+ }
421
+
422
+ function logPurchaseEventPerProduct(event) {
362
423
  if (event.ProductAction.ProductList) {
363
- event.ProductAction.ProductList.forEach(function (product) {
364
- if (product.Attributes == null) {
365
- product.Attributes = {};
366
- }
367
- product.Attributes['Sku'] = product.Sku;
424
+ event.ProductAction.ProductList.forEach(function(product) {
425
+ var productName;
368
426
 
369
- var sanitizedProductName;
370
427
  if (forwarderSettings.forwardSkuAsProductName === 'True') {
371
- sanitizedProductName = getSanitizedValueForAppboy(
372
- String(product.Sku)
373
- );
428
+ productName = product.Sku;
374
429
  } else {
375
- sanitizedProductName = getSanitizedValueForAppboy(
376
- String(product.Name)
377
- );
430
+ productName = product.Name;
431
+ }
432
+ var sanitizedProductName = getSanitizedValueForAppboy(
433
+ productName
434
+ );
435
+
436
+ if (product.Attributes == null) {
437
+ product.Attributes = {};
378
438
  }
379
439
 
440
+ product.Attributes['Sku'] = product.Sku;
441
+
380
442
  var productAttributes = mergeObjects(product.Attributes, {
381
443
  'Transaction Id': event.ProductAction.TransactionId,
382
444
  });
383
445
 
384
- var sanitizedProperties =
385
- getSanitizedCustomProperties(productAttributes);
446
+ var sanitizedProperties = getSanitizedCustomProperties(
447
+ productAttributes
448
+ );
386
449
 
387
450
  if (sanitizedProperties == null) {
388
451
  return (
@@ -413,6 +476,57 @@ var constructor = function () {
413
476
  return reportEvent === true;
414
477
  }
415
478
 
479
+ function getCommerceEventName(eventType) {
480
+ const eventNamePrefix = 'eCommerce';
481
+ let eventName;
482
+
483
+ switch (eventType) {
484
+ case CommerceEventType.ProductAddToCart:
485
+ eventName = 'add_to_cart';
486
+ break;
487
+ case CommerceEventType.ProductRemoveFromCart:
488
+ eventName = 'remove_from_cart';
489
+ break;
490
+ case CommerceEventType.ProductCheckout:
491
+ eventName = 'checkout';
492
+ break;
493
+ case CommerceEventType.ProductCheckoutOption:
494
+ eventName = 'checkout_option';
495
+ break;
496
+ case CommerceEventType.ProductClick:
497
+ eventName = 'click';
498
+ break;
499
+ case CommerceEventType.ProductViewDetail:
500
+ eventName = 'view_detail';
501
+ break;
502
+ case CommerceEventType.ProductPurchase:
503
+ eventName = 'purchase';
504
+ break;
505
+ case CommerceEventType.ProductRefund:
506
+ eventName = 'refund';
507
+ break;
508
+ case CommerceEventType.ProductAddToWishlist:
509
+ eventName = 'add_to_wishlist';
510
+ break;
511
+ case CommerceEventType.ProductRemoveFromWishlist:
512
+ eventName = 'remove_from_wishlist';
513
+ break;
514
+ case CommerceEventType.PromotionView:
515
+ eventName = 'view';
516
+ break;
517
+ case CommerceEventType.PromotionClick:
518
+ eventName = 'click';
519
+ break;
520
+ case CommerceEventType.ProductImpression:
521
+ eventName = 'Impression';
522
+ break;
523
+ default:
524
+ eventName = 'unknown';
525
+ break;
526
+ }
527
+ return [eventNamePrefix, eventName].join(' - ');
528
+ }
529
+
416
530
  function logAppboyPageViewEvent(event) {
417
531
  var sanitizedEventName,
418
532
  sanitizedAttrs,
@@ -536,29 +650,8 @@ var constructor = function () {
536
650
  function processEvent(event) {
537
651
  var reportEvent = false;
538
652
 
539
- if (
540
- event.EventDataType == MessageType.Commerce &&
541
- event.EventCategory == mParticle.CommerceEventType.ProductPurchase
542
- ) {
543
- reportEvent = logPurchaseEvent(event);
544
- } else if (event.EventDataType == MessageType.Commerce) {
545
- var listOfPageEvents =
546
- mParticle.eCommerce.expandCommerceEvent(event);
547
- if (listOfPageEvents != null) {
548
- for (var i = 0; i < listOfPageEvents.length; i++) {
549
- // finalLoopResult keeps track of if any logAppBoyEvent in this loop returns true or not
550
- var finalLoopResult = false;
551
- try {
552
- reportEvent = logAppboyEvent(listOfPageEvents[i]);
553
- if (reportEvent === true) {
554
- finalLoopResult = true;
555
- }
556
- } catch (err) {
557
- return 'Error logging page event' + err.message;
558
- }
559
- }
560
- reportEvent = finalLoopResult === true;
561
- }
653
+ if (event.EventDataType == MessageType.Commerce) {
654
+ reportEvent = logCommerceEvent(event);
562
655
  } else if (event.EventDataType == MessageType.PageEvent) {
563
656
  reportEvent = logAppboyEvent(event);
564
657
  } else if (event.EventDataType == MessageType.PageView) {
@@ -578,6 +671,155 @@ var constructor = function () {
578
671
  }
579
672
  }
580
673
 
674
+ // mParticle commerce events use different appboy methods depending on if they are
675
+ // a purchase event or a non-purchase commerce event
676
+ function logCommerceEvent(event) {
677
+ if (event.EventCategory === CommerceEventType.ProductPurchase) {
678
+ reportEvent = logPurchaseEvent(event);
679
+ return reportEvent === true;
680
+ } else {
681
+ reportEvent = logNonPurchaseCommerceEvent(event);
682
+ return reportEvent === true;
683
+ }
684
+ }
685
+
686
+ // A non-purchase commerce event can either log a single event with all products
687
+ // or one event per product when the commerce event is expanded
688
+ function logNonPurchaseCommerceEvent(event) {
689
+ if (bundleCommerceEventData) {
690
+ return logNonPurchaseCommerceEventWithProducts(event);
691
+ } else {
692
+ return logExpandedNonPurchaseCommerceEvents(event);
693
+ }
694
+ }
695
+
696
+ function logNonPurchaseCommerceEventWithProducts(mpEvent) {
697
+ const commerceEventAttrs = {};
698
+ const eventName = getCommerceEventName(mpEvent.EventCategory);
699
+ try {
700
+ switch (mpEvent.EventCategory) {
701
+ case CommerceEventType.PromotionClick:
702
+ case CommerceEventType.PromotionView:
703
+ commerceEventAttrs.promotions = addPromotions(
704
+ mpEvent.PromotionAction
705
+ );
706
+ break;
707
+ case CommerceEventType.ProductImpression:
708
+ commerceEventAttrs.impressions = addImpressions(
709
+ mpEvent.ProductImpressions
710
+ );
711
+ break;
712
+ default:
713
+ if (mpEvent.ProductAction.ProductList) {
714
+ commerceEventAttrs.products = addProducts(
715
+ mpEvent.ProductAction.ProductList
716
+ );
717
+ }
718
+ var transactionId = mpEvent.ProductAction.TransactionId;
719
+ if (transactionId) {
720
+ commerceEventAttrs['Transaction Id'] = transactionId;
721
+ }
722
+ }
723
+
724
+ var sanitizedProperties = getSanitizedCustomProperties(
725
+ mpEvent.EventAttributes
726
+ );
727
+
728
+ const brazeEvent = {
729
+ EventName: eventName,
730
+ EventAttributes: mergeObjects(
731
+ commerceEventAttrs,
732
+ sanitizedProperties
733
+ ),
734
+ };
735
+
736
+ reportEvent = logAppboyEvent(brazeEvent);
737
+ return reportEvent;
738
+ } catch (err) {
739
+ return 'Error logging commerce event' + err.message;
740
+ }
741
+ }
742
+
743
+ function addPromotions(promotionAction) {
744
+ if (promotionAction && promotionAction.PromotionList) {
745
+ return promotionAction.PromotionList;
746
+ }
747
+ return [];
748
+ }
749
+
750
+ function addImpressions(productImpressions) {
751
+ if (productImpressions.length) {
752
+ return productImpressions.map(function(impression) {
753
+ return {
754
+ 'Product Impression List': impression.ProductImpressionList,
755
+ products: addProducts(impression.ProductList),
756
+ };
757
+ });
758
+ } else {
759
+ return [];
760
+ }
761
+ }
762
+
763
+ function addProducts(productList) {
764
+ const productArray = [];
765
+ if (!productList || productList.length === 0) {
766
+ return productArray;
767
+ }
768
+
769
+ productList.forEach(function(product) {
770
+ {
771
+ var sanitizedProduct = parseProduct(
772
+ getSanitizedCustomProperties(product)
773
+ );
774
+ productArray.push(sanitizedProduct);
775
+ }
776
+ });
777
+
778
+ return productArray;
779
+ }
780
+
781
+ function parseProduct(_product) {
782
+ var product = {};
783
+
784
+ for (var key in _product) {
785
+ switch (key) {
786
+ case 'Sku':
787
+ product.Id = _product[key];
788
+ break;
789
+ case 'CouponCode':
790
+ product['Coupon Code'] = _product[key];
791
+ break;
792
+ case 'TotalAmount':
793
+ product['Total Product Amount'] = _product[key];
794
+ break;
795
+ default:
796
+ product[key] = _product[key];
797
+ }
798
+ }
799
+
800
+ return product;
801
+ }
802
+
803
+ function logExpandedNonPurchaseCommerceEvents(event) {
804
+ var listOfPageEvents = mParticle.eCommerce.expandCommerceEvent(event);
805
+ if (listOfPageEvents !== null) {
806
+ for (var i = 0; i < listOfPageEvents.length; i++) {
807
+ // finalLoopResult keeps track of if any logAppBoyEvent in this loop returns true or not
808
+ var finalLoopResult = false;
809
+ try {
810
+ reportEvent = logAppboyEvent(listOfPageEvents[i]);
811
+ if (reportEvent === true) {
812
+ finalLoopResult = true;
813
+ }
814
+ } catch (err) {
815
+ return 'Error logging page event' + err.message;
816
+ }
817
+ }
818
+ reportEvent = finalLoopResult === true;
819
+ }
820
+ return reportEvent;
821
+ }
822
+
581
823
  function removeUserAttribute(key) {
582
824
  if (!(key in DefaultAttributeMethods)) {
583
825
  var sanitizedKey = getSanitizedValueForAppboy(key);
@@ -667,7 +909,7 @@ var constructor = function () {
667
909
  // The following code block is based on Braze's best practice for implementing
668
910
  // their push primer. We only modify it to include pushPrimer and register_inapp settings.
669
911
  // https://www.braze.com/docs/developer_guide/platform_integration_guides/web/push_notifications/integration/#soft-push-prompts
670
- appboy.subscribeToInAppMessage(function (inAppMessage) {
912
+ appboy.subscribeToInAppMessage(function(inAppMessage) {
671
913
  var shouldDisplay = true;
672
914
  var pushPrimer = false;
673
915
  if (inAppMessage instanceof appboy.InAppMessage) {
@@ -689,7 +931,7 @@ var constructor = function () {
689
931
  if (inAppMessage.buttons[0] != null) {
690
932
  // Prompt the user when the first button is clicked
691
933
  inAppMessage.buttons[0].subscribeToClickedEvent(
692
- function () {
934
+ function() {
693
935
  appboy.registerAppboyPushMessages();
694
936
  }
695
937
  );
@@ -737,19 +979,21 @@ var constructor = function () {
737
979
  if (!self.logger) {
738
980
  // create a logger
739
981
  self.logger = {
740
- verbose: function () {},
982
+ verbose: function() {},
741
983
  };
742
984
  }
743
985
  // eslint-disable-line no-unused-vars
744
986
  mpCustomFlags = customFlags;
745
987
  try {
746
988
  forwarderSettings = settings;
989
+ bundleCommerceEventData =
990
+ forwarderSettings.bundleCommerceEventData === 'True';
747
991
  reportingService = service;
748
992
  // 30 min is Appboy default
749
993
  options.sessionTimeoutInSeconds =
750
994
  forwarderSettings.ABKSessionTimeoutKey || 1800;
751
995
  options.sdkFlavor = 'mparticle';
752
- options.enableHtmlInAppMessages =
996
+ options.allowUserSuppliedJavascript =
753
997
  forwarderSettings.enableHtmlInAppMessages == 'True';
754
998
  options.doNotLoadFontAwesome =
755
999
  forwarderSettings.doNotLoadFontAwesome == 'True';
@@ -910,7 +1154,7 @@ var constructor = function () {
910
1154
  var nonMethodArguments = Array.prototype.slice.call(arguments, 1);
911
1155
  msg += '\n' + method + ':\n';
912
1156
 
913
- nonMethodArguments.forEach(function (arg) {
1157
+ nonMethodArguments.forEach(function(arg) {
914
1158
  if (isObject(arg) || Array.isArray(arg)) {
915
1159
  msg += JSON.stringify(arg);
916
1160
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mparticle/web-braze-kit",
3
- "version": "3.0.8",
3
+ "version": "3.0.9",
4
4
  "author": "mParticle Developers <developers@mparticle.com> (https://www.mparticle.com)",
5
5
  "description": "mParticle integration sdk for Braze",
6
6
  "main": "dist/BrazeKit.common.js",