@blotoutio/providers-blotout-wallet-sdk 0.43.0 → 0.44.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.
Files changed (4) hide show
  1. package/index.cjs.js +138 -5
  2. package/index.js +138 -5
  3. package/index.mjs +138 -5
  4. package/package.json +1 -1
package/index.cjs.js CHANGED
@@ -1,5 +1,72 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ * Returns whether A contains the entirety of B (A superset of B)
5
+ *
6
+ * A ⊇ B
7
+ */
8
+ const isSuperset = (a, b) => {
9
+ for (const item of b) {
10
+ if (!a.has(item)) {
11
+ return false;
12
+ }
13
+ }
14
+ return true;
15
+ };
16
+ /**
17
+ * Returns whether A is entirely contained within B (A subset of B)
18
+ *
19
+ * A ⊆ B
20
+ */
21
+ const isSubset = (a, b) => {
22
+ for (const item of a) {
23
+ if (!b.has(item)) {
24
+ return false;
25
+ }
26
+ }
27
+ return true;
28
+ };
29
+ /**
30
+ * Returns true when the two ets contain the same set of elements
31
+ *
32
+ * A = B
33
+ */
34
+ const areEquivalent = (a, b) => a.size == b.size && isSuperset(a, b) && isSubset(a, b);
35
+
36
+ const expand = (str) => str.split(',').flatMap((entry) => {
37
+ if (!entry.includes('-')) {
38
+ return entry;
39
+ }
40
+ const result = [];
41
+ const [start, end] = entry.split('-').map(Number);
42
+ for (let i = start; i <= end; i++) {
43
+ result.push(i.toString());
44
+ }
45
+ return result;
46
+ });
47
+ /**
48
+ * Exported from https://en.wikipedia.org/wiki/List_of_North_American_Numbering_Plan_area_codes
49
+ *
50
+ * In Dev Tools, select the `tbody` element containing the area codes and run the following code,
51
+ * replacing the emdash character with a simple endash:
52
+ *
53
+ * ```ts
54
+ * [...$0.querySelectorAll('td:first-child')]
55
+ * .filter(cell => cell.firstChild.nodeName != 'A')
56
+ * .map(cell => cell.textContent.trim()).join(',')
57
+ * ```
58
+ */
59
+ new Set([
60
+ ...expand('200,211,221,222,230,232,233,235,237-238,241,243,244,245,247,255,257,258-259,261,265,266,271,273,274,275,277,278,280,282,283,285-287,288,290-299'),
61
+ ...expand('300,311,322,324,327,328,333,335,338,342,344,348-349,353,355,356,357-359,362,366,369,370-379,381,382,383-384,387,388,389,390-399'),
62
+ ...expand('400,411,420,421-422,426-427,428,429,433,439,444,446,449,451-454,455,456,457,459,460,461-462,465,466,467,471,476,477,481-483,485-486,487,488,489,490-499'),
63
+ ...expand('511,532,535,536,537,538,542-543,545-547,549-550,552-554,555,556,558,560,565,568,569,576,578,583,589,590-599'),
64
+ ...expand('611,621,624,625,627,632,633,634-635,637-638,642-643,644,648,652-654,655,663,665,666,668,673-676,677,679,685,686,687,688,690-699'),
65
+ ...expand('711,722,723,729,733,735-736,739,741,744,745-746,748,749-751,752,755,756,759,761,764,766,768,776,777,783,788,789,790-799'),
66
+ ...expand('811,821,822,823-824,827,834,836,841-842,846,851,852-853,871,874-875,879,880-887,889,890-899'),
67
+ ...expand('911,921,922,923,924,926,927,932,933,935,942,944,946,950,953,955,957-958,960-969,974,975,976,977,981-982,987,988,990-999'),
68
+ ]);
69
+
3
70
  const packageName = 'blotoutWallet';
4
71
  const customAttributes = {
5
72
  '--bw-primary': { type: 'color', defaultValue: '#f25c2b' },
@@ -54,19 +121,29 @@ const logger = {
54
121
  },
55
122
  };
