Skip to content

Commit b088a8d

Browse files
committed
updated the analytical services
1 parent 9bfcd10 commit b088a8d

1 file changed

Lines changed: 128 additions & 58 deletions

File tree

services/AnalyticsService.js

Lines changed: 128 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,60 @@ class AnalyticsService {
260260
}
261261
}
262262

263+
/**
264+
* Export data for external analytics tools
265+
*/
266+
async exportData(startDate, endDate, format = 'json') {
267+
try {
268+
const start = new Date(startDate);
269+
const end = new Date(endDate);
270+
const allEvents = [];
271+
272+
// Collect events from the date range
273+
const diffTime = Math.abs(end - start);
274+
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
275+
276+
for (let i = 0; i <= diffDays; i++) {
277+
const date = new Date(start);
278+
date.setDate(date.getDate() + i);
279+
const dateStr = date.toISOString().split('T')[0];
280+
const filename = path.join(this.dataDir, `analytics-${dateStr}.jsonl`);
281+
282+
if (fs.existsSync(filename)) {
283+
const events = await this.readLogFile(filename);
284+
allEvents.push(...events.filter(event => {
285+
const eventDate = new Date(event.timestamp);
286+
return eventDate >= start && eventDate <= end;
287+
}));
288+
}
289+
}
290+
291+
if (format === 'csv') {
292+
// Convert to CSV format
293+
if (allEvents.length === 0) return 'timestamp,type,sessionId,page,query,rating\n';
294+
295+
const csvHeader = Object.keys(allEvents[0]).join(',') + '\n';
296+
const csvRows = allEvents.map(event =>
297+
Object.values(event).map(value =>
298+
typeof value === 'string' && value.includes(',') ? `"${value}"` : value
299+
).join(',')
300+
).join('\n');
301+
302+
return csvHeader + csvRows;
303+
}
304+
305+
return {
306+
exportDate: new Date().toISOString(),
307+
dateRange: { start: startDate, end: endDate },
308+
totalEvents: allEvents.length,
309+
events: allEvents
310+
};
311+
} catch (error) {
312+
console.error('Failed to export data:', error);
313+
return null;
314+
}
315+
}
316+
263317
/**
264318
* Private helper methods
265319
*/
@@ -355,73 +409,89 @@ class AnalyticsService {
355409
}
356410

357411
async getUserFlow(days) {
358-
// Implementation for user flow analysis
359-
return {
360-
entryPages: [],
361-
exitPages: [],
362-
commonPaths: []
363-
};
364-
}
412+
const files = await this.getRecentLogFiles(days);
413+
const entryPages = new Map();
414+
const exitPages = new Map();
415+
const pathSequences = new Map();
365416

366-
async getPerformanceMetrics(days) {
367-
// Implementation for performance metrics
368-
return {
369-
avgLoadTime: 0,
370-
bounceRate: 0,
371-
avgSessionDuration: 0
372-
};
373-
}
417+
for (const file of files) {
418+
const events = await this.readLogFile(file);
419+
const sessions = new Map();
374420

375-
/**
376-
* Export data for external analytics tools
377-
*/
378-
async exportData(startDate, endDate, format = 'json') {
379-
// Implementation for data export
380-
return null;
381-
}
421+
// Group events by session
422+
for (const event of events) {
423+
if (event.type === 'page_view' && event.sessionId) {
424+
if (!sessions.has(event.sessionId)) {
425+
sessions.set(event.sessionId, []);
426+
}
427+
sessions.get(event.sessionId).push(event);
428+
}
429+
}
382430

383-
/**
384-
* Generate analytics report
385-
*/
386-
async generateReport(days = 30) {
387-
const data = await this.getDashboardData(days);
388-
389-
const report = {
390-
generatedAt: new Date().toISOString(),
391-
period: `${days} days`,
392-
summary: data.summary,
393-
insights: {
394-
mostPopularPage: data.topPages[0]?.page || 'N/A',
395-
topSearchTerm: data.topSearches[0]?.query || 'N/A',
396-
userEngagement: data.summary.avgSessionTime > 180 ? 'High' : 'Moderate'
397-
},
398-
recommendations: this.generateRecommendations(data)
399-
};
431+
// Analyze each session
432+
for (const [sessionId, sessionEvents] of sessions) {
433+
if (sessionEvents.length === 0) continue;
400434

401-
return report;
402-
}
435+
// Sort by timestamp
436+
sessionEvents.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp));
403437

404-
generateRecommendations(data) {
405-
const recommendations = [];
406-
407-
if (data.topSearches.length > 0) {
408-
recommendations.push({
409-
type: 'content',
410-
message: `Consider creating more content about "${data.topSearches[0].query}" - it's a popular search term`
411-
});
438+
// Track entry and exit pages
439+
const firstPage = sessionEvents[0].page;
440+
const lastPage = sessionEvents[sessionEvents.length - 1].page;
441+
442+
entryPages.set(firstPage, (entryPages.get(firstPage) || 0) + 1);
443+
exitPages.set(lastPage, (exitPages.get(lastPage) || 0) + 1);
444+
445+
// Track common paths for sessions with multiple pages
446+
if (sessionEvents.length > 1) {
447+
const pathKey = sessionEvents.map(event => event.page).join(' > ');
448+
pathSequences.set(pathKey, (pathSequences.get(pathKey) || 0) + 1);
449+
}
450+
}
412451
}
413-
414-
if (data.recentFeedback.length > 0) {
415-
const avgRating = data.recentFeedback.reduce((sum, f) => sum + f.rating, 0) / data.recentFeedback.length;
416-
if (avgRating < 4) {
417-
recommendations.push({
418-
type: 'improvement',
419-
message: 'Recent feedback suggests areas for improvement - review feedback comments'
420-
});
452+
453+
const topEntryPages = Array.from(entryPages.entries())
454+
.sort((a, b) => b[1] - a[1])
455+
.map(([page, count]) => ({ page, count }))
456+
.slice(0, 10);
457+
458+
const topExitPages = Array.from(exitPages.entries())
459+
.sort((a, b) => b[1] - a[1])
460+
.map(([page, count]) => ({ page, count }))
461+
.slice(0, 10);
462+
463+
const topPaths = Array.from(pathSequences.entries())
464+
.sort((a, b) => b[1] - a[1])
465+
.map(([path, count]) => ({ path, count }))
466+
.slice(0, 10);
467+
468+
return { topEntryPages, topExitPages, topPaths };
469+
}
470+
471+
async getPerformanceMetrics(days) {
472+
const files = await this.getRecentLogFiles(days);
473+
let totalLoadTime = 0;
474+
let totalCount = 0;
475+
476+
for (const file of files) {
477+
const events = await this.readLogFile(file);
478+
479+
for (const event of events) {
480+
if (event.type === 'page_view' && event.loadTime) {
481+
totalLoadTime += event.loadTime;
482+
totalCount++;
483+
}
421484
}
422485
}
423486

424-
return recommendations;
487+
const avgLoadTime = totalCount > 0 ? totalLoadTime / totalCount : 0;
488+
489+
return {
490+
totalLoadTime,
491+
avgLoadTime,
492+
totalCount,
493+
period: `${days} days`
494+
};
425495
}
426496
}
427497

0 commit comments

Comments
 (0)