Allow admin and tabulators to enter and modify prelim scores.
This commit is contained in:
parent
62a3694c03
commit
30cbaf69f8
|
|
@ -2,11 +2,13 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Tabulation;
|
namespace App\Http\Controllers\Tabulation;
|
||||||
|
|
||||||
|
use App\Actions\Tabulation\EnterPrelimScore;
|
||||||
use App\Actions\Tabulation\EnterScore;
|
use App\Actions\Tabulation\EnterScore;
|
||||||
use App\Exceptions\AuditionAdminException;
|
use App\Exceptions\AuditionAdminException;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Entry;
|
use App\Models\Entry;
|
||||||
use App\Models\EntryTotalScore;
|
use App\Models\EntryTotalScore;
|
||||||
|
use App\Models\PrelimScoreSheet;
|
||||||
use App\Models\ScoreSheet;
|
use App\Models\ScoreSheet;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -67,8 +69,25 @@ class ScoreController extends Controller
|
||||||
'This entry is marked as a no-show. Entering a score will remove the no-show flag');
|
'This entry is marked as a no-show. Entering a score will remove the no-show flag');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($entry->audition->prelimDefinition) {
|
||||||
|
$existing_prelim_sheets = [];
|
||||||
|
$prelim_subscores = $entry->audition->prelimDefinition->scoringGuide->subscores->sortBy('display_order');
|
||||||
|
$prelim_judges = $entry->audition->prelimDefinition->room->judges;
|
||||||
|
foreach ($prelim_judges as $judge) {
|
||||||
|
$prelim_scoreSheet = PrelimScoreSheet::where('entry_id', $entry->id)->where('user_id', $judge->id)->first();
|
||||||
|
if ($prelim_scoreSheet) {
|
||||||
|
Session::flash('caution', 'Prelim scores exist for this entry. Now editing existing scores');
|
||||||
|
$existing_prelim_sheets[$judge->id] = $prelim_scoreSheet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$prelim_subscores = null;
|
||||||
|
$prelim_judges = null;
|
||||||
|
$existing_prelim_sheets = null;
|
||||||
|
}
|
||||||
|
|
||||||
return view('tabulation.entry_score_sheet',
|
return view('tabulation.entry_score_sheet',
|
||||||
compact('entry', 'judges', 'scoring_guide', 'subscores', 'existing_sheets'));
|
compact('entry', 'judges', 'scoring_guide', 'subscores', 'existing_sheets', 'prelim_subscores', 'prelim_judges', 'existing_prelim_sheets'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveEntryScoreSheet(Request $request, Entry $entry, EnterScore $scoreRecorder)
|
public function saveEntryScoreSheet(Request $request, Entry $entry, EnterScore $scoreRecorder)
|
||||||
|
|
@ -85,7 +104,7 @@ class ScoreController extends Controller
|
||||||
* The array should have a key for each subscore and the value of the score submitted
|
* The array should have a key for each subscore and the value of the score submitted
|
||||||
*/
|
*/
|
||||||
foreach ($request->all() as $key => $value) {
|
foreach ($request->all() as $key => $value) {
|
||||||
// We're not interested in submission values that don't ahve judge in the name
|
// We're not interested in submission values that don't have judge in the name
|
||||||
if (! str_contains($key, 'judge')) {
|
if (! str_contains($key, 'judge')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -114,6 +133,50 @@ class ScoreController extends Controller
|
||||||
return redirect()->route('scores.chooseEntry')->with('success', 'Scores saved');
|
return redirect()->route('scores.chooseEntry')->with('success', 'Scores saved');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function savePrelimEntryScoreSheet(Request $request, Entry $entry, EnterPrelimScore $scoreRecorder)
|
||||||
|
{
|
||||||
|
$publishedCheck = $this->checkIfPublished($entry);
|
||||||
|
if ($publishedCheck) {
|
||||||
|
return $publishedCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Here we process the submission from the scoring form.
|
||||||
|
* We're expecting submitted data to include an array for each judge.
|
||||||
|
* Each array should be called judge+ the judges ID number
|
||||||
|
* The array should have a key for each subscore and the value of the score submitted
|
||||||
|
*/
|
||||||
|
foreach ($request->all() as $key => $value) {
|
||||||
|
// We're not interested in submission values that don't have judge in the name
|
||||||
|
if (! str_contains($key, 'judge')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Extract the judge ID from the field name and load the user
|
||||||
|
$judge_id = str_replace('judge', '', $key);
|
||||||
|
$judge = User::find($judge_id);
|
||||||
|
|
||||||
|
// Check for existing scores, if so, tell EnterScores action that we're updating it, otherwise a new score
|
||||||
|
$existingScore = PrelimScoreSheet::where('entry_id', $entry->id)
|
||||||
|
->where('user_id', $judge->id)->first();
|
||||||
|
if ($existingScore === null) {
|
||||||
|
$existingScore = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$scoreRecorder($judge, $entry, $value, $existingScore);
|
||||||
|
} catch (AuditionAdminException $e) {
|
||||||
|
return redirect()->route('scores.entryScoreSheet', ['entry_id' => $entry->id])
|
||||||
|
->with('error', $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we're entering a score, this apparently isn't a no show.
|
||||||
|
$entry->removeFlag('no_show');
|
||||||
|
|
||||||
|
return redirect()->route('scores.chooseEntry')->with('success', 'Prelim Scores Saved');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected function checkIfPublished($entry)
|
protected function checkIfPublished($entry)
|
||||||
{
|
{
|
||||||
// We're not going to enter scores if seats are published
|
// We're not going to enter scores if seats are published
|
||||||
|
|
|
||||||
|
|
@ -25,4 +25,10 @@ class PrelimScoreSheet extends Model
|
||||||
{
|
{
|
||||||
return $this->hasOne(Entry::class);
|
return $this->hasOne(Entry::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSubscore($id)
|
||||||
|
{
|
||||||
|
return $this->subscores[$id]['score'] ?? false;
|
||||||
|
// this function is used at resources/views/tabulation/entry_score_sheet.blade.php
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,17 @@
|
||||||
<x-slot:page_title>Entry Score Sheet</x-slot:page_title>
|
<x-slot:page_title>Entry Score Sheet</x-slot:page_title>
|
||||||
<x-card.card class="mx-auto max-w-7xl">
|
<x-card.card class="mx-auto max-w-7xl">
|
||||||
<x-card.heading>
|
<x-card.heading>
|
||||||
{{ $entry->audition->name }} #{{ $entry->draw_number }}
|
{{ $entry->audition->name }} #{{ $entry->draw_number }} FINALS SCORES
|
||||||
|
@if($entry->hasFlag('failed_prelim'))
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center rounded-md bg-red-100 px-2 py-1 text-sm font-medium text-red-700 ">Failed Prelim</span>
|
||||||
|
@elseif($entry->hasFlag('passed_prelim'))
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center rounded-md bg-green-100 px-2 py-1 text-sm font-medium text-green-700">Passed Prelim</span>
|
||||||
|
@elseif($entry->audition->prelimDefinition)
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center rounded-md bg-yellow-100 px-2 py-1 text-sm font-medium text-yellow-800 ">Prelim Pending</span>
|
||||||
|
@endif
|
||||||
<x-slot:subheading>ID #{{ $entry->id }}</x-slot:subheading>
|
<x-slot:subheading>ID #{{ $entry->id }}</x-slot:subheading>
|
||||||
<x-slot:right_side class="text-right">
|
<x-slot:right_side class="text-right">
|
||||||
<p>{{ $entry->student->full_name() }}</p>
|
<p>{{ $entry->student->full_name() }}</p>
|
||||||
|
|
@ -11,7 +21,8 @@
|
||||||
</x-slot:right_side>
|
</x-slot:right_side>
|
||||||
</x-card.heading>
|
</x-card.heading>
|
||||||
|
|
||||||
<x-form.form method="POST" id='scoreForm' action="{{ route('scores.saveEntryScoreSheet',[ 'entry' => $entry->id]) }}">
|
<x-form.form method="POST" id='scoreForm'
|
||||||
|
action="{{ route('scores.saveEntryScoreSheet',[ 'entry' => $entry->id]) }}">
|
||||||
<x-table.table>
|
<x-table.table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
@ -33,7 +44,7 @@
|
||||||
<x-table.body :sortable="false">
|
<x-table.body :sortable="false">
|
||||||
@foreach($judges as $judge)
|
@foreach($judges as $judge)
|
||||||
@php($existingSheet = $existing_sheets[$judge->id] ?? null)
|
@php($existingSheet = $existing_sheets[$judge->id] ?? null)
|
||||||
<tr >
|
<tr>
|
||||||
<x-table.td>{{ $judge->full_name() }}</x-table.td>
|
<x-table.td>{{ $judge->full_name() }}</x-table.td>
|
||||||
@foreach($subscores as $subscore)
|
@foreach($subscores as $subscore)
|
||||||
<x-table.td>
|
<x-table.td>
|
||||||
|
|
@ -48,11 +59,11 @@
|
||||||
value="{{ $existingSheet->getSubscore($subscore->id) }}"
|
value="{{ $existingSheet->getSubscore($subscore->id) }}"
|
||||||
@endif
|
@endif
|
||||||
required
|
required
|
||||||
{{-- onchange="judge{{$judge->id}}sum()"--}}
|
{{-- onchange="judge{{$judge->id}}sum()"--}}
|
||||||
>
|
>
|
||||||
</x-table.td>
|
</x-table.td>
|
||||||
@endforeach
|
@endforeach
|
||||||
<x-table.td >
|
<x-table.td>
|
||||||
<p id="judge{{ $judge->id }}total" class="pr-3">
|
<p id="judge{{ $judge->id }}total" class="pr-3">
|
||||||
0.000
|
0.000
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -67,35 +78,145 @@
|
||||||
</x-form.form>
|
</x-form.form>
|
||||||
|
|
||||||
</x-card.card>
|
</x-card.card>
|
||||||
|
|
||||||
|
@if($entry->audition->prelimDefinition)
|
||||||
|
<x-card.card class="mx-auto max-w-7xl mt-5">
|
||||||
|
<x-card.heading>
|
||||||
|
{{ $entry->audition->name }} #{{ $entry->draw_number }} PRELIM SCORES
|
||||||
|
<x-slot:subheading>ID #{{ $entry->id }}</x-slot:subheading>
|
||||||
|
<x-slot:right_side class="text-right">
|
||||||
|
<p>{{ $entry->student->full_name() }}</p>
|
||||||
|
<p>{{ $entry->student->school->name }}</p>
|
||||||
|
</x-slot:right_side>
|
||||||
|
</x-card.heading>
|
||||||
|
|
||||||
|
<x-form.form method="POST" id='scoreForm'
|
||||||
|
action="{{ route('scores.savePrelimEntryScoreSheet',[ 'entry' => $entry->id]) }}">
|
||||||
|
<x-table.table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<x-table.th>Judges</x-table.th>
|
||||||
|
@foreach($prelim_subscores as $subscore)
|
||||||
|
<x-table.th>
|
||||||
|
<div class="">
|
||||||
|
<div>{{ $subscore->name }}</div>
|
||||||
|
<div class="text-xs text-gray-500">
|
||||||
|
<span>Max: {{ $subscore->max_score }}</span>
|
||||||
|
<span class="pl-2">Weight: {{ $subscore->weight }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-table.th>
|
||||||
|
@endforeach
|
||||||
|
<x-table.th>Total</x-table.th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<x-table.body :sortable="false">
|
||||||
|
@foreach($prelim_judges as $judge)
|
||||||
|
@php($existingSheet = $existing_prelim_sheets[$judge->id] ?? null)
|
||||||
|
<tr>
|
||||||
|
<x-table.td>{{ $judge->full_name() }}</x-table.td>
|
||||||
|
@foreach($prelim_subscores as $subscore)
|
||||||
|
<x-table.td>
|
||||||
|
<input type="number"
|
||||||
|
max="{{ $subscore->max_score }}"
|
||||||
|
id="j{{ $judge->id }}ss{{ $subscore->id }}"
|
||||||
|
name="judge{{ $judge->id }}[{{ $subscore->id }}]"
|
||||||
|
class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6 judge{{$judge->id}}score"
|
||||||
|
@if($oldScores)
|
||||||
|
value="{{ $oldScores['judge'.$judge->id][$subscore->id] }}"
|
||||||
|
@elseif($existingSheet)
|
||||||
|
value="{{ $existingSheet->getSubscore($subscore->id) }}"
|
||||||
|
@endif
|
||||||
|
required
|
||||||
|
{{-- onchange="judge{{$judge->id}}sum()"--}}
|
||||||
|
>
|
||||||
|
</x-table.td>
|
||||||
|
@endforeach
|
||||||
|
<x-table.td>
|
||||||
|
<p id="judge{{ $judge->id }}total" class="pr-3">
|
||||||
|
0.000
|
||||||
|
</p>
|
||||||
|
</x-table.td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</x-table.body>
|
||||||
|
</x-table.table>
|
||||||
|
<x-form.footer class="mb-3">
|
||||||
|
<x-form.button>Save Scores</x-form.button>
|
||||||
|
</x-form.footer>
|
||||||
|
</x-form.form>
|
||||||
|
|
||||||
|
</x-card.card>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function calculateTotal(judgeId) {
|
function calculateTotal(judgeId) {
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let totalWeights = 0;
|
let totalWeights = 0;
|
||||||
|
let maxPossible = 0;
|
||||||
let thisSubscore
|
let thisSubscore
|
||||||
@foreach($subscores as $subscore)
|
@foreach($subscores as $subscore)
|
||||||
thisSubscore = parseFloat(document.getElementById("j" + judgeId + "ss{{ $subscore->id }}").value) * {{ $subscore->weight }};
|
thisSubscore = parseFloat(document.getElementById("j" + judgeId + "ss{{ $subscore->id }}").value) * {{ $subscore->weight }};
|
||||||
if (!isNaN(thisSubscore)) {
|
if (!isNaN(thisSubscore)) {
|
||||||
total += thisSubscore;
|
total += thisSubscore;
|
||||||
}
|
}
|
||||||
totalWeights += {{ $subscore->weight }};
|
totalWeights += {{ $subscore->weight }};
|
||||||
|
maxPossible += {{ $subscore->weight * $subscore->max_score }};
|
||||||
@endforeach
|
@endforeach
|
||||||
let finalTotal = (total / totalWeights).toFixed(3);
|
let finalTotal = ((total / maxPossible) * 100).toFixed(3);
|
||||||
document.getElementById('judge' + judgeId + 'total').innerHTML = finalTotal;
|
document.getElementById('judge' + judgeId + 'total').innerHTML = finalTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@foreach($judges as $judge)
|
@foreach($judges as $judge)
|
||||||
document.querySelectorAll('.judge' + {{ $judge->id }} + 'score').forEach(function(el) {
|
document.querySelectorAll('.judge' + {{ $judge->id }} + 'score').forEach(function (el) {
|
||||||
el.addEventListener('change', function() {
|
el.addEventListener('change', function () {
|
||||||
calculateTotal({{ $judge->id }});
|
calculateTotal({{ $judge->id }});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function () {
|
||||||
// Call the function for each judge
|
// Call the function for each judge
|
||||||
@foreach($judges as $judge)
|
@foreach($judges as $judge)
|
||||||
calculateTotal({{ $judge->id }});
|
calculateTotal({{ $judge->id }});
|
||||||
@endforeach
|
@if($entry->audition->prelimDefinition)
|
||||||
|
@foreach($prelim_judges as $judge)
|
||||||
|
calculatePrelimTotal({{ $judge->id }});
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@if($entry->audition->prelimDefinition)
|
||||||
|
<script>
|
||||||
|
function calculatePrelimTotal(judgeId) {
|
||||||
|
let total = 0;
|
||||||
|
let totalWeights = 0;
|
||||||
|
let maxPossible = 0;
|
||||||
|
let thisSubscore
|
||||||
|
@foreach($prelim_subscores as $subscore)
|
||||||
|
thisSubscore = parseFloat(document.getElementById("j" + judgeId + "ss{{ $subscore->id }}").value) * {{ $subscore->weight }};
|
||||||
|
if (!isNaN(thisSubscore)) {
|
||||||
|
total += thisSubscore;
|
||||||
|
}
|
||||||
|
totalWeights += {{ $subscore->weight }};
|
||||||
|
maxPossible += {{ $subscore->weight * $subscore->max_score }};
|
||||||
|
@endforeach
|
||||||
|
let finalTotal = ((total / maxPossible) * 100).toFixed(3);
|
||||||
|
document.getElementById('judge' + judgeId + 'total').innerHTML = finalTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@foreach($prelim_judges as $judge)
|
||||||
|
document.querySelectorAll('.judge' + {{ $judge->id }} + 'score').forEach(function (el) {
|
||||||
|
el.addEventListener('change', function () {
|
||||||
|
calculatePrelimTotal({{ $judge->id }});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
</script>
|
||||||
|
@endif
|
||||||
|
|
||||||
</x-layout.app>
|
</x-layout.app>
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ Route::middleware(['auth', 'verified', CheckIfCanTab::class])->group(function ()
|
||||||
Route::get('/choose_entry', 'chooseEntry')->name('scores.chooseEntry');
|
Route::get('/choose_entry', 'chooseEntry')->name('scores.chooseEntry');
|
||||||
Route::get('/entry', 'entryScoreSheet')->name('scores.entryScoreSheet');
|
Route::get('/entry', 'entryScoreSheet')->name('scores.entryScoreSheet');
|
||||||
Route::post('/entry/{entry}', 'saveEntryScoreSheet')->name('scores.saveEntryScoreSheet');
|
Route::post('/entry/{entry}', 'saveEntryScoreSheet')->name('scores.saveEntryScoreSheet');
|
||||||
|
Route::post('/entry/prelim/{entry}', 'savePrelimEntryScoreSheet')->name('scores.savePrelimEntryScoreSheet');
|
||||||
Route::delete('/{score}', 'destroyScore')->name('scores.destroy');
|
Route::delete('/{score}', 'destroyScore')->name('scores.destroy');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue