Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
93.22% |
55 / 59 |
|
60.00% |
3 / 5 |
CRAP | |
0.00% |
0 / 1 |
DashboardMetricService | |
93.22% |
55 / 59 |
|
60.00% |
3 / 5 |
20.12 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
getProgressionStats | |
91.30% |
21 / 23 |
|
0.00% |
0 / 1 |
8.04 | |||
getConversationStatsForPeriod | |
81.82% |
9 / 11 |
|
0.00% |
0 / 1 |
4.10 | |||
getHistoricalWeeklyAverageStats | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
4 | |||
calculateEvolution | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | |
3 | namespace App\Services\RolePlay; |
4 | |
5 | use App\Http\Models\Auth\User; |
6 | use App\Http\Models\RolePlayConversations; |
7 | use App\Http\Models\RolePlayProjects; |
8 | use App\Http\Models\RolePlaySkillProgressions; |
9 | use Carbon\Carbon; |
10 | use MongoDB\BSON\UTCDateTime; |
11 | |
12 | class DashboardMetricService |
13 | { |
14 | protected RolePlayConversations $conversationModel; |
15 | protected RolePlaySkillProgressions $skillProgressionModel; |
16 | protected RolePlayProjects $projectModel; |
17 | |
18 | public function __construct( |
19 | RolePlayConversations $conversationModel, |
20 | RolePlaySkillProgressions $skillProgressionModel, |
21 | RolePlayProjects $projectModel |
22 | ) { |
23 | $this->conversationModel = $conversationModel; |
24 | $this->skillProgressionModel = $skillProgressionModel; |
25 | $this->projectModel = $projectModel; |
26 | } |
27 | |
28 | public function getProgressionStats(User $user): array |
29 | { |
30 | $skillProgressions = $this->skillProgressionModel->where('status', 'active')->get(); |
31 | |
32 | $criterias = []; |
33 | |
34 | foreach ($skillProgressions as $progression) { |
35 | if (empty($progression->scorecard_config) || !is_array($progression->scorecard_config)) { |
36 | continue; |
37 | } |
38 | |
39 | foreach ($progression->scorecard_config as $config) { |
40 | $projects = $this->projectModel->where('user_id', $user->id)->where('type', $progression->type)->get(); |
41 | |
42 | foreach ($projects as $project) { |
43 | $progressions = $project->progression ?? []; |
44 | |
45 | $progress = collect($progressions)->first(function ($prog) use ($config) { |
46 | return $prog['name'] === $config['name']; |
47 | }); |
48 | |
49 | $existentCriteria = collect($criterias)->first(function ($crit) use ($config, $progression) { |
50 | return $crit['name'] === $config['name'] && $crit['type'] === $progression->type; |
51 | }); |
52 | |
53 | if ($existentCriteria) { |
54 | $existentCriteria['score'] = ($existentCriteria['score'] + ($progress['score'] ?? 0)) / 2; |
55 | } else { |
56 | $criterias[] = [ |
57 | 'type' => $progression->type, |
58 | 'name' => $config['name'], |
59 | 'score' => $progress['score'] ?? 0, |
60 | ]; |
61 | } |
62 | } |
63 | } |
64 | } |
65 | |
66 | return $criterias; |
67 | } |
68 | |
69 | public function getConversationStatsForPeriod(User $user, ?Carbon $startDate, ?Carbon $endDate): array |
70 | { |
71 | $query = $this->conversationModel->where('user_id', $user->id); |
72 | |
73 | if ($startDate && $endDate) { |
74 | $query->where('created_at', '>=', new UTCDateTime(strtotime($startDate->toDateString()) * 1000)) |
75 | ->where('created_at', '<=', new UTCDateTime(strtotime($endDate->toDateString()) * 1000)); |
76 | } elseif ($endDate) { |
77 | $query->where('created_at', '<', new UTCDateTime(strtotime($endDate->toDateString()) * 1000)); |
78 | } |
79 | |
80 | return [ |
81 | 'conversationsCount' => $query->clone()->count() ?? 0, |
82 | 'practiceTimeSeconds' => $query->clone()->sum('duration') ?? 0, |
83 | 'averageScore' => round($query->clone()->avg('score') ?? 0, 2), |
84 | ]; |
85 | } |
86 | |
87 | public function getHistoricalWeeklyAverageStats(User $user): array |
88 | { |
89 | $historicalQuery = $this->conversationModel->where('user_id', $user->id) |
90 | ->where('created_at', '<', now()->startOfWeek()->subWeek()); |
91 | |
92 | $firstRecord = $historicalQuery->clone()->orderBy('created_at', 'asc')->first(); |
93 | |
94 | if (!$firstRecord) { |
95 | return [ |
96 | 'conversationsCount' => 0, |
97 | 'practiceTimeSeconds' => 0, |
98 | 'averageScore' => 0, |
99 | ]; |
100 | } |
101 | |
102 | $lastRecordDate = $historicalQuery->clone()->orderBy('created_at', 'desc')->first()->created_at; |
103 | $totalWeeks = ($firstRecord->created_at->diffInWeeks($lastRecordDate) ?? 0) + 1; |
104 | |
105 | $totalConversations = $historicalQuery->clone()->count() ?? 0; |
106 | $totalPracticeTime = $historicalQuery->clone()->sum('duration') ?? 0; |
107 | |
108 | return [ |
109 | 'conversationsCount' => $totalWeeks > 0 ? $totalConversations / $totalWeeks : 0, |
110 | 'practiceTimeSeconds' => $totalWeeks > 0 ? $totalPracticeTime / $totalWeeks : 0, |
111 | 'averageScore' => round($historicalQuery->clone()->avg('score') ?? 0, 2), |
112 | ]; |
113 | } |
114 | |
115 | public function calculateEvolution(float $current, float $previous): float |
116 | { |
117 | if ($previous == 0) { |
118 | return $current > 0 ? 100.00 : 0.00; |
119 | } |
120 | |
121 | $evolution = (($current - $previous) / $previous) * 100; |
122 | |
123 | return round($evolution, 2); |
124 | } |
125 | } |