mirror of
https://github.com/nihonbuzz/nihonbuzz-academy.git
synced 2026-01-26 05:25:37 +07:00
feat: implement Notion-like LMS (Course Player, Exam, Certificate) with R2 integration
This commit is contained in:
@@ -42,6 +42,14 @@ class CoursePlayerController extends Controller
|
||||
? Lesson::where('slug', $lessonSlug)->with('vocabularies')->firstOrFail()
|
||||
: $allLessons->first()->load('vocabularies');
|
||||
|
||||
// Navigation Logic (Next/Prev)
|
||||
$currentIndex = $allLessons->search(function ($item) use ($currentLesson) {
|
||||
return $item->id === $currentLesson->id;
|
||||
});
|
||||
|
||||
$prevLesson = $currentIndex > 0 ? $allLessons[$currentIndex - 1] : null;
|
||||
$nextLesson = $currentIndex < $allLessons->count() - 1 ? $allLessons[$currentIndex + 1] : null;
|
||||
|
||||
// Get user progress for this course
|
||||
$completedLessonsIds = UserProgress::where('user_id', $user->id)
|
||||
->whereIn('lesson_id', $allLessons->pluck('id'))
|
||||
@@ -55,42 +63,52 @@ class CoursePlayerController extends Controller
|
||||
['started_at' => now(), 'last_heartbeat_at' => now()]
|
||||
);
|
||||
|
||||
return Inertia::render('Courses/Player', [
|
||||
return Inertia::render('Courses/Learn', [
|
||||
'course' => [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
'slug' => $course->slug,
|
||||
'modules' => $course->modules->map(function ($module) use ($completedLessonsIds) {
|
||||
return [
|
||||
'id' => $module->id,
|
||||
'title' => $module->title,
|
||||
'lessons' => $module->lessons->map(function ($lesson) use ($completedLessonsIds) {
|
||||
return [
|
||||
'id' => $lesson->id,
|
||||
'title' => $lesson->title,
|
||||
'slug' => $lesson->slug,
|
||||
'type' => $lesson->type,
|
||||
'is_completed' => in_array($lesson->id, $completedLessonsIds),
|
||||
];
|
||||
})
|
||||
];
|
||||
})
|
||||
'progress_percentage' => count($allLessons) > 0 ? round((count($completedLessonsIds) / count($allLessons)) * 100) : 0,
|
||||
],
|
||||
'currentLesson' => [
|
||||
'modules' => $course->modules->map(function ($module) use ($completedLessonsIds) {
|
||||
return [
|
||||
'id' => $module->id,
|
||||
'title' => $module->title,
|
||||
'lessons' => $module->lessons->map(function ($lesson) use ($completedLessonsIds) {
|
||||
return [
|
||||
'id' => $lesson->id,
|
||||
'title' => $lesson->title,
|
||||
'slug' => $lesson->slug,
|
||||
'type' => $lesson->type,
|
||||
'duration_seconds' => $lesson->duration_seconds,
|
||||
'is_completed' => in_array($lesson->id, $completedLessonsIds),
|
||||
];
|
||||
})
|
||||
];
|
||||
}),
|
||||
'lesson' => [
|
||||
'id' => $currentLesson->id,
|
||||
'title' => $currentLesson->title,
|
||||
'slug' => $currentLesson->slug,
|
||||
'type' => $currentLesson->type,
|
||||
'content' => $currentLesson->content,
|
||||
'video_url' => $currentLesson->video_url,
|
||||
'content_pdf' => $currentLesson->content_pdf,
|
||||
// Prefer Spatie Media Library URL (R2), fallback to legacy column
|
||||
'content_pdf' => $currentLesson->getFirstMediaUrl('content_pdf') ?: $currentLesson->content_pdf,
|
||||
'duration_seconds' => $currentLesson->duration_seconds,
|
||||
'is_completed' => in_array($currentLesson->id, $completedLessonsIds),
|
||||
'vocabularies' => $currentLesson->vocabularies,
|
||||
'next_lesson_slug' => $nextLesson?->slug,
|
||||
'prev_lesson_slug' => $prevLesson?->slug,
|
||||
'attachments' => $currentLesson->getMedia('attachments')->map(function ($media) {
|
||||
return [
|
||||
'id' => $media->uuid,
|
||||
'name' => $media->file_name,
|
||||
'url' => $media->getUrl(),
|
||||
'size' => $media->human_readable_size,
|
||||
];
|
||||
}),
|
||||
],
|
||||
'progress' => [
|
||||
'completed_count' => count($completedLessonsIds),
|
||||
'total_count' => count($allLessons),
|
||||
'percentage' => count($allLessons) > 0 ? round((count($completedLessonsIds) / count($allLessons)) * 100) : 0,
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user