feat: setup drizzle (#594)

* chore: migration to SvelteKit 2

* stage 1: migrate to svelte 5 and fix rerendering issues

* stage 2: fix more $: reactivity across dashboard

* fix merge conflicts

* chore: migrate code in main to svelte 5

* chore: update preventDefault

* chore: simplify tsconfig and remove unused mobileMenuRef in MobileMenu.svelte

* chore: enforce .ts across dashboard

* rename from classroomio-com to website

* stage-3: Replace carbon icon svelte with lucide icon

* update lock file

* chore: finish icon replacement

* fix: settings and setup page multiple rerender

* stage 3: More icon and rerendering fixes

* feat: setup drizzle and better auth

* fix: onboarding validation error showing translation key #586 (#593)

* fix: onboarding validation error showing translation key #586

* fix: remove debug log for profile update errors

* chore: add a clean command

* fix: remove message from email verification response
This commit is contained in:
Rotimi Best
2025-11-01 15:49:29 +01:00
committed by GitHub
parent 97fb446df5
commit b96d91cd7c
801 changed files with 22279 additions and 10834 deletions
@@ -79,9 +79,7 @@ async function getCourseAnalytics(courseId: string): Promise<CourseAnalytics> {
// Count tutors and students
const members = (courseData.group as any)?.members || [];
analytics.totalTutors = members.filter(
(member) => member.role_id === 1 || member.role_id === 2
).length;
analytics.totalTutors = members.filter((member) => member.role_id === 1 || member.role_id === 2).length;
analytics.totalStudents = members.filter((member) => member.role_id === 3).length;
// Count lessons and exercises
@@ -91,35 +89,27 @@ async function getCourseAnalytics(courseId: string): Promise<CourseAnalytics> {
// Get student analytics
const studentAnalytics = await Promise.all(
members
.filter((member) => member.role_id === 3)
.map((member) => getStudentOverview(courseId, member))
members.filter((member) => member.role_id === 3).map((member) => getStudentOverview(courseId, member))
);
analytics.students = studentAnalytics.filter(
(student): student is StudentOverview => student !== null
);
analytics.students = studentAnalytics.filter((student): student is StudentOverview => student !== null);
// Calculate aggregated metrics
if (analytics.students.length > 0) {
analytics.lessonCompletionRate = Math.round(
analytics.students.reduce((sum, student) => sum + student.progressPercentage, 0) /
analytics.students.length
analytics.students.reduce((sum, student) => sum + student.progressPercentage, 0) / analytics.students.length
);
analytics.exerciseCompletionRate = Math.round(
analytics.students.reduce((sum, student) => {
const completionRate =
student.totalExercises > 0
? (student.exercisesSubmitted / student.totalExercises) * 100
: 0;
student.totalExercises > 0 ? (student.exercisesSubmitted / student.totalExercises) * 100 : 0;
return sum + completionRate;
}, 0) / analytics.students.length
);
analytics.averageGrade = Math.round(
analytics.students.reduce((sum, student) => sum + student.averageGrade, 0) /
analytics.students.length
analytics.students.reduce((sum, student) => sum + student.averageGrade, 0) / analytics.students.length
);
}
@@ -167,8 +157,7 @@ async function getStudentOverview(courseId: string, member: any): Promise<Studen
const userExercisesStats = await fetchUserExercisesStats(courseId, member.profile_id);
// Calculate exercise completion using the same logic as people page
const completedExercises =
userExercisesStats?.filter((exercise) => exercise.isCompleted)?.length || 0;
const completedExercises = userExercisesStats?.filter((exercise) => exercise.isCompleted)?.length || 0;
const totalExercises = userExercisesStats?.length || 0;
// Get last login using the same approach as analytics/user API
@@ -197,10 +186,8 @@ async function getStudentOverview(courseId: string, member: any): Promise<Studen
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 totalEarnedPoints = userExercisesStats?.reduce((sum, exercise) => sum + exercise.score, 0) || 0;
const totalPoints = userExercisesStats?.reduce((sum, exercise) => sum + exercise.totalPoints, 0) || 0;
const averageGrade = calcPercentageWithRounding(totalEarnedPoints, totalPoints);
return {
@@ -224,10 +211,7 @@ async function getStudentOverview(courseId: string, member: any): Promise<Studen
}
}
async function fetchUserExercisesStats(
courseId: string,
userId: string
): Promise<UserExercisesStats[] | undefined> {
async function fetchUserExercisesStats(courseId: string, userId: string): Promise<UserExercisesStats[] | undefined> {
try {
const { data: courseData, error: queryError } = await supabase
.from('course')