Skip to content

Commit 2434dd7

Browse files
[MOB-9999] Aggregate user update event gets deleted (#469)
* prettify code * [MOB-9703] Added support for fetching new JWT prior to calling merge * [MOB-9999] Aggregate user update event gets deleted * missed this * fix up tests and issues * update types * update types some more * forgot to commit this --------- Co-authored-by: mitch prewitt <mitch.prewitt@iterable.com>
1 parent 4b1829a commit 2434dd7

13 files changed

Lines changed: 1257 additions & 967 deletions

src/anonymousUserTracking/anonymousUserEventManager.ts

Lines changed: 98 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import { v4 as uuidv4 } from 'uuid';
33
import {
44
UpdateCartRequestParams,
5-
TrackPurchaseRequestParams
5+
TrackPurchaseRequestParams,
6+
CommerceItem
67
} from '../commerce/types';
78

89
import {
@@ -26,7 +27,8 @@ import {
2627
KEY_PREFER_USERID,
2728
ENDPOINTS,
2829
DEFAULT_EVENT_THRESHOLD_LIMIT,
29-
SHARED_PREF_ANON_USAGE_TRACKED
30+
SHARED_PREF_ANON_USAGE_TRACKED,
31+
SHARED_PREFS_USER_UPDATE_OBJECT_KEY
3032
} from '../constants';
3133
import { baseIterableRequest } from '../request';
3234
import { IterableResponse } from '../types';
@@ -42,6 +44,39 @@ import { updateUserSchema } from '../users/users.schema';
4244
import { InAppTrackRequestParams } from '../events';
4345
import config from '../utils/config';
4446

47+
// Type definitions for anonymous event data objects
48+
type AnonTrackEventData = {
49+
eventName: string;
50+
createdAt: number;
51+
dataFields?: Record<string, any>;
52+
createNewFields: boolean;
53+
eventType: string;
54+
};
55+
56+
type AnonTrackPurchaseData = {
57+
items: CommerceItem[];
58+
createdAt: number;
59+
dataFields?: Record<string, any>;
60+
total: number;
61+
eventType: string;
62+
};
63+
64+
type AnonUpdateCartData = {
65+
items: CommerceItem[];
66+
eventType: string;
67+
preferUserId: boolean;
68+
createdAt: number;
69+
};
70+
71+
type AnonUserUpdateData = Record<string, any> & {
72+
eventType: string;
73+
};
74+
75+
type AnonEventData =
76+
| AnonTrackEventData
77+
| AnonTrackPurchaseData
78+
| AnonUpdateCartData;
79+
4580
type AnonUserFunction = (userId: string) => void;
4681

4782
let anonUserIdSetter: AnonUserFunction | null = null;
@@ -136,15 +171,15 @@ export class AnonymousUserEventManager {
136171
[KEY_CREATE_NEW_FIELDS]: true,
137172
[SHARED_PREFS_EVENT_TYPE]: TRACK_EVENT
138173
};
139-
this.storeEventListToLocalStorage(newDataObject, false);
174+
this.storeEventListToLocalStorage(newDataObject);
140175
}
141176

142177
async trackAnonUpdateUser(payload: UpdateUserParams) {
143178
const newDataObject = {
144179
...payload.dataFields,
145180
[SHARED_PREFS_EVENT_TYPE]: UPDATE_USER
146181
};
147-
this.storeEventListToLocalStorage(newDataObject, true);
182+
this.storeUserUpdateToLocalStorage(newDataObject);
148183
}
149184

150185
async trackAnonPurchaseEvent(payload: TrackPurchaseRequestParams) {
@@ -155,7 +190,7 @@ export class AnonymousUserEventManager {
155190
[KEY_TOTAL]: payload.total,
156191
[SHARED_PREFS_EVENT_TYPE]: TRACK_PURCHASE
157192
};
158-
this.storeEventListToLocalStorage(newDataObject, false);
193+
this.storeEventListToLocalStorage(newDataObject);
159194
}
160195

161196
async trackAnonUpdateCart(payload: UpdateCartRequestParams) {
@@ -165,17 +200,23 @@ export class AnonymousUserEventManager {
165200
[KEY_PREFER_USERID]: true,
166201
[KEY_CREATED_AT]: this.getCurrentTime()
167202
};
168-
this.storeEventListToLocalStorage(newDataObject, false);
203+
this.storeEventListToLocalStorage(newDataObject);
169204
}
170205

171206
private checkCriteriaCompletion(): string | null {
172207
const criteriaData = localStorage.getItem(SHARED_PREFS_CRITERIA);
173208
const localStoredEventList = localStorage.getItem(
174209
SHARED_PREFS_EVENT_LIST_KEY
175210
);
211+
const localStoredUserUpdate = localStorage.getItem(
212+
SHARED_PREFS_USER_UPDATE_OBJECT_KEY
213+
);
176214
try {
177215
if (criteriaData && localStoredEventList) {
178-
const checker = new CriteriaCompletionChecker(localStoredEventList);
216+
const checker = new CriteriaCompletionChecker(
217+
localStoredEventList,
218+
localStoredUserUpdate
219+
);
179220
return checker.getMatchedCriteria(criteriaData);
180221
}
181222
} catch (error) {
@@ -191,14 +232,11 @@ export class AnonymousUserEventManager {
191232
if (!anonymousUsageTracked) return;
192233

193234
const userData = localStorage.getItem(SHARED_PREFS_ANON_SESSIONS);
194-
const eventList = localStorage.getItem(SHARED_PREFS_EVENT_LIST_KEY);
195-
const events = eventList ? JSON.parse(eventList) : [];
235+
const strUserUpdate = localStorage.getItem(
236+
SHARED_PREFS_USER_UPDATE_OBJECT_KEY
237+
);
238+
const dataFields = strUserUpdate ? JSON.parse(strUserUpdate) : {};
196239

197-
const dataFields = {
198-
...events.find(
199-
(event: any) => event[SHARED_PREFS_EVENT_TYPE] === UPDATE_USER
200-
)
201-
};
202240
delete dataFields[SHARED_PREFS_EVENT_TYPE];
203241

204242
const userId = uuidv4();
@@ -238,15 +276,7 @@ export class AnonymousUserEventManager {
238276
}
239277
});
240278
if (response?.status === 200) {
241-
// Update local storage, remove updateUser from local storage
242-
localStorage.setItem(
243-
SHARED_PREFS_EVENT_LIST_KEY,
244-
JSON.stringify(
245-
events.filter(
246-
(event: any) => event[SHARED_PREFS_EVENT_TYPE] !== UPDATE_USER
247-
)
248-
)
249-
);
279+
localStorage.removeItem(SHARED_PREFS_USER_UPDATE_OBJECT_KEY);
250280

251281
const onAnonUserCreated = config.getConfig('onAnonUserCreated');
252282

@@ -267,6 +297,11 @@ export class AnonymousUserEventManager {
267297
? JSON.parse(strTrackEventList)
268298
: [];
269299

300+
const strUserUpdate = localStorage.getItem(
301+
SHARED_PREFS_USER_UPDATE_OBJECT_KEY
302+
);
303+
const userUpdateObject = strUserUpdate ? JSON.parse(strUserUpdate) : {};
304+
270305
if (trackEventList.length) {
271306
trackEventList.forEach(
272307
(
@@ -288,31 +323,28 @@ export class AnonymousUserEventManager {
288323
this.updateCart(event);
289324
break;
290325
}
291-
case UPDATE_USER: {
292-
this.updateUser({ dataFields: event });
293-
break;
294-
}
295326
default:
296327
break;
297328
}
298329
this.removeAnonSessionCriteriaData();
299330
}
300331
);
301332
}
333+
334+
if (Object.keys(userUpdateObject).length) {
335+
// eslint-disable-next-line no-param-reassign
336+
delete userUpdateObject[SHARED_PREFS_EVENT_TYPE];
337+
this.updateUser(userUpdateObject);
338+
}
302339
}
303340

304341
removeAnonSessionCriteriaData() {
305342
localStorage.removeItem(SHARED_PREFS_ANON_SESSIONS);
306343
localStorage.removeItem(SHARED_PREFS_EVENT_LIST_KEY);
344+
localStorage.removeItem(SHARED_PREFS_USER_UPDATE_OBJECT_KEY);
307345
}
308346

309-
private async storeEventListToLocalStorage(
310-
newDataObject: Record<
311-
any /* eslint-disable-line @typescript-eslint/no-explicit-any */,
312-
any /* eslint-disable-line @typescript-eslint/no-explicit-any */
313-
>,
314-
shouldOverWrite: boolean
315-
) {
347+
private async storeEventListToLocalStorage(newDataObject: AnonEventData) {
316348
const anonymousUsageTracked = isAnonymousUsageTracked();
317349

318350
if (!anonymousUsageTracked) return;
@@ -324,24 +356,7 @@ export class AnonymousUserEventManager {
324356
previousDataArray = JSON.parse(strTrackEventList);
325357
}
326358

327-
if (shouldOverWrite) {
328-
const trackingType = newDataObject[SHARED_PREFS_EVENT_TYPE];
329-
const indexToUpdate = previousDataArray.findIndex(
330-
(obj: any) => obj[SHARED_PREFS_EVENT_TYPE] === trackingType
331-
);
332-
if (indexToUpdate !== -1) {
333-
const dataToUpdate = previousDataArray[indexToUpdate];
334-
335-
previousDataArray[indexToUpdate] = {
336-
...dataToUpdate,
337-
...newDataObject
338-
};
339-
} else {
340-
previousDataArray.push(newDataObject);
341-
}
342-
} else {
343-
previousDataArray.push(newDataObject);
344-
}
359+
previousDataArray.push(newDataObject);
345360

346361
// - The code below limits the number of events stored in local storage.
347362
// - The event list acts as a queue, with the oldest events being deleted
@@ -366,6 +381,37 @@ export class AnonymousUserEventManager {
366381
}
367382
}
368383

384+
private async storeUserUpdateToLocalStorage(
385+
newDataObject: AnonUserUpdateData
386+
) {
387+
const anonymousUsageTracked = isAnonymousUsageTracked();
388+
389+
if (!anonymousUsageTracked) return;
390+
391+
const strUserUpdate = localStorage.getItem(
392+
SHARED_PREFS_USER_UPDATE_OBJECT_KEY
393+
);
394+
let userUpdateObject = {};
395+
396+
if (strUserUpdate) {
397+
userUpdateObject = JSON.parse(strUserUpdate);
398+
}
399+
400+
userUpdateObject = {
401+
...userUpdateObject,
402+
...newDataObject
403+
};
404+
405+
localStorage.setItem(
406+
SHARED_PREFS_USER_UPDATE_OBJECT_KEY,
407+
JSON.stringify(userUpdateObject)
408+
);
409+
const criteriaId = this.checkCriteriaCompletion();
410+
if (criteriaId !== null) {
411+
this.createAnonymousUser(criteriaId);
412+
}
413+
}
414+
369415
private getCurrentTime = () => {
370416
const dateInMillis = new Date().getTime();
371417
const dateInSeconds = Math.floor(dateInMillis / 1000);

0 commit comments

Comments
 (0)