feat: implement Learning Tracer (heartbeat duration tracking) for LPK Audit

This commit is contained in:
2026-01-23 19:06:32 +07:00
parent 8a61cda3e4
commit 6caa0e88dd
5 changed files with 85 additions and 0 deletions

View File

@@ -45,9 +45,16 @@ class CoursePlayerController extends Controller
// Get user progress for this course
$completedLessonsIds = UserProgress::where('user_id', $user->id)
->whereIn('lesson_id', $allLessons->pluck('id'))
->whereNotNull('completed_at')
->pluck('lesson_id')
->toArray();
// Initialize started_at if first time viewing
UserProgress::firstOrCreate(
['user_id' => $user->id, 'lesson_id' => $currentLesson->id],
['started_at' => now(), 'last_heartbeat_at' => now()]
);
return Inertia::render('Courses/Player', [
'course' => [
'id' => $course->id,
@@ -109,4 +116,33 @@ class CoursePlayerController extends Controller
return back()->with('success', 'Materi selesai! +50 XP');
}
/**
* Update learning duration via heartbeat.
*/
public function heartbeat(Request $request, Lesson $lesson)
{
$user = $request->user();
$now = now();
$progress = UserProgress::firstOrCreate(
['user_id' => $user->id, 'lesson_id' => $lesson->id],
['started_at' => $now, 'last_heartbeat_at' => $now]
);
$lastHeartbeat = $progress->last_heartbeat_at ?? $progress->created_at;
$diffSeconds = $now->diffInSeconds($lastHeartbeat);
// Limit diff to prevent massive jumps (e.g. if user leaves tab open and comes back hours later)
// Max 90 seconds per heartbeat (assuming heartbeat is every 60s)
$increment = min($diffSeconds, 90);
$progress->increment('time_spent_seconds', $increment);
$progress->update(['last_heartbeat_at' => $now]);
return response()->json([
'status' => 'success',
'time_spent' => $progress->time_spent_seconds,
]);
}
}