diff --git a/apps/dashboard/src/lib/utils/functions/number.ts b/apps/dashboard/src/lib/utils/functions/number.ts new file mode 100644 index 00000000..0e379e02 --- /dev/null +++ b/apps/dashboard/src/lib/utils/functions/number.ts @@ -0,0 +1,10 @@ +export function calcPercentageWithRounding(a: number, b: number) { + if (b === 0) { + return 0; + } + const rawPercentage = (a / b) * 100; + const fixedString = rawPercentage.toFixed(1); + const roundedNumber = parseFloat(fixedString); + + return isNaN(roundedNumber) ? 0 : roundedNumber; +} diff --git a/apps/dashboard/src/routes/api/analytics/course/+server.ts b/apps/dashboard/src/routes/api/analytics/course/+server.ts index 251ffc2c..4a649cb6 100644 --- a/apps/dashboard/src/routes/api/analytics/course/+server.ts +++ b/apps/dashboard/src/routes/api/analytics/course/+server.ts @@ -1,6 +1,7 @@ import type { CourseAnalytics, StudentOverview } from '$lib/utils/types/analytics'; import type { UserExercisesStats } from '$lib/utils/types/analytics'; +import { calcPercentageWithRounding } from '$lib/utils/functions/number.js'; import { fetchProfileCourseProgress } from '$lib/utils/services/courses'; import { getServerSupabase } from '$lib/utils/functions/supabase.server'; import { json } from '@sveltejs/kit'; @@ -193,15 +194,14 @@ async function getStudentOverview(courseId: string, member: any): Promise 0 ? Math.round((lessonsCompleted / totalLessons) * 100) : 0; + const progressPercentage = calcPercentageWithRounding(lessonsCompleted, totalLessons); // Calculate average grade using the same logic as the people page const totalEarnedPoints = userExercisesStats?.reduce((sum, exercise) => sum + exercise.score, 0) || 0; const totalPoints = userExercisesStats?.reduce((sum, exercise) => sum + exercise.totalPoints, 0) || 0; - const averageGrade = totalPoints > 0 ? Math.round((totalEarnedPoints / totalPoints) * 100) : 0; + const averageGrade = calcPercentageWithRounding(totalEarnedPoints, totalPoints); return { id: member.profile_id, diff --git a/apps/dashboard/src/routes/api/analytics/user/+server.ts b/apps/dashboard/src/routes/api/analytics/user/+server.ts index badb55b7..5b9c86ca 100644 --- a/apps/dashboard/src/routes/api/analytics/user/+server.ts +++ b/apps/dashboard/src/routes/api/analytics/user/+server.ts @@ -6,6 +6,7 @@ import type { } from '$lib/utils/types/analytics'; import { fetchCourses, fetchProfileCourseProgress } from '$lib/utils/services/courses'; +import { calcPercentageWithRounding } from '$lib/utils/functions/number'; import { getServerSupabase } from '$lib/utils/functions/supabase.server'; import { json } from '@sveltejs/kit'; @@ -42,10 +43,6 @@ function sumArrObject(arr: T[], key: keyof T) { return arr.reduce((sum, item) => sum + ((item[key] as number) || 0), 0); } -function roundNumber(a: number, b: number) { - return Math.round(a / b) * 100 || 0; -} - async function getLastLogin(userId: string): Promise { try { const { data, error } = await supabase @@ -103,14 +100,14 @@ async function getAudienceData(userId: string, orgId: string): Promise acc + course.lessons_completed, 0 ); - const overallCourseProgress = roundNumber(completedLessons, totalLessons); + const overallCourseProgress = calcPercentageWithRounding(completedLessons, totalLessons); const allGrades = sumArrObject(audienceAnalytics.courses, 'average_grade'); - const overallAverageGrade = roundNumber(allGrades, audienceAnalytics.courses.length); + const overallAverageGrade = calcPercentageWithRounding( + allGrades, + audienceAnalytics.courses.length + ); audienceAnalytics.overallCourseProgress = overallCourseProgress; audienceAnalytics.overallAverageGrade = overallAverageGrade || 0; @@ -168,30 +168,32 @@ async function getStudentAnalyticsData( userCourseAnalytics.user.lastSeen = await getLastLogin(userId); // fetch marks, lessons, and exercise progress - const [userExercisesStats, lessonCompletions, exerciseResponse] = await Promise.all([ + const [userExercisesStats, lessons, exerciseResponse] = await Promise.all([ fetchUserExercisesStats(courseId, userId), - fetchLessonCompletion(courseId, userId), + fetchLessonsWithCompletion(courseId, userId), fetchProfileCourseProgress(courseId, userId) ]); - if (!userExercisesStats || !lessonCompletions || !exerciseResponse.data) { + if (!userExercisesStats || !lessons || !exerciseResponse.data) { throw new Error('Failed to fetch course analytics data'); } const totalEarnedPoints = sumArrObject(userExercisesStats, 'score'); const totalPoints = sumArrObject(userExercisesStats, 'totalPoints'); - userCourseAnalytics.averageGrade = roundNumber(totalEarnedPoints, totalPoints); + userCourseAnalytics.averageGrade = calcPercentageWithRounding(totalEarnedPoints, totalPoints); userCourseAnalytics.userExercisesStats = userExercisesStats; - const completedLessons = lessonCompletions.filter((lesson) => lesson.completed); + const completedLessons = lessons.filter((lesson) => lesson.completed); userCourseAnalytics.totalExercises = exerciseResponse.data[0].exercises_count; userCourseAnalytics.completedExercises = exerciseResponse.data[0].exercises_completed; - userCourseAnalytics.progressPercentage = roundNumber( + console.log('completedLessons.length', completedLessons.length); + console.log('lessons.length', lessons.length); + userCourseAnalytics.progressPercentage = calcPercentageWithRounding( completedLessons.length, - lessonCompletions.length + lessons.length ); return userCourseAnalytics; @@ -250,7 +252,7 @@ async function fetchUserExercisesStats( } } -async function fetchLessonCompletion(courseId, userId) { +async function fetchLessonsWithCompletion(courseId, userId) { try { const { data: lessons, error: lessonsError } = await supabase .from('lesson')