UNPKG

@pinelab/vendure-plugin-metrics

Version:

Vendure plugin measuring and visualizing e-commerce metrics

137 lines (136 loc) 4.81 kB
"use strict"; 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; }