ttf-api
Version:
The TrueToForm API SDK
114 lines (99 loc) • 3.09 kB
JavaScript
class EventQueue {
constructor(client) {
if (EventQueue.instance) {
return EventQueue.instance;
}
this.eventQueue = [];
this.MAX_BATCH_SIZE = 50;
this.MAX_TIME_INTERVAL = 5000;
this.sendEventsTimer = null;
this.client = client;
this.loadQueueFromLocalStorage();
// Send remaining events on page unload
window.addEventListener("beforeunload", () => {
this.sendEvents();
});
// Handle storage events to synchronize across tabs
window.addEventListener("storage", (event) => {
if (event.key === "analyticsEventQueue") {
this.loadQueueFromLocalStorage();
}
});
EventQueue.instance = this;
}
static getInstance(client) {
if (!EventQueue.instance) {
EventQueue.instance = new EventQueue(client);
}
return EventQueue.instance;
}
loadQueueFromLocalStorage() {
try {
const storedQueue = localStorage.getItem("analyticsEventQueue");
if (storedQueue) {
this.eventQueue = JSON.parse(storedQueue);
}
} catch (error) {
console.error("Failed to load event queue from localStorage:", error);
}
}
saveQueueToLocalStorage() {
try {
localStorage.setItem(
"analyticsEventQueue",
JSON.stringify(this.eventQueue)
);
} catch (error) {
console.error("Failed to save event queue to localStorage:", error);
}
}
enqueueEvent(event) {
// save the latest widget state if provided
// and pass it to the next event if it doesn't have one
const widgetState = event.metadata.widgetState;
if (widgetState) {
// make sure it's object and not empty
if (typeof widgetState === "object" && Object.keys(widgetState).length) {
this.latestWidgetState = widgetState;
}
}
// if the event already has a widget state, we are setting
// the event's widget state to it again. while if it doesn't
// then this event will have the latest widget state from the previous event
if (this.latestWidgetState) {
event.metadata.widgetState = this.latestWidgetState;
}
this.eventQueue.push(event);
this.saveQueueToLocalStorage();
this.checkAndSendEvents();
}
checkAndSendEvents() {
if (this.eventQueue.length >= this.MAX_BATCH_SIZE) {
this.sendEvents();
} else if (!this.sendEventsTimer) {
this.sendEventsTimer = setTimeout(() => {
this.sendEvents();
}, this.MAX_TIME_INTERVAL);
}
}
async sendEvents() {
if (this.sendEventsTimer) {
clearTimeout(this.sendEventsTimer);
this.sendEventsTimer = null;
}
if (this.eventQueue.length === 0) return;
const eventsToSend = [...this.eventQueue];
this.eventQueue = [];
this.saveQueueToLocalStorage();
try {
await this.client.post("analytics/event", {
events: eventsToSend,
});
} catch (error) {
console.error("Failed to send events:", error);
this.eventQueue = [...eventsToSend, ...this.eventQueue];
this.saveQueueToLocalStorage();
}
}
}
export default EventQueue;