@pinelab/vendure-plugin-metrics
Version:
Vendure plugin measuring and visualizing e-commerce metrics
137 lines (136 loc) • 4.81 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getMonthName = getMonthName;
exports.groupEntitiesPerMonth = groupEntitiesPerMonth;
exports.getEntitiesForMonth = getEntitiesForMonth;
exports.mapToSeries = mapToSeries;
exports.getSessions = getSessions;
const date_fns_1 = require("date-fns");
function getMonthName(monthNr) {
const monthNames = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
];
return monthNames[monthNr];
}
/**
* Categorize loaded entities per month
*/
function groupEntitiesPerMonth(entities, sortableField, from, to) {
// Helper function to construct yearMonth as identifier. E.g. "2021-1"
const getYearMonth = (date) => `${date.getFullYear()}-${date.getMonth()}`;
const entitiesPerMonth = new Map();
// Populate the map with all months in the range
let currentDate = (0, date_fns_1.startOfMonth)(from);
while ((0, date_fns_1.isBefore)(currentDate, to)) {
const yearMonth = getYearMonth(currentDate);
entitiesPerMonth.set(yearMonth, {
monthNr: currentDate.getMonth(),
year: currentDate.getFullYear(),
date: currentDate,
entities: [],
});
currentDate = (0, date_fns_1.addMonths)(currentDate, 1);
}
// Loop over each item and categorize it in the correct month
entities.forEach((entity) => {
const date = entity[sortableField];
if (!(date instanceof Date) || isNaN(date)) {
throw Error(`${date} is not a valid date! Can not split ${entities.constructor.name}'s in months.`);
}
const yearMonth = getYearMonth(date);
const entry = entitiesPerMonth.get(yearMonth);
if (!entry) {
// Should never happen, but type safety
return;
}
entry.entities.push(entity);
entitiesPerMonth.set(yearMonth, entry);
});
return Array.from(entitiesPerMonth.values());
}
/**
* Get entities from a list for given month and year
*/
function getEntitiesForMonth(entities, date, dateFilterField) {
return entities.filter((entity) => {
const entityDate = entity[dateFilterField];
return (0, date_fns_1.isSameMonth)(entityDate, date) && (0, date_fns_1.isSameYear)(entityDate, date);
});
}
/**
* Map the data points per month map to the AdvancedMetricSeries array.
*
* E.g. `'product1', [10, 20, 30]` becomes
* `[{ name: 'product1', values: [10, 20, 30] }]`
* This is used to display the data in the chart.
*/
function mapToSeries(dataPointsPerMonth) {
const series = [];
dataPointsPerMonth.forEach((dataPoints, name) => {
series.push({
name,
values: dataPoints,
});
});
return series;
}
/**
* Aggregates the raw requests to sessions, grouping them by identifier and session length.
*
* E.g. multiple requests from id:123 within 5 minutes are combined into 1 session
*
*/
function getSessions(requests, sessionLengthInMinutes) {
const sessions = [];
const sessionLengthInMs = sessionLengthInMinutes * 60 * 1000;
// Group requests by identifier
const requestsByIdentifier = requests.reduce((map, request) => {
const group = map.get(request.identifier) || [];
group.push(request);
map.set(request.identifier, group);
return map;
}, new Map());
// Combine requests within the same session length into one session
for (const [identifier, groupedRequests] of requestsByIdentifier) {
// Sort requests by timestamp
groupedRequests.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
let currentSession = null;
for (const request of groupedRequests) {
const isWithinSession = currentSession &&
request.createdAt.getTime() - currentSession.start.getTime() <=
sessionLengthInMs;
if (sessionLengthInMs && isWithinSession && currentSession) {
// Extend the current session if the request is within the same session
currentSession.end = request.createdAt;
}
else {
// Start a new session
if (currentSession) {
sessions.push(currentSession);
}
currentSession = {
identifier,
start: request.createdAt,
end: request.createdAt,
deviceType: request.deviceType,
};
}
}
// Push the last session
if (currentSession) {
sessions.push(currentSession);
}
}
return sessions;
}