const httpserver = "https://stargazer.rest:4000/analytics";
/**
* Create an empty session for analytics usage, uses default/empty values
* @returns {JSONObject} JSON object representing current session
*/
function getEmptySession() {
const emptySessionJSON = {
id: makeid(12),
status: 1,
exitPage: "",
errors: [],
timeOnPage: {
landing: 0,
skymap: 0,
explanation: 0,
response: 0,
thankYou: 0,
},
categorySelected: "",
clicks: [],
starSelected: 0,
};
return emptySessionJSON;
}
/**
* Get the current session. If no current session exists, creates an empty session and returns it
* @returns {JSONObject} JSON object representing current session
*/
function getSession() {
let sessionObj = localStorage.getItem("session");
if (sessionObj === null) {
sessionObj = getEmptySession();
} else {
sessionObj = JSON.parse(sessionObj);
}
return sessionObj;
}
/**
* Writes a session to local storage
* @param {JSONObject} sessionJSON session object to be written
*/
function writeSession(sessionJSON) {
const sessionString = JSON.stringify(sessionJSON);
localStorage.setItem("session", sessionString);
}
/**
* Set the current session to empty
*/
function setEmptySession() {
let session = getEmptySession();
writeSession(session);
}
/**
* Set the status of the session to either 0=success, or 1=error/exit
* @param {number} status status code to be entered
*/
function setSessionStatus(status) {
let session = getSession();
session.status = status;
writeSession(session);
}
/**
* Set the exit page name
* @param {string} pageName page name to be written
*/
function setSessionExit(pageName) {
let session = getSession();
session.exitPage = pageName;
writeSession(session);
}
/**
* Add an error to current session
* @param {string} pageName page name that the error occured on
* @param {string} name top level name of error
* @param {string} message error message
* @param {string} stack string representation of the stack trace at error
*/
function addSessionError(pageName, name, message, stack) {
let session = getSession();
session.errors.push({
page: pageName,
name: name,
message: message,
stack: stack,
});
writeSession(session);
}
/**
* Add to current time on page, by a specified amount
* @param {string} pageName page name to add time to
* @param {number} time amount of time to increment by
*/
function addSessionPageTime(pageName, time) {
let session = getSession();
session.timeOnPage[pageName] += time;
writeSession(session);
}
/**
* Change the category selected of the current session
* @param {string} category category name to set to
*/
function addSessionCategorySelected(category) {
let session = getSession();
session.categorySelected = category;
writeSession(session);
}
/**
* Add a mouse click event to the sessions click history
* @param {Array} click coordinates of downclick and upclick, in nested length 2 arrays
*/
function addSessionClick(click) {
let session = getSession();
session.clicks.push(click);
writeSession(session);
}
/**
* Increment the starselected for the session
*/
function sessionStarSelectedInc() {
let session = getSession();
session.starSelected += 1;
writeSession(session);
}
function sessionPOST() {
fetch(httpserver, {
method: "POST",
body: JSON.stringify(getSession()),
headers: {
"Content-type": "application/json; charset=UTF-8",
},
keepalive: true,
});
}
function sessionBeacon() {
navigator.sendBeacon(httpserver, JSON.stringify(getSession()));
}
/**
* This function generates a random id of length
* @param {number} length
* @returns a random string of provided length
*/
function makeid(length) {
let result = "";
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
counter += 1;
}
return result;
}
/**
* This function tags a page with duration tracking, and error tracking
* Requires a string for the current page name, and status of being on this page
* @param {string} pageName page name of current page
* @param {int} status status code to post when this page is left from
*/
function defaultPageAnalytics(pageName, status) {
setSessionExit(pageName);
setSessionStatus(status);
/**
* Start time tracker on initial dom content load
*/
let startTime;
document.addEventListener("DOMContentLoaded", () => {
startTime = new Date();
console.log("Starting time");
});
/**
* Listen for visibility changes or beforeunload for end time and
* push session
*/
document.addEventListener("beforeunload", () => {
console.log("Posting");
const endTime = new Date();
addSessionPageTime(pageName, endTime.getTime() - startTime.getTime());
sessionPOST();
});
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "visible") {
// If it came back into visibility start a new time
console.log("Restarting time");
startTime = new Date();
} else {
console.log("Posting");
const endTime = new Date();
addSessionPageTime(pageName, endTime.getTime() - startTime.getTime());
sessionPOST();
}
});
/**
* Error tracker for page analytics
*/
window.addEventListener("error", (event) => {
addSessionError(
pageName,
event.error.name,
event.error.message,
event.error.stack
);
});
}
export {
setEmptySession,
setSessionStatus,
setSessionExit,
addSessionError,
addSessionPageTime,
addSessionCategorySelected,
addSessionClick,
sessionStarSelectedInc,
sessionPOST,
sessionBeacon,
defaultPageAnalytics,
};