diff --git a/app/Http/Controllers/StudentController.php b/app/Http/Controllers/StudentController.php
index 102692b..e8bacec 100644
--- a/app/Http/Controllers/StudentController.php
+++ b/app/Http/Controllers/StudentController.php
@@ -97,19 +97,34 @@ public static function getStudentScoresForBlok($group, $cohortId, $onlyForUser =
// Pre-compute the scores for each feedback moment up to the current week.
$feedbackScores = $feedbackmomenten->mapWithKeys(function($fm) use ($scores) {
- return [$fm->id => $scores->where('feedbackmoment_id', $fm->id)->pluck('score', 'student_id')];
+ // Note that because this plucks the key to the student_id, it will overwrite any duplicate student_id's with
+ // the last one. This is fine, because we only want the last score for each student.
+ // TODO: Or do we want the highest score for each student?
+ return [
+ $fm->id => $scores->where('feedbackmoment_id', $fm->id)->mapWithKeys(function($score) {
+ return [
+ $score->student_id => [
+ 'score' => $score->score,
+ 'attempt' => $score->attempt
+ ]
+ ];
+ })->toArray()
+ ];
});
$students = $students->map(function($user) use ($blok, $group, $feedbackScores, $totalPointsToGainUntilNow, $totalBpointsToGainUntilNow) {
// Calculate total points by summing the highest scores for each feedback moment.
$totalPoints = collect($feedbackScores)->map(function ($scores, $fmId) use ($user) {
- return $scores[$user['id']] ?? 0;
+ return $scores[$user['id']]['score'] ?? 0;
})->sum();
// Prepare the scores per feedback moment for the student.
$feedbackmomentenScores = collect($feedbackScores)->mapWithKeys(function ($scores, $fmId) use ($user) {
- return [$fmId => $scores[$user['id']] ?? null];
+ return [$fmId => $scores[$user['id']] ?? [
+ 'score' => null,
+ 'attempt' => null
+ ]];
});
$totalBpoints = DB::table('student_scores_b')->where('student_id', $user['id'])->sum('score');
diff --git a/app/Livewire/Concerns/CanFloodFill.php b/app/Livewire/Concerns/CanFloodFill.php
new file mode 100644
index 0000000..4ffc6d2
--- /dev/null
+++ b/app/Livewire/Concerns/CanFloodFill.php
@@ -0,0 +1,59 @@
+students);
+ $feedbackmoment = $this->blok->vakken->pluck('feedbackmomenten')->flatten()->firstWhere('id', $feedbackmomentId);
+
+ // Count the students that have a score for this feedbackmoment and wont be affected by the floodfill
+ $studentsWithScore = 0;
+
+ foreach($this->students as $student)
+ {
+ if(isset($student->feedbackmomenten[$feedbackmomentId]['score']))
+ $studentsWithScore++;
+ }
+
+ $count = $studentCount - $studentsWithScore;
+
+ // TODO: Nice message that tells the user nobody will be affected by the floodfill
+ if ($count == 0)
+ return;
+
+ $this->floodFillCount = $count;
+ $this->floodFillSubject = $feedbackmoment;
+ $this->floodFillValue = $feedbackmoment->points;
+ }
+
+ public function doFloodFill()
+ {
+ foreach($this->students as $key => $student)
+ {
+ if(!isset($student->feedbackmomenten[$this->floodFillSubject->id]['score']))
+ {
+ $student->feedbackmomenten[$this->floodFillSubject->id] = [
+ 'attempt' => 1,
+ 'score' => $this->floodFillValue,
+ ];
+ $this->updatedStudents($this->floodFillValue, $key . '.feedbackmomenten.' . $this->floodFillSubject->id . '.score');
+ }
+ }
+
+ $this->cancelFloodFill();
+ }
+
+ public function cancelFloodFill()
+ {
+ $this->floodFillValue = -1;
+ $this->floodFillSubject = null;
+ $this->floodFillCount = null;
+ }
+}
diff --git a/app/Livewire/Concerns/CanManageAttempts.php b/app/Livewire/Concerns/CanManageAttempts.php
new file mode 100644
index 0000000..996b0c6
--- /dev/null
+++ b/app/Livewire/Concerns/CanManageAttempts.php
@@ -0,0 +1,91 @@
+students->firstWhere('id', $studentId);
+ $feedbackmoment = $this->blok->vakken->pluck('feedbackmomenten')->flatten()->firstWhere('id', $feedbackmomentId);
+
+ $this->manageAttempts = StudentScore::where('student_id', $studentId)
+ ->where('feedbackmoment_id', $feedbackmomentId)
+ ->get()
+ ->mapWithKeys(function ($score) {
+ return [
+ $score->id => [
+ 'attempt' => $score->attempt,
+ 'score' => $score->score,
+ ]
+ ];
+ })
+ ->toArray();
+ $this->manageAttemptsStudent = $student;
+ $this->manageAttemptsFeedbackmoment = $feedbackmoment;
+ }
+
+ public function removeAttempt($scoreId)
+ {
+ StudentScore::find($scoreId)->delete();
+ unset($this->manageAttempts[$scoreId]);
+ $this->updateStudentScores();
+ }
+
+ public function doManageAttempts()
+ {
+ $highestAttempt = 1;
+ foreach ($this->manageAttempts as $id => $attempt) {
+ StudentScore::find($id)->update([
+ 'attempt' => $attempt['attempt'],
+ 'score' => $attempt['score'],
+ ]);
+
+ if ($highestAttempt < $attempt['attempt']) {
+ $highestAttempt = $attempt['attempt'];
+ }
+ }
+
+ if ($this->manageAttemptsNew > -1) {
+ $updatedScores = [
+ [
+ 'student_id' => $this->manageAttemptsStudent->id,
+ 'feedbackmoment_id' => $this->manageAttemptsFeedbackmoment->id,
+ 'teacher_id' => auth()->user()->id,
+ 'score' => $this->manageAttemptsNew ?: 0,
+ 'attempt' => $highestAttempt + 1,
+ ],
+ ];
+
+ StudentScore::updateFeedbackForStudents($updatedScores);
+ $this->manageAttemptsNew = -1;
+ }
+
+ $this->cancelManageAttempts();
+ }
+
+ public function cancelManageAttempts()
+ {
+ $this->manageAttempts = [];
+ $this->manageAttemptsStudent = null;
+ $this->manageAttemptsFeedbackmoment = null;
+ $this->manageAttemptsNew = -1;
+ }
+
+ public function addNewAttempt()
+ {
+ $this->manageAttemptsNew = 0;
+ }
+
+ public function removeNewAttempt()
+ {
+ $this->manageAttemptsNew = -1;
+ }
+}
diff --git a/app/Livewire/StudyPointMatrix.php b/app/Livewire/StudyPointMatrix.php
index 4591b79..7246498 100644
--- a/app/Livewire/StudyPointMatrix.php
+++ b/app/Livewire/StudyPointMatrix.php
@@ -3,6 +3,8 @@
namespace App\Livewire;
use App\Http\Controllers\StudentController;
+use App\Livewire\Concerns\CanFloodFill;
+use App\Livewire\Concerns\CanManageAttempts;
use App\Models\StudentScore;
use App\Models\Group;
use App\Traits\SendsNotifications;
@@ -14,11 +16,17 @@
class StudyPointMatrix extends Component
{
use SendsNotifications;
+ use CanFloodFill;
+ use CanManageAttempts;
public $blok;
public $groups;
public $blokken = [];
public $students;
+ public $changedStudents = [];
+
+ #[Url(as: 'points', history: true)]
+ public $showPoints = 'a';
#[Url(as: 'group', history: true)]
public $selectedGroupId = -1;
@@ -28,10 +36,6 @@ class StudyPointMatrix extends Component
public $fbmsActive;
public $vakkenActiveB;
- public $floodFillValue = -1;
- public $floodFillCount;
- public $floodFillSubject;
-
private $selectedCohortId;
public function render()
@@ -72,6 +76,7 @@ private function updateStudentScores()
list($this->blok, $this->fbmsActive, $this->students, $this->vakkenActiveB) = StudentController::getStudentScoresForBlok($group, $selectedCohortId, blokId: $this->selectedBlokId);
$this->selectedBlokId = $this->blok->id;
+ $this->changedStudents = [];
}
public function updatedSelectedGroupId()
@@ -86,121 +91,108 @@ public function updatedSelectedBlokId()
$this->updateStudentScores();
}
- public function save()
- {
- $this->updateStudentScores();
- $this->dispatch('study-point-matrix-changed');
- }
-
- public function startFloodFill($feedbackmomentId)
+ public function updatedStudents($value, $key)
{
- $studentCount = count($this->students);
- $feedbackmoment = $this->blok->vakken->pluck('feedbackmomenten')->flatten()->firstWhere('id', $feedbackmomentId);
-
- // Count the students that have a score for this feedbackmoment and wont be affected by the floodfill
- $studentsWithScore = 0;
+ $parts = explode('.', $key);
+ $studentId = $parts[0];
+ $type = $parts[1];
- foreach($this->students as $student)
- {
- if(isset($student->feedbackmomenten[$feedbackmomentId]))
- $studentsWithScore++;
+ if ($type === 'bPointsOverview') {
+ $subjectId = $parts[count($parts) - 1];
+ } elseif ($type === 'feedbackmomenten') {
+ $subjectId = $parts[count($parts) - 2];
}
- $count = $studentCount - $studentsWithScore;
-
- // TODO: Nice message that tells the user nobody will be affected by the floodfill
- if ($count == 0)
- return;
-
- $this->floodFillCount = $count;
- $this->floodFillSubject = $feedbackmoment;
- $this->floodFillValue = $feedbackmoment->points;
+ $this->changedStudents[$studentId] = [
+ 'type' => $type,
+ 'subjectId' => $subjectId,
+ 'score' => $value,
+ ];
}
- public function doFloodFill()
+ public function save()
{
- foreach($this->students as $key => $student)
- {
- if(!isset($student->feedbackmomenten[$this->floodFillSubject->id]))
- {
- $student->feedbackmomenten[$this->floodFillSubject->id] = $this->floodFillValue;
- $this->updatedStudents($this->floodFillValue, $key . '.feedbackmomenten.' . $this->floodFillSubject->id);
+ foreach($this->changedStudents as $studentKey => $change) {
+ $student = $this->students[$studentKey];
+ $subjectId = $change['subjectId'];
+ $value = $change['score'];
+
+ if($change['type'] == 'bPointsOverview') {
+ $this->savePointsB($student, $subjectId, $value);
+ } else {
+ $this->savePointsA($student, $subjectId, $value);
}
}
- $this->cancelFloodFill();
- }
-
- public function cancelFloodFill()
- {
- $this->floodFillValue = -1;
- $this->floodFillSubject = null;
- $this->floodFillCount = null;
+ $this->changedStudents = [];
}
- public function updatedStudents($value, $key)
+ private function savePointsA($student, $feedbackmomentId, $value)
{
- $parts = explode('.', $key);
- $studentKey = $parts[0];
- $student = $this->students[$studentKey];
-
- // handle b points update
- // todo: maybe make a model out of B points...
- if($parts[1] == 'bPointsOverview') {
- $subjectId = $parts[count($parts) - 1];
- $row = DB::table('student_scores_b')
- ->where('student_id', $student->id)
- ->where('subject_id', $subjectId)
- ->first();
-
- if (!$row) {
- DB::table('student_scores_b')->insert([
- 'student_id' => $student->id,
- 'subject_id' => $subjectId,
- 'score' => $value ?: 0,
- 'teacher_id' => auth()->user()->id,
- 'created_at' => \Carbon\Carbon::now(), // Not using Eloquent, so need to handle this manually..
- 'updated_at' => \Carbon\Carbon::now(), // Not using Eloquent, so need to handle this manually..
- ]);
- return;
- }
- if ($value == null) {
- // If $value is null, delete the row
- DB::table('student_scores_b')
- ->where('student_id', $student->id)
- ->where('subject_id', $subjectId)
- ->delete();
- } else {
- // If $value is not null, update the score
- DB::table('student_scores_b')
- ->where('student_id', $student->id)
- ->where('subject_id', $subjectId)
- ->update([
- 'score' => $value,
- 'updated_at' => \Carbon\Carbon::now(), // Not using Eloquent, so need to handle this manually..
- ]);
- }
- return;
- }
-
- $feedbackmomentId = $parts[count($parts) - 1];
+ $attempt = $student->feedbackmomenten[$feedbackmomentId]['attempt'];
if($value == null)
{
- $score = StudentScore::where('student_id', $student->id)->where('feedbackmoment_id', $feedbackmomentId)->first();
+ $score = StudentScore::where('student_id', $student->id)
+ ->where('feedbackmoment_id', $feedbackmomentId)
+ ->where('attempt', $attempt)
+ ->first();
$score?->delete();
}
else
{
+ $attempt = $attempt ?? 1;
$updatedScores = [
[
'student_id' => $student->id,
'feedbackmoment_id' => $feedbackmomentId,
'teacher_id' => auth()->user()->id,
- 'score' => $value ?: 0
+ 'score' => $value ?: 0,
+ 'attempt' => $attempt,
],
];
+
StudentScore::updateFeedbackForStudents($updatedScores);
+ $student->feedbackmomenten[$feedbackmomentId]['attempt'] = $attempt;
+ }
+ }
+
+ private function savePointsB($student, $subjectId, $value)
+ {
+ // TODO: Make a model out of B points...
+ $row = DB::table('student_scores_b')
+ ->where('student_id', $student->id)
+ ->where('subject_id', $subjectId)
+ ->first();
+
+ if (!$row) {
+ DB::table('student_scores_b')->insert([
+ 'student_id' => $student->id,
+ 'subject_id' => $subjectId,
+ 'score' => $value ?: 0,
+ 'teacher_id' => auth()->user()->id,
+ 'created_at' => \Carbon\Carbon::now(), // Not using Eloquent, so need to handle this manually..
+ 'updated_at' => \Carbon\Carbon::now(), // Not using Eloquent, so need to handle this manually..
+ ]);
+
+ return;
+ }
+
+ if ($value == null) {
+ // If $value is null, delete the row
+ DB::table('student_scores_b')
+ ->where('student_id', $student->id)
+ ->where('subject_id', $subjectId)
+ ->delete();
+ } else {
+ // If $value is not null, update the score
+ DB::table('student_scores_b')
+ ->where('student_id', $student->id)
+ ->where('subject_id', $subjectId)
+ ->update([
+ 'score' => $value,
+ 'updated_at' => \Carbon\Carbon::now(), // Not using Eloquent, so need to handle this manually..
+ ]);
}
}
}
diff --git a/resources/views/components/button-icon.blade.php b/resources/views/components/button-icon.blade.php
index eeef742..d8974c6 100644
--- a/resources/views/components/button-icon.blade.php
+++ b/resources/views/components/button-icon.blade.php
@@ -1,9 +1,12 @@
+@props(['icon', 'compact' => false])
diff --git a/resources/views/components/icon/base.blade.php b/resources/views/components/icon/base.blade.php
new file mode 100644
index 0000000..9359d41
--- /dev/null
+++ b/resources/views/components/icon/base.blade.php
@@ -0,0 +1,9 @@
+@props(['compact' => false])
+
diff --git a/resources/views/components/icon/close.blade.php b/resources/views/components/icon/close.blade.php
index 3045e26..5f9fe66 100644
--- a/resources/views/components/icon/close.blade.php
+++ b/resources/views/components/icon/close.blade.php
@@ -1,5 +1,3 @@
-
+
diff --git a/resources/views/components/icon/edit.blade.php b/resources/views/components/icon/edit.blade.php
index 84a67c5..9298e87 100644
--- a/resources/views/components/icon/edit.blade.php
+++ b/resources/views/components/icon/edit.blade.php
@@ -1,5 +1,3 @@
-
+
diff --git a/resources/views/components/icon/filter.blade.php b/resources/views/components/icon/filter.blade.php
index ba9e079..631ce22 100644
--- a/resources/views/components/icon/filter.blade.php
+++ b/resources/views/components/icon/filter.blade.php
@@ -1,5 +1,3 @@
-
+
diff --git a/resources/views/components/icon/loading.blade.php b/resources/views/components/icon/loading.blade.php
index 6c40ac9..673a7c1 100644
--- a/resources/views/components/icon/loading.blade.php
+++ b/resources/views/components/icon/loading.blade.php
@@ -1,5 +1,3 @@
-
+
diff --git a/resources/views/components/icon/save.blade.php b/resources/views/components/icon/save.blade.php
index 8685721..556f1f4 100644
--- a/resources/views/components/icon/save.blade.php
+++ b/resources/views/components/icon/save.blade.php
@@ -1,5 +1,3 @@
-
+
diff --git a/resources/views/components/icon/stack.blade.php b/resources/views/components/icon/stack.blade.php
new file mode 100644
index 0000000..0c9caa9
--- /dev/null
+++ b/resources/views/components/icon/stack.blade.php
@@ -0,0 +1,3 @@
+
Je kunt deze actie niet ongedaan maken!
+ Let op! Deze wijzigingen (ook verwijderen) worden direct opgeslagen. +
+ +Dit @if (count($manageAttempts) == 1) is de poging @else zijn de pogingen @endif van {{ $manageAttemptsStudent->name }} bij {{ __('":feedbackmoment (:fb_code)"', [ + 'feedbackmoment' => $manageAttemptsFeedbackmoment->naam, + 'fb_code' => $manageAttemptsFeedbackmoment->code + ]) }}:
+ +