@memberjunction/actions-bizapps-lms
Version:
LMS system integration actions for MemberJunction
334 lines • 15.1 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GetCourseAnalyticsAction = void 0;
const global_1 = require("@memberjunction/global");
const learnworlds_base_action_1 = require("../learnworlds-base.action");
const actions_1 = require("@memberjunction/actions");
/**
* Action to retrieve comprehensive analytics for a LearnWorlds course
*/
let GetCourseAnalyticsAction = class GetCourseAnalyticsAction extends learnworlds_base_action_1.LearnWorldsBaseAction {
/**
* Get course performance analytics
*/
async InternalRunAction(params) {
const { Params, ContextUser } = params;
this.params = Params;
try {
// Extract and validate parameters
const courseId = this.getParamValue(Params, 'CourseID');
const dateFrom = this.getParamValue(Params, 'DateFrom');
const dateTo = this.getParamValue(Params, 'DateTo');
const includeUserBreakdown = this.getParamValue(Params, 'IncludeUserBreakdown') === true;
const includeModuleStats = this.getParamValue(Params, 'IncludeModuleStats') !== false;
const includeRevenue = this.getParamValue(Params, 'IncludeRevenue') !== false;
if (!courseId) {
return {
Success: false,
ResultCode: 'VALIDATION_ERROR',
Message: 'CourseID is required',
Params
};
}
// Build query parameters
const queryParams = {};
if (dateFrom) {
queryParams.date_from = new Date(dateFrom).toISOString().split('T')[0];
}
if (dateTo) {
queryParams.date_to = new Date(dateTo).toISOString().split('T')[0];
}
// Build query string
const queryString = Object.keys(queryParams).length > 0
? '?' + new URLSearchParams(queryParams).toString()
: '';
// Get course analytics
const analyticsResponse = await this.makeLearnWorldsRequest(`/courses/${courseId}/analytics${queryString}`, 'GET', null, ContextUser);
if (!analyticsResponse.success) {
return {
Success: false,
ResultCode: 'API_ERROR',
Message: analyticsResponse.message || 'Failed to retrieve analytics',
Params
};
}
const analyticsData = analyticsResponse.data || {};
// Format analytics data
const analytics = {
courseId: courseId,
period: {
from: dateFrom || 'all-time',
to: dateTo || 'current'
},
enrollment: {
totalEnrollments: analyticsData.total_enrollments || 0,
newEnrollments: analyticsData.new_enrollments || 0,
activeStudents: analyticsData.active_students || 0,
enrollmentTrend: analyticsData.enrollment_trend || []
},
progress: {
averageProgressPercentage: analyticsData.average_progress || 0,
completionRate: analyticsData.completion_rate || 0,
totalCompletions: analyticsData.total_completions || 0,
inProgressCount: analyticsData.in_progress_count || 0,
notStartedCount: analyticsData.not_started_count || 0,
dropoutRate: analyticsData.dropout_rate || 0
},
engagement: {
averageTimeSpent: analyticsData.average_time_spent || 0,
averageTimeSpentText: this.formatDuration(analyticsData.average_time_spent || 0),
totalTimeSpent: analyticsData.total_time_spent || 0,
totalTimeSpentText: this.formatDuration(analyticsData.total_time_spent || 0),
averageSessionDuration: analyticsData.average_session_duration || 0,
lastActivityDate: analyticsData.last_activity_date,
dailyActiveUsers: analyticsData.daily_active_users || []
},
performance: {
averageQuizScore: analyticsData.average_quiz_score || 0,
passRate: analyticsData.pass_rate || 0,
certificatesIssued: analyticsData.certificates_issued || 0,
averageTimeToComplete: analyticsData.average_time_to_complete || 0,
averageTimeToCompleteText: this.formatDuration(analyticsData.average_time_to_complete || 0)
}
};
// Get revenue analytics if requested
if (includeRevenue) {
const revenueResponse = await this.makeLearnWorldsRequest(`/courses/${courseId}/revenue${queryString}`, 'GET', null, ContextUser);
if (revenueResponse.success && revenueResponse.data) {
analytics.revenue = {
totalRevenue: revenueResponse.data.total_revenue || 0,
currency: revenueResponse.data.currency || 'USD',
averageOrderValue: revenueResponse.data.average_order_value || 0,
totalOrders: revenueResponse.data.total_orders || 0,
revenueTrend: revenueResponse.data.revenue_trend || [],
topMarkets: revenueResponse.data.top_markets || []
};
}
}
// Get module/lesson stats if requested
if (includeModuleStats) {
const moduleStatsResponse = await this.makeLearnWorldsRequest(`/courses/${courseId}/modules/analytics`, 'GET', null, ContextUser);
if (moduleStatsResponse.success && moduleStatsResponse.data) {
analytics.moduleStats = this.formatModuleStats(moduleStatsResponse.data.data || moduleStatsResponse.data);
}
}
// Get user breakdown if requested
if (includeUserBreakdown) {
const enrollmentQueryString = '?' + new URLSearchParams({ limit: '1000', include: 'progress' }).toString();
const userBreakdownResponse = await this.makeLearnWorldsRequest(`/courses/${courseId}/enrollments${enrollmentQueryString}`, 'GET', null, ContextUser);
if (userBreakdownResponse.success && userBreakdownResponse.data) {
const enrollments = userBreakdownResponse.data.data || userBreakdownResponse.data;
analytics.userBreakdown = this.calculateUserBreakdown(enrollments);
}
}
// Create summary
const summary = {
courseId: courseId,
period: analytics.period,
keyMetrics: {
totalEnrollments: analytics.enrollment.totalEnrollments,
completionRate: analytics.progress.completionRate,
averageProgress: analytics.progress.averageProgressPercentage,
activeStudents: analytics.enrollment.activeStudents,
averageTimeSpent: analytics.engagement.averageTimeSpentText,
certificatesIssued: analytics.performance.certificatesIssued
},
trends: {
enrollmentGrowth: this.calculateGrowthRate(analytics.enrollment.enrollmentTrend),
engagementTrend: this.calculateEngagementTrend(analytics.engagement.dailyActiveUsers),
completionTrend: 'stable' // Would calculate from historical data
}
};
// Update output parameters
const outputParams = [...Params];
const courseAnalyticsParam = outputParams.find(p => p.Name === 'CourseAnalytics');
if (courseAnalyticsParam) {
courseAnalyticsParam.Value = analytics;
}
const summaryParam = outputParams.find(p => p.Name === 'Summary');
if (summaryParam) {
summaryParam.Value = summary;
}
return {
Success: true,
ResultCode: 'SUCCESS',
Message: 'Course analytics retrieved successfully',
Params: outputParams
};
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
return {
Success: false,
ResultCode: 'EXECUTION_ERROR',
Message: `Error retrieving course analytics: ${errorMessage}`,
Params
};
}
}
/**
* Format module statistics
*/
formatModuleStats(modules) {
return modules.map(module => ({
moduleId: module.id,
moduleTitle: module.title,
completionRate: module.completion_rate || 0,
averageProgress: module.average_progress || 0,
averageTimeSpent: module.average_time_spent || 0,
averageTimeSpentText: this.formatDuration(module.average_time_spent || 0),
studentsStarted: module.students_started || 0,
studentsCompleted: module.students_completed || 0,
lessons: module.lessons?.map((lesson) => ({
lessonId: lesson.id,
lessonTitle: lesson.title,
completionRate: lesson.completion_rate || 0,
averageTimeSpent: lesson.average_time_spent || 0,
viewCount: lesson.view_count || 0
})) || []
}));
}
/**
* Calculate user breakdown statistics
*/
calculateUserBreakdown(enrollments) {
const progressBuckets = {
notStarted: 0,
under25: 0,
between25And50: 0,
between50And75: 0,
between75And99: 0,
completed: 0
};
enrollments.forEach(enrollment => {
const progress = enrollment.progress_percentage || 0;
if (progress === 0)
progressBuckets.notStarted++;
else if (progress < 25)
progressBuckets.under25++;
else if (progress < 50)
progressBuckets.between25And50++;
else if (progress < 75)
progressBuckets.between50And75++;
else if (progress < 100)
progressBuckets.between75And99++;
else
progressBuckets.completed++;
});
return {
total: enrollments.length,
progressDistribution: progressBuckets,
percentageDistribution: {
notStarted: (progressBuckets.notStarted / enrollments.length * 100).toFixed(1),
under25: (progressBuckets.under25 / enrollments.length * 100).toFixed(1),
between25And50: (progressBuckets.between25And50 / enrollments.length * 100).toFixed(1),
between50And75: (progressBuckets.between50And75 / enrollments.length * 100).toFixed(1),
between75And99: (progressBuckets.between75And99 / enrollments.length * 100).toFixed(1),
completed: (progressBuckets.completed / enrollments.length * 100).toFixed(1)
}
};
}
/**
* Calculate growth rate from trend data
*/
calculateGrowthRate(trend) {
if (!trend || trend.length < 2)
return 'insufficient-data';
const recent = trend[trend.length - 1]?.value || 0;
const previous = trend[trend.length - 2]?.value || 0;
if (previous === 0)
return 'new';
const growthRate = ((recent - previous) / previous) * 100;
if (growthRate > 10)
return 'high-growth';
if (growthRate > 0)
return 'growing';
if (growthRate === 0)
return 'stable';
return 'declining';
}
/**
* Calculate engagement trend
*/
calculateEngagementTrend(dailyActiveUsers) {
if (!dailyActiveUsers || dailyActiveUsers.length < 7)
return 'insufficient-data';
// Simple trend calculation based on last 7 days
const recentAvg = dailyActiveUsers.slice(-7).reduce((sum, day) => sum + (day.value || 0), 0) / 7;
const previousAvg = dailyActiveUsers.slice(-14, -7).reduce((sum, day) => sum + (day.value || 0), 0) / 7;
if (previousAvg === 0)
return 'new';
const change = ((recentAvg - previousAvg) / previousAvg) * 100;
if (change > 5)
return 'increasing';
if (change < -5)
return 'decreasing';
return 'stable';
}
/**
* Define the parameters this action expects
*/
get Params() {
const baseParams = this.getCommonLMSParams();
const specificParams = [
{
Name: 'CourseID',
Type: 'Input',
Value: null
},
{
Name: 'DateFrom',
Type: 'Input',
Value: null
},
{
Name: 'DateTo',
Type: 'Input',
Value: null
},
{
Name: 'IncludeUserBreakdown',
Type: 'Input',
Value: false
},
{
Name: 'IncludeModuleStats',
Type: 'Input',
Value: true
},
{
Name: 'IncludeRevenue',
Type: 'Input',
Value: true
},
{
Name: 'CourseAnalytics',
Type: 'Output',
Value: null
},
{
Name: 'Summary',
Type: 'Output',
Value: null
}
];
return [...baseParams, ...specificParams];
}
/**
* Metadata about this action
*/
get Description() {
return 'Retrieves comprehensive analytics and performance metrics for a LearnWorlds course';
}
};
exports.GetCourseAnalyticsAction = GetCourseAnalyticsAction;
exports.GetCourseAnalyticsAction = GetCourseAnalyticsAction = __decorate([
(0, global_1.RegisterClass)(actions_1.BaseAction, 'GetCourseAnalyticsAction')
], GetCourseAnalyticsAction);
//# sourceMappingURL=get-course-analytics.action.js.map