@basicsu/courses-mcp
Version:
Interactive programming courses from Basics - MCP server for Cursor
140 lines • 6.56 kB
JavaScript
// Hierarchical Progress Calculation
import { getCourseModules, getCourseLessons, getLessonSteps } from './database-helper.js';
import { createClient } from '@supabase/supabase-js';
const SUPABASE_URL = 'https://mqvlccclucfewgtmhyiv.supabase.co';
const SUPABASE_ANON_KEY = 'sb_publishable_MiRSlSxgvZ_D_VeB3-73Mw_gtReq_yT';
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
export async function calculateHierarchicalProgress(userProfileId, courseId, currentModuleId, currentLessonId, currentStepId) {
// Get course structure
const allModules = await getCourseModules(courseId);
const currentModuleIndex = allModules.findIndex(m => m.id === currentModuleId);
const currentModule = allModules[currentModuleIndex];
const allLessonsInModule = await getCourseLessons(currentModuleId);
const currentLessonIndex = allLessonsInModule.findIndex(l => l.id === currentLessonId);
const currentLesson = allLessonsInModule[currentLessonIndex];
const allStepsInLesson = await getLessonSteps(currentLessonId);
const currentStepIndex = currentStepId ? allStepsInLesson.findIndex(s => s.id === currentStepId) : -1;
const currentStep = currentStepId ? allStepsInLesson[currentStepIndex] : allStepsInLesson[0] || null;
// Calculate total course structure
let totalLessons = 0;
let totalSteps = 0;
for (const module of allModules) {
const moduleLessons = await getCourseLessons(module.id);
totalLessons += moduleLessons.length;
for (const lesson of moduleLessons) {
const lessonSteps = await getLessonSteps(lesson.id);
totalSteps += lessonSteps.length;
}
}
// Get user's completed steps from database (using profile ID directly)
const { data: completedSteps } = await supabase
.from('user_step_progress')
.select('step_id')
.eq('user_id', userProfileId);
const completedStepIds = new Set((completedSteps || []).map(s => s.step_id));
// Calculate completed lessons and modules
let completedLessons = 0;
let completedModules = 0;
let currentModuleCompletedLessons = 0;
for (let i = 0; i < allModules.length; i++) {
const module = allModules[i];
const moduleLessons = await getCourseLessons(module.id);
let moduleCompletedLessons = 0;
for (let j = 0; j < moduleLessons.length; j++) {
const lesson = moduleLessons[j];
const lessonSteps = await getLessonSteps(lesson.id);
if (lessonSteps.length === 0) {
// No steps means lesson is incomplete (has no content)
// Don't count as completed
}
else {
// Count completed steps in this lesson
const completedStepsInLesson = lessonSteps.filter(step => completedStepIds.has(step.id)).length;
if (completedStepsInLesson === lessonSteps.length) {
// All steps completed = lesson complete
moduleCompletedLessons++;
if (i < currentModuleIndex)
completedLessons++;
}
else if (i === currentModuleIndex && j < currentLessonIndex) {
// Previous lessons in current module should be complete if we're past them
// But only if they have steps
if (lessonSteps.length > 0) {
moduleCompletedLessons++;
}
}
}
}
if (i === currentModuleIndex) {
currentModuleCompletedLessons = moduleCompletedLessons;
}
if (moduleCompletedLessons === moduleLessons.length && moduleLessons.length > 0) {
completedModules++;
}
}
// Calculate progress at each level
const stepProgress = {
completed: completedStepIds.size,
total: totalSteps,
percentage: totalSteps > 0 ? Math.round((completedStepIds.size / totalSteps) * 100) : 0
};
// Current lesson progress (steps within current lesson)
const completedStepsInCurrentLesson = allStepsInLesson.filter(step => completedStepIds.has(step.id)).length;
const currentLessonStepPercentage = allStepsInLesson.length > 0 ?
Math.round((completedStepsInCurrentLesson / allStepsInLesson.length) * 100) : 100;
const lessonProgress = {
completed: completedLessons,
total: totalLessons,
percentage: totalLessons > 0 ? Math.round((completedLessons / totalLessons) * 100) : 0,
currentLessonPercentage: currentLessonStepPercentage
};
// Current module progress (lessons within current module + partial current lesson)
const moduleProgressWithCurrent = currentModuleCompletedLessons + (currentLessonStepPercentage / 100);
const currentModulePercentage = allLessonsInModule.length > 0 ?
Math.round((moduleProgressWithCurrent / allLessonsInModule.length) * 100) : 0;
const moduleProgress = {
completed: completedModules,
total: allModules.length,
percentage: allModules.length > 0 ? Math.round((completedModules / allModules.length) * 100) : 0,
currentModulePercentage
};
// Overall course progress (hierarchical) - based on modules
const courseProgressWithCurrent = completedModules + (currentModulePercentage / 100);
const coursePercentage = allModules.length > 0 ?
Math.round((courseProgressWithCurrent / allModules.length) * 100) : 0;
const courseProgress = {
completed: completedModules,
total: allModules.length,
percentage: coursePercentage
};
return {
currentModule: {
id: currentModule.id,
title: currentModule.title,
index: currentModuleIndex,
totalModules: allModules.length
},
currentLesson: {
id: currentLesson.id,
title: currentLesson.title,
index: currentLessonIndex,
totalLessons: allLessonsInModule.length
},
currentStep: currentStep ? {
id: currentStep.id,
title: currentStep.title,
index: currentStepIndex,
totalSteps: allStepsInLesson.length
} : {
id: null,
title: 'No steps in this lesson',
index: -1,
totalSteps: allStepsInLesson.length
},
stepProgress,
lessonProgress,
moduleProgress,
courseProgress
};
}
//# sourceMappingURL=hierarchical-progress.js.map