56
123
 
124
+ // eslint-disable-next-line @nx/enforce-module-boundaries
57
125
  class APIError extends Error {
58
126
  constructor(...args) {
59
127
  super(...args);
60
128
  }
61
129
  }
130
+ const getItemKey = (item) => `${item.productId}-${item.variantId}`;
131
+ const postMessageKey = 'blotoutWallet';
62
132
  class WalletAPI {
63
133
  constructor({ baseUrl, userId, enabled }) {
64
134
  this.listeners = new Set();
65
135
  this._cart = { cartId: null, items: [], email: false };
136
+ this.onWindowMessage = (event) => {
137
+ var _a;
138
+ if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.name) == postMessageKey) {
139
+ this.cart = event.data.cart;
140
+ }
141
+ };
66
142
  this.baseUrl = baseUrl;
67
143
  this.userId = userId;
68
144
  this.enabled = enabled;
69
145
  logger.info(`[Blotout Wallet] User is ${enabled ? 'enabled' : 'disabled'}`);
146
+ window.addEventListener('message', this.onWindowMessage);
70
147
  }
71
148
  getHeaders(json = false) {
72
149
  const headers = new Headers({
@@ -81,6 +158,7 @@ class WalletAPI {
81
158
  return `${this.baseUrl}/providers/blotoutWallet${path}`;
82
159
  }
83
160
  notify() {
161
+ var _a;
84
162
  for (const listener of this.listeners) {
85
163
  try {
86
164
  listener(this.cart);
@@ -89,13 +167,41 @@ class WalletAPI {
89
167
  console.error(err);
90
168
  }
91
169
  }
170
+ (_a = window.top) === null || _a === void 0 ? void 0 : _a.postMessage({ name: postMessageKey, cart: this.cart }, '*');
92
171
  }
93
172
  get cart() {
94
173
  return this._cart;
95
174
  }
96
175
  set cart(value) {
97
- this._cart = value;
98
- this.notify();
176
+ if (this.isCartUpdated(value)) {
177
+ this._cart = value;
178
+ this.notify();
179
+ }
180
+ }
181
+ isCartUpdated(value) {
182
+ if (value.cartId != this.cart.cartId ||
183
+ value.email != this.cart.email ||
184
+ value.items.length != this.cart.items.length) {
185
+ return true;
186
+ }
187
+ const newItemsMap = new Map(value.items.map((item) => [item.itemId, item]));
188
+ const newItemsKeys = new Set(newItemsMap.keys());
189
+ const currenItemsMap = new Map(this.cart.items.map((item) => [item.itemId, item]));
190
+ const currentItemsKeys = new Set(currenItemsMap.keys());
191
+ if (!areEquivalent(newItemsKeys, currentItemsKeys)) {
192
+ return true;
193
+ }
194
+ for (const [key, newItem] of newItemsMap) {
195
+ const currentItem = currenItemsMap.get(key);
196
+ if (newItem.amount != currentItem.amount ||
197
+ newItem.value != currentItem.value ||
198
+ newItem.name != currentItem.name ||
199
+ newItem.productId != currentItem.productId ||
200
+ newItem.variantId != currentItem.variantId) {
201
+ return true;
202
+ }
203
+ }
204
+ return false;
99
205
  }
100
206
  get segmentEnabled() {
101
207
  return this.enabled;
@@ -131,6 +237,26 @@ class WalletAPI {
131
237
  return (this.cart = await response.json());
132
238
  });
133
239
  }
240
+ removeItems(items) {
241
+ const cartLookup = new Map(this._cart.items.map((item) => [getItemKey(item), item]));
242
+ const itemLookup = new Map(items.map((item) => [getItemKey(item), item]));
243
+ const updatedCartItems = [];
244
+ for (const [itemKey, walletItem] of cartLookup.entries()) {
245
+ const itemToRemove = itemLookup.get(itemKey);
246
+ if (itemToRemove) {
247
+ // if the removed amount is equal or greater, we simply don't push the
248
+ // wallet item into the updated cart contents
249
+ if (walletItem.amount > itemToRemove.amount) {
250
+ walletItem.amount -= itemToRemove.amount;
251
+ updatedCartItems.push(walletItem);
252
+ }
253
+ }
254
+ else {
255
+ updatedCartItems.push(walletItem);
256
+ }
257
+ }
258
+ return this.setItems(updatedCartItems);
259
+ }
134
260
  setItems(items) {
135
261
  return fetch(this.getUrl('/items'), {
136
262
  method: 'PUT',
@@ -144,7 +270,7 @@ class WalletAPI {
144
270
  });
145
271
  }
146
272
  updateItem(item) {
147
- fetch(this.getUrl(`/items/${item.itemId}`), {
273
+ return fetch(this.getUrl(`/items/${item.itemId}`), {
148
274
  method: 'PUT',
149
275
  headers: this.getHeaders(true),
150
276
  body: JSON.stringify({
@@ -161,7 +287,7 @@ class WalletAPI {
161
287
  });
162
288
  }
163
289
  removeItem(itemId) {
164
- fetch(this.getUrl(`/items/${itemId}`), {
290
+ return fetch(this.getUrl(`/items/${itemId}`), {
165
291
  method: 'DELETE',
166
292
  headers: this.getHeaders(),
167
293
  }).then(async (response) => {
@@ -500,7 +626,7 @@ let BlotoutWallet = class BlotoutWallet extends s {
500
626
  this.hasItemsInWallet = false;
501
627
  this.hasEmail = false;
502
628
  this.onWalletUpdated = (walletContent) => {
503
- logger.log({ walletContent });
629
+ logger.log('[Blotout Wallet] Cart updated', walletContent);
504
630
  this.hasItemsInWallet = walletContent.items.length > 0;
505
631
  this.hasEmail = walletContent.email;
506
632
  if (this.isSegmentEnabled && (this.hasItemsInWallet || !this.hasEmail)) {
@@ -1009,6 +1135,13 @@ const tag = (params) => {
1009
1135
  }
1010
1136
  return;
1011
1137
  }
1138
+ case 'RemoveFromCart': {
1139
+ const items = transformItems(params.data);
1140
+ if (items === null || items === void 0 ? void 0 : items.length) {
1141
+ wallet.removeItems(items).catch(logger.error);
1142
+ }
1143
+ return;
1144
+ }
1012
1145
  }
1013
1146
  };
1014
1147
 
package/index.js CHANGED
@@ -1,6 +1,73 @@
1
1
  var ProvidersBlotoutWalletSdk = (function () {
2
2
  'use strict';
3
3
 
4
+ /**
5
+ * Returns whether A contains the entirety of B (A superset of B)
6
+ *
7
+ * A ⊇ B
8
+ */
9
+ const isSuperset = (a, b) => {
10
+ for (const item of b) {
11
+ if (!a.has(item)) {
12
+ return false;
13
+ }
14
+ }
15
+ return true;
16
+ };
17
+ /**
18
+ * Returns whether A is entirely contained within B (A subset of B)
19
+ *
20
+ * A ⊆ B
21
+ */
22
+ const isSubset = (a, b) => {
23
+ for (const item of a) {
24
+ if (!b.has(item)) {
25
+ return false;
26
+ }
27
+ }
28
+ return true;
29
+ };
30
+ /**
31
+ * Returns true when the two ets contain the same set of elements
32
+ *
33
+ * A = B
34
+ */
35
+ const areEquivalent = (a, b) => a.size == b.size && isSuperset(a, b) && isSubset(a, b);
36
+
37
+ const expand = (str) => str.split(',').flatMap((entry) => {
38
+ if (!entry.includes('-')) {
39
+ return entry;
40
+ }
41
+ const result = [];
42
+ const [start, end] = entry.split('-').map(Number);
43
+ for (let i = start; i <= end; i++) {
44
+ result.push(i.toString());
45
+ }
46
+ return result;
47
+ });
48
+ /**
49
+ * Exported from https://en.wikipedia.org/wiki/List_of_North_American_Numbering_Plan_area_codes
50
+ *
51
+ * In Dev Tools, select the `tbody` element containing the area codes and run the following code,
52
+ * replacing the emdash character with a simple endash:
53
+ *
54
+ * ```ts
55
+ * [...$0.querySelectorAll('td:first-child')]
56
+ * .filter(cell => cell.firstChild.nodeName != 'A')
57
+ * .map(cell => cell.textContent.trim()).join(',')
58
+ * ```
59
+ */
60
+ new Set([
61
+ ...expand('200,211,221,222,230,232,233,235,237-238,241,243,244,245,247,255,257,258-259,261,265,266,271,273,274,275,277,278,280,282,283,285-287,288,290-299'),
62
+ ...expand('300,311,322,324,327,328,333,335,338,342,344,348-349,353,355,356,357-359,362,366,369,370-379,381,382,383-384,387,388,389,390-399'),
63
+ ...expand('400,411,420,421-422,426-427,428,429,433,439,444,446,449,451-454,455,456,457,459,460,461-462,465,466,467,471,476,477,481-483,485-486,487,488,489,490-499'),
64
+ ...expand('511,532,535,536,537,538,542-543,545-547,549-550,552-554,555,556,558,560,565,568,569,576,578,583,589,590-599'),
65
+ ...expand('611,621,624,625,627,632,633,634-635,637-638,642-643,644,648,652-654,655,663,665,666,668,673-676,677,679,685,686,687,688,690-699'),
66
+ ...expand('711,722,723,729,733,735-736,739,741,744,745-746,748,749-751,752,755,756,759,761,764,766,768,776,777,783,788,789,790-799'),
67
+ ...expand('811,821,822,823-824,827,834,836,841-842,846,851,852-853,871,874-875,879,880-887,889,890-899'),
68
+ ...expand('911,921,922,923,924,926,927,932,933,935,942,944,946,950,953,955,957-958,960-969,974,975,976,977,981-982,987,988,990-999'),
69
+ ]);
70
+
4
71
  const packageName = 'blotoutWallet';
5
72
  const customAttributes = {
6
73
  '--bw-primary': { type: 'color', defaultValue: '#f25c2b' },
@@ -55,19 +122,29 @@ var ProvidersBlotoutWalletSdk = (function () {
55
122
  },
56
123
  };
57
124
 
125
+ // eslint-disable-next-line @nx/enforce-module-boundaries
58
126
  class APIError extends Error {
59
127
  constructor(...args) {
60
128
  super(...args);
61
129
  }
62
130
  }
131
+ const getItemKey = (item) => `${item.productId}-${item.variantId}`;
132
+ const postMessageKey = 'blotoutWallet';
63
133
  class WalletAPI {
64
134
  constructor({ baseUrl, userId, enabled }) {
65
135
  this.listeners = new Set();
66
136
  this._cart = { cartId: null, items: [], email: false };
137
+ this.onWindowMessage = (event) => {
138
+ var _a;
139
+ if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.name) == postMessageKey) {
140
+ this.cart = event.data.cart;
141
+ }
142
+ };
67
143
  this.baseUrl = baseUrl;
68
144
  this.userId = userId;
69
145
  this.enabled = enabled;
70
146
  logger.info(`[Blotout Wallet] User is ${enabled ? 'enabled' : 'disabled'}`);
147
+ window.addEventListener('message', this.onWindowMessage);
71
148
  }
72
149
  getHeaders(json = false) {
73
150
  const headers = new Headers({
@@ -82,6 +159,7 @@ var ProvidersBlotoutWalletSdk = (function () {
82
159
  return `${this.baseUrl}/providers/blotoutWallet${path}`;
83
160
  }
84
161
  notify() {
162
+ var _a;
85
163
  for (const listener of this.listeners) {
86
164
  try {
87
165
  listener(this.cart);
@@ -90,13 +168,41 @@ var ProvidersBlotoutWalletSdk = (function () {
90
168
  console.error(err);
91
169
  }
92
170
  }
171
+ (_a = window.top) === null || _a === void 0 ? void 0 : _a.postMessage({ name: postMessageKey, cart: this.cart }, '*');
93
172
  }
94
173
  get cart() {
95
174
  return this._cart;
96
175
  }
97
176
  set cart(value) {
98
- this._cart = value;
99
- this.notify();
177
+ if (this.isCartUpdated(value)) {
178
+ this._cart = value;
179
+ this.notify();
180
+ }
181
+ }
182
+ isCartUpdated(value) {
183
+ if (value.cartId != this.cart.cartId ||
184
+ value.email != this.cart.email ||
185
+ value.items.length != this.cart.items.length) {
186
+ return true;
187
+ }
188
+ const newItemsMap = new Map(value.items.map((item) => [item.itemId, item]));
189
+ const newItemsKeys = new Set(newItemsMap.keys());
190
+ const currenItemsMap = new Map(this.cart.items.map((item) => [item.itemId, item]));
191
+ const currentItemsKeys = new Set(currenItemsMap.keys());
192
+ if (!areEquivalent(newItemsKeys, currentItemsKeys)) {
193
+ return true;
194
+ }
195
+ for (const [key, newItem] of newItemsMap) {
196
+ const currentItem = currenItemsMap.get(key);
197
+ if (newItem.amount != currentItem.amount ||
198
+ newItem.value != currentItem.value ||
199
+ newItem.name != currentItem.name ||
200
+ newItem.productId != currentItem.productId ||
201
+ newItem.variantId != currentItem.variantId) {
202
+ return true;
203
+ }
204
+ }
205
+ return false;
100
206
  }
101
207
  get segmentEnabled() {
102
208
  return this.enabled;
@@ -132,6 +238,26 @@ var ProvidersBlotoutWalletSdk = (function () {
132
238
  return (this.cart = await response.json());
133
239
  });
134
240
  }
241
+ removeItems(items) {
242
+ const cartLookup = new Map(this._cart.items.map((item) => [getItemKey(item), item]));
243
+ const itemLookup = new Map(items.map((item) => [getItemKey(item), item]));
244
+ const updatedCartItems = [];
245
+ for (const [itemKey, walletItem] of cartLookup.entries()) {
246
+ const itemToRemove = itemLookup.get(itemKey);
247
+ if (itemToRemove) {
248
+ // if the removed amount is equal or greater, we simply don't push the
249
+ // wallet item into the updated cart contents
250
+ if (walletItem.amount > itemToRemove.amount) {
251
+ walletItem.amount -= itemToRemove.amount;
252
+ updatedCartItems.push(walletItem);
253
+ }
254
+ }
255
+ else {
256
+ updatedCartItems.push(walletItem);
257
+ }
258
+ }
259
+ return this.setItems(updatedCartItems);
260
+ }
135
261
  setItems(items) {
136
262
  return fetch(this.getUrl('/items'), {
137
263
  method: 'PUT',
@@ -145,7 +271,7 @@ var ProvidersBlotoutWalletSdk = (function () {
145
271
  });
146
272
  }
147
273
  updateItem(item) {
148
- fetch(this.getUrl(`/items/${item.itemId}`), {
274
+ return fetch(this.getUrl(`/items/${item.itemId}`), {
149
275
  method: 'PUT',
150
276
  headers: this.getHeaders(true),
151
277
  body: JSON.stringify({
@@ -162,7 +288,7 @@ var ProvidersBlotoutWalletSdk = (function () {
162
288
  });
163
289
  }
164
290
  removeItem(itemId) {
165
- fetch(this.getUrl(`/items/${itemId}`), {
291
+ return fetch(this.getUrl(`/items/${itemId}`), {
166
292
  method: 'DELETE',
167
293
  headers: this.getHeaders(),
168
294
  }).then(async (response) => {
@@ -501,7 +627,7 @@ var ProvidersBlotoutWalletSdk = (function () {
501
627
  this.hasItemsInWallet = false;
502
628
  this.hasEmail = false;
503
629
  this.onWalletUpdated = (walletContent) => {
504
- logger.log({ walletContent });
630
+ logger.log('[Blotout Wallet] Cart updated', walletContent);
505
631
  this.hasItemsInWallet = walletContent.items.length > 0;
506
632
  this.hasEmail = walletContent.email;
507
633
  if (this.isSegmentEnabled && (this.hasItemsInWallet || !this.hasEmail)) {
@@ -1010,6 +1136,13 @@ var ProvidersBlotoutWalletSdk = (function () {
1010
1136
  }
1011
1137
  return;
1012
1138
  }
1139
+ case 'RemoveFromCart': {
1140
+ const items = transformItems(params.data);
1141
+ if (items === null || items === void 0 ? void 0 : items.length) {
1142
+ wallet.removeItems(items).catch(logger.error);
1143
+ }
1144
+ return;
1145
+ }
1013
1146
  }
1014
1147
  };
1015
1148
 
package/index.mjs CHANGED
@@ -1,3 +1,70 @@
1
+ /**
2
+ * Returns whether A contains the entirety of B (A superset of B)
3
+ *
4
+ * A ⊇ B
5
+ */
6
+ const isSuperset = (a, b) => {
7
+ for (const item of b) {
8
+ if (!a.has(item)) {
9
+ return false;
10
+ }
11
+ }
12
+ return true;
13
+ };
14
+ /**
15
+ * Returns whether A is entirely contained within B (A subset of B)
16
+ *
17
+ * A ⊆ B
18
+ */
19
+ const isSubset = (a, b) => {
20
+ for (const item of a) {
21
+ if (!b.has(item)) {
22
+ return false;
23
+ }
24
+ }
25
+ return true;
26
+ };
27
+ /**
28
+ * Returns true when the two ets contain the same set of elements
29
+ *
30
+ * A = B
31
+ */
32
+ const areEquivalent = (a, b) => a.size == b.size && isSuperset(a, b) && isSubset(a, b);
33
+
34
+ const expand = (str) => str.split(',').flatMap((entry) => {
35
+ if (!entry.includes('-')) {
36
+ return entry;
37
+ }
38
+ const result = [];
39
+ const [start, end] = entry.split('-').map(Number);
40
+ for (let i = start; i <= end; i++) {
41
+ result.push(i.toString());
42
+ }
43
+ return result;
44
+ });
45
+ /**
46
+ * Exported from https://en.wikipedia.org/wiki/List_of_North_American_Numbering_Plan_area_codes
47
+ *
48
+ * In Dev Tools, select the `tbody` element containing the area codes and run the following code,
49
+ * replacing the emdash character with a simple endash:
50
+ *
51
+ * ```ts
52
+ * [...$0.querySelectorAll('td:first-child')]
53
+ * .filter(cell => cell.firstChild.nodeName != 'A')
54
+ * .map(cell => cell.textContent.trim()).join(',')
55
+ * ```
56
+ */
57
+ new Set([
58
+ ...expand('200,211,221,222,230,232,233,235,237-238,241,243,244,245,247,255,257,258-259,261,265,266,271,273,274,275,277,278,280,282,283,285-287,288,290-299'),
59
+ ...expand('300,311,322,324,327,328,333,335,338,342,344,348-349,353,355,356,357-359,362,366,369,370-379,381,382,383-384,387,388,389,390-399'),
60
+ ...expand('400,411,420,421-422,426-427,428,429,433,439,444,446,449,451-454,455,456,457,459,460,461-462,465,466,467,471,476,477,481-483,485-486,487,488,489,490-499'),
61
+ ...expand('511,532,535,536,537,538,542-543,545-547,549-550,552-554,555,556,558,560,565,568,569,576,578,583,589,590-599'),
62
+ ...expand('611,621,624,625,627,632,633,634-635,637-638,642-643,644,648,652-654,655,663,665,666,668,673-676,677,679,685,686,687,688,690-699'),
63
+ ...expand('711,722,723,729,733,735-736,739,741,744,745-746,748,749-751,752,755,756,759,761,764,766,768,776,777,783,788,789,790-799'),
64
+ ...expand('811,821,822,823-824,827,834,836,841-842,846,851,852-853,871,874-875,879,880-887,889,890-899'),
65
+ ...expand('911,921,922,923,924,926,927,932,933,935,942,944,946,950,953,955,957-958,960-969,974,975,976,977,981-982,987,988,990-999'),
66
+ ]);
67
+
1
68
  const packageName = 'blotoutWallet';
2
69
  const customAttributes = {
3
70
  '--bw-primary': { type: 'color', defaultValue: '#f25c2b' },
@@ -52,19 +119,29 @@ const logger = {
52
119
  },
53
120
  };
54
121
 
122
+ // eslint-disable-next-line @nx/enforce-module-boundaries
55
123
  class APIError extends Error {
56
124
  constructor(...args) {
57
125
  super(...args);
58
126
  }
59
127
  }
128
+ const getItemKey = (item) => `${item.productId}-${item.variantId}`;
129
+ const postMessageKey = 'blotoutWallet';
60
130
  class WalletAPI {
61
131
  constructor({ baseUrl, userId, enabled }) {
62
132
  this.listeners = new Set();
63
133
  this._cart = { cartId: null, items: [], email: false };
134
+ this.onWindowMessage = (event) => {
135
+ var _a;
136
+ if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.name) == postMessageKey) {
137
+ this.cart = event.data.cart;
138
+ }
139
+ };
64
140
  this.baseUrl = baseUrl;
65
141
  this.userId = userId;
66
142
  this.enabled = enabled;
67
143
  logger.info(`[Blotout Wallet] User is ${enabled ? 'enabled' : 'disabled'}`);
144
+ window.addEventListener('message', this.onWindowMessage);
68
145
  }
69
146
  getHeaders(json = false) {
70
147
  const headers = new Headers({
@@ -79,6 +156,7 @@ class WalletAPI {
79
156
  return `${this.baseUrl}/providers/blotoutWallet${path}`;
80
157
  }
81
158
  notify() {
159
+ var _a;
82
160
  for (const listener of this.listeners) {
83
161
  try {
84
162
  listener(this.cart);
@@ -87,13 +165,41 @@ class WalletAPI {
87
165
  console.error(err);
88
166
  }
89
167
  }
168
+ (_a = window.top) === null || _a === void 0 ? void 0 : _a.postMessage({ name: postMessageKey, cart: this.cart }, '*');
90
169
  }
91
170
  get cart() {
92
171
  return this._cart;
93
172
  }
94
173
  set cart(value) {
95
- this._cart = value;
96
- this.notify();
174
+ if (this.isCartUpdated(value)) {
175
+ this._cart = value;
176
+ this.notify();
177
+ }
178
+ }
179
+ isCartUpdated(value) {
180
+ if (value.cartId != this.cart.cartId ||
181
+ value.email != this.cart.email ||
182
+ value.items.length != this.cart.items.length) {
183
+ return true;
184
+ }
185
+ const newItemsMap = new Map(value.items.map((item) => [item.itemId, item]));
186
+ const newItemsKeys = new Set(newItemsMap.keys());
187
+ const currenItemsMap = new Map(this.cart.items.map((item) => [item.itemId, item]));
188
+ const currentItemsKeys = new Set(currenItemsMap.keys());
189
+ if (!areEquivalent(newItemsKeys, currentItemsKeys)) {
190
+ return true;
191
+ }
192
+ for (const [key, newItem] of newItemsMap) {
193
+ const currentItem = currenItemsMap.get(key);
194
+ if (newItem.amount != currentItem.amount ||
195
+ newItem.value != currentItem.value ||
196
+ newItem.name != currentItem.name ||
197
+ newItem.productId != currentItem.productId ||
198
+ newItem.variantId != currentItem.variantId) {
199
+ return true;
200
+ }
201
+ }
202
+ return false;
97
203
  }
98
204
  get segmentEnabled() {
99
205
  return this.enabled;
@@ -129,6 +235,26 @@ class WalletAPI {
129
235
  return (this.cart = await response.json());
130
236
  });
131
237
  }
238
+ removeItems(items) {
239
+ const cartLookup = new Map(this._cart.items.map((item) => [getItemKey(item), item]));
240
+ const itemLookup = new Map(items.map((item) => [getItemKey(item), item]));
241
+ const updatedCartItems = [];
242
+ for (const [itemKey, walletItem] of cartLookup.entries()) {
243
+ const itemToRemove = itemLookup.get(itemKey);
244
+ if (itemToRemove) {
245
+ // if the removed amount is equal or greater, we simply don't push the
246
+ // wallet item into the updated cart contents
247
+ if (walletItem.amount > itemToRemove.amount) {
248
+ walletItem.amount -= itemToRemove.amount;
249
+ updatedCartItems.push(walletItem);
250
+ }
251
+ }
252
+ else {
253
+ updatedCartItems.push(walletItem);
254
+ }
255
+ }
256
+ return this.setItems(updatedCartItems);
257
+ }
132
258
  setItems(items) {
133
259
  return fetch(this.getUrl('/items'), {
134
260
  method: 'PUT',
@@ -142,7 +268,7 @@ class WalletAPI {
142
268
  });
143
269
  }
144
270
  updateItem(item) {
145
- fetch(this.getUrl(`/items/${item.itemId}`), {
271
+ return fetch(this.getUrl(`/items/${item.itemId}`), {
146
272
  method: 'PUT',
147
273
  headers: this.getHeaders(true),
148
274
  body: JSON.stringify({
@@ -159,7 +285,7 @@ class WalletAPI {
159
285
  });
160
286
  }
161
287
  removeItem(itemId) {
162
- fetch(this.getUrl(`/items/${itemId}`), {
288
+ return fetch(this.getUrl(`/items/${itemId}`), {
163
289
  method: 'DELETE',
164
290
  headers: this.getHeaders(),
165
291
  }).then(async (response) => {
@@ -498,7 +624,7 @@ let BlotoutWallet = class BlotoutWallet extends s {
498
624
  this.hasItemsInWallet = false;
499
625
  this.hasEmail = false;
500
626
  this.onWalletUpdated = (walletContent) => {
501
- logger.log({ walletContent });
627
+ logger.log('[Blotout Wallet] Cart updated', walletContent);
502
628
  this.hasItemsInWallet = walletContent.items.length > 0;
503
629
  this.hasEmail = walletContent.email;
504
630
  if (this.isSegmentEnabled && (this.hasItemsInWallet || !this.hasEmail)) {
@@ -1007,6 +1133,13 @@ const tag = (params) => {
1007
1133
  }
1008
1134
  return;
1009
1135
  }
1136
+ case 'RemoveFromCart': {
1137
+ const items = transformItems(params.data);
1138
+ if (items === null || items === void 0 ? void 0 : items.length) {
1139
+ wallet.removeItems(items).catch(logger.error);
1140
+ }
1141
+ return;
1142
+ }
1010
1143
  }
1011
1144
  };
1012
1145
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blotoutio/providers-blotout-wallet-sdk",
3
- "version": "0.43.0",
3
+ "version": "0.44.1",
4
4
  "description": "Blotout Wallet SDK for EdgeTag",
5
5
  "author": "Blotout",
6
6
  "license": "MIT",