From 8125ef6a322f36daaa61436b5dfd6d8a3e6cabcf Mon Sep 17 00:00:00 2001 From: Matt Young Date: Wed, 26 Jun 2024 12:29:55 -0500 Subject: [PATCH] First steps on advancement. Some cleanup in supporting services --- .../Tabulation/AdvancementController.php | 35 +++++++++++++ app/Services/DoublerService.php | 15 ++++-- app/Services/EntryCacheService.php | 17 ++++++- app/Services/ScoreService.php | 4 +- app/Services/TabulationService.php | 11 ++-- .../layout/navbar/menus/tabulation.blade.php | 3 +- .../tabulation/advancement/ranking.blade.php | 23 +++++++++ .../advancement/results-table.blade.php | 22 ++++++++ .../tabulation/advancement/status.blade.php | 51 +++++++++++++++++++ routes/tabulation.php | 8 ++- 10 files changed, 174 insertions(+), 15 deletions(-) create mode 100644 app/Http/Controllers/Tabulation/AdvancementController.php create mode 100644 resources/views/tabulation/advancement/ranking.blade.php create mode 100644 resources/views/tabulation/advancement/results-table.blade.php create mode 100644 resources/views/tabulation/advancement/status.blade.php diff --git a/app/Http/Controllers/Tabulation/AdvancementController.php b/app/Http/Controllers/Tabulation/AdvancementController.php new file mode 100644 index 0000000..4626872 --- /dev/null +++ b/app/Http/Controllers/Tabulation/AdvancementController.php @@ -0,0 +1,35 @@ +tabulationService = $tabulationService; + } + + public function status() + { + $auditions = $this->tabulationService->getAuditionsWithStatus('advancement'); + + return view('tabulation.advancement.status', compact('auditions')); + } + + public function ranking(Request $request, Audition $audition) + { + $entries = $this->tabulationService->auditionEntries($audition->id); + $entries = $entries->filter(function ($entry) { + return $entry->for_advancement; + }); + + return view('tabulation.advancement.ranking', compact('audition', 'entries')); + } +} diff --git a/app/Services/DoublerService.php b/app/Services/DoublerService.php index daffd3a..5a1f777 100644 --- a/app/Services/DoublerService.php +++ b/app/Services/DoublerService.php @@ -4,6 +4,7 @@ namespace App\Services; use App\Models\Entry; use App\Models\Student; +use Illuminate\Contracts\Database\Eloquent\Builder; use Illuminate\Support\Facades\Cache; class DoublerService @@ -32,13 +33,19 @@ class DoublerService public function getDoublers(): \Illuminate\Database\Eloquent\Collection { // TODO creating or destroying an entry should refresh the doubler cache - // TODO this currently counts total entries, only need to count seating_entries. Would be an edge case, but needs to be fixed. - return Cache::remember($this->doublersCacheKey, 60, function () { - return Student::withCount('entries') - ->with('entries') + // TODO needs to split by event so that a doubler may enter jazz and concert events for example + $doublers = Cache::remember($this->doublersCacheKey, 60, function () { + return Student::withCount(['entries' => function (Builder $query) { + $query->where('for_seating', true); + }]) + ->with(['entries' => function (Builder $query) { + $query->where('for_seating', true); + }]) ->havingRaw('entries_count > ?', [1]) ->get(); }); + + return $doublers; } public function refreshDoublerCache() diff --git a/app/Services/EntryCacheService.php b/app/Services/EntryCacheService.php index 5ee0e2c..d353d74 100644 --- a/app/Services/EntryCacheService.php +++ b/app/Services/EntryCacheService.php @@ -24,17 +24,30 @@ class EntryCacheService * * @return \Illuminate\Database\Eloquent\Collection */ - public function getEntriesForAudition($auditionId) + public function getEntriesForAudition($auditionId, $mode = 'seating') { // TODO this invokes a lot of lazy loading. Perhaps cache the data for all entries then draw from that for each audition $cacheKey = 'audition'.$auditionId.'entries'; - return Cache::remember($cacheKey, 3600, function () use ($auditionId) { + $entries = Cache::remember($cacheKey, 3600, function () use ($auditionId) { return Entry::where('audition_id', $auditionId) ->with('student.school') ->get() ->keyBy('id'); }); + + switch ($mode) { + case 'seating': + return $entries->filter(function ($entry) { + return $entry->for_seating; + }); + case 'advancement': + return $entries->filter(function ($entry) { + return $entry->for_advancement; + }); + default: + return $entries; + } } /** diff --git a/app/Services/ScoreService.php b/app/Services/ScoreService.php index ad3ec19..128f5f4 100644 --- a/app/Services/ScoreService.php +++ b/app/Services/ScoreService.php @@ -101,7 +101,7 @@ class ScoreService * * @return void */ - public function calculateScoresForAudition($auditionId) + public function calculateScoresForAudition($auditionId, $mode= 'seating') { static $alreadyChecked = []; // if $auditionId is in the array $alreadyChecked return @@ -111,7 +111,7 @@ class ScoreService $alreadyChecked[] = $auditionId; $audition = $this->auditionCache->getAudition($auditionId); $scoringGuideId = $audition->scoring_guide_id; - $entries = $this->entryCache->getEntriesForAudition($auditionId); + $entries = $this->entryCache->getEntriesForAudition($auditionId, $mode); $entries->load('scoreSheets'); // TODO Cache this somehow, it's expensive and repetitive on the seating page foreach ($entries as $entry) { diff --git a/app/Services/TabulationService.php b/app/Services/TabulationService.php index 7c8e3b6..822ff14 100644 --- a/app/Services/TabulationService.php +++ b/app/Services/TabulationService.php @@ -44,7 +44,7 @@ class TabulationService * * @return \Illuminate\Support\Collection|mixed */ - public function auditionEntries(int $auditionId) + public function auditionEntries(int $auditionId, $mode = 'seating') { static $cache = []; if (isset($cache[$auditionId])) { @@ -52,7 +52,7 @@ class TabulationService } $audition = $this->auditionCacheService->getAudition($auditionId); - $entries = $this->entryCacheService->getEntriesForAudition($auditionId); + $entries = $this->entryCacheService->getEntriesForAudition($auditionId, $mode); $this->scoreService->calculateScoresForAudition($auditionId); foreach ($entries as $entry) { @@ -117,6 +117,7 @@ class TabulationService case 'advancement': return $audition->advancement_entries_count - $audition->scored_entries_count; } + return $audition->entries_count - $audition->scored_entries_count; } @@ -132,9 +133,7 @@ class TabulationService return Cache::remember('auditionsWithStatus', 30, function () use ($mode) { // Retrieve auditions from the cache and load entry IDs - $auditions = $this->auditionCacheService->getAuditions(); - - + $auditions = $this->auditionCacheService->getAuditions($mode); // Iterate over the auditions and calculate the scored_entries_count foreach ($auditions as $audition) { $scored_entries_count = 0; @@ -168,7 +167,9 @@ class TabulationService $audition->scored_entries_count = $scored_entries_count; } + return $auditions; + }); } } diff --git a/resources/views/components/layout/navbar/menus/tabulation.blade.php b/resources/views/components/layout/navbar/menus/tabulation.blade.php index 9e1906f..10617d7 100644 --- a/resources/views/components/layout/navbar/menus/tabulation.blade.php +++ b/resources/views/components/layout/navbar/menus/tabulation.blade.php @@ -21,7 +21,8 @@
diff --git a/resources/views/tabulation/advancement/ranking.blade.php b/resources/views/tabulation/advancement/ranking.blade.php new file mode 100644 index 0000000..e6b1f65 --- /dev/null +++ b/resources/views/tabulation/advancement/ranking.blade.php @@ -0,0 +1,23 @@ + + {{ auditionSetting('advanceTo') }} Advancement - {{ $audition->name }} +
+
+
+ @include('tabulation.advancement.results-table') +
+
+{{-- @if($audition->hasFlag('seats_published'))--}} +{{-- @include('tabulation.auditionSeating-show-published-seats')--}} +{{-- @elseif(! $auditionComplete)--}} +{{-- @include('tabulation.auditionSeating-unable-to-seat-card')--}} +{{-- @else--}} +{{-- @include('tabulation.auditionSeating-fill-seats-form')--}} +{{-- @include('tabulation.auditionSeating-show-proposed-seats')--}} +{{-- @endif--}} + + +
+
+ + +
diff --git a/resources/views/tabulation/advancement/results-table.blade.php b/resources/views/tabulation/advancement/results-table.blade.php new file mode 100644 index 0000000..ca825be --- /dev/null +++ b/resources/views/tabulation/advancement/results-table.blade.php @@ -0,0 +1,22 @@ + + + + + Rank + ID + Draw # + Student Name + Total Score + All Scores? + + + + + @foreach($entries as $entry) + + {{ $entry->rank }} + + @endforeach + + + diff --git a/resources/views/tabulation/advancement/status.blade.php b/resources/views/tabulation/advancement/status.blade.php new file mode 100644 index 0000000..d2e269a --- /dev/null +++ b/resources/views/tabulation/advancement/status.blade.php @@ -0,0 +1,51 @@ + + {{ auditionSetting('advanceTo') }} Status + + + {{ auditionSetting('advanceTo') }} Advancement Status + + + + + Audition + Scoring Complete + Advancement Published + + + + @foreach($auditions as $audition) + @php + $percent = 100; + if($audition->advancement_entries_count > 0) { + $percent = round(($audition->scored_entries_count / $audition->advancement_entries_count) * 100); + } + @endphp + + + + +
+ {{ $audition->name }} + {{ $audition->scored_entries_count }} / {{ $audition->advancement_entries_count }} Scored +
+
+
+
+
+
+ + @if( $audition->scored_entries_count == $audition->advancement_entries_count) + + @endif + + + @if( $audition->hasFlag('advancement_published')) + + @endif + + + @endforeach +
+
+
+
diff --git a/routes/tabulation.php b/routes/tabulation.php index 82a9b58..f79826a 100644 --- a/routes/tabulation.php +++ b/routes/tabulation.php @@ -16,12 +16,18 @@ Route::middleware(['auth', 'verified', CheckIfCanTab::class])->group(function () // Generic Tabulation Routes Route::prefix('tabulation/')->controller(\App\Http\Controllers\Tabulation\TabulationController::class)->group(function () { - Route::get('/status', 'status'); + Route::get('/status', 'status')->name('tabulation.status'); Route::match(['get', 'post'], '/auditions/{audition}', 'auditionSeating')->name('tabulation.audition.seat'); Route::post('/auditions/{audition}/publish-seats', 'publishSeats')->name('tabulation.seat.publish'); Route::post('/auditions/{audition}/unpublish-seats', 'unpublishSeats')->name('tabulation.seat.unpublish'); }); + // Advancement Routes + Route::prefix('advancement/')->controller(\App\Http\Controllers\Tabulation\AdvancementController::class)->group(function () { + Route::get('/status', 'status')->name('advancement.status'); + Route::get('/{audition}', 'ranking')->name('advancement.ranking'); + }); + // Doubler decision routes Route::prefix('doubler-decision')->controller(DoublerDecisionController::class)->group(function () { Route::post('{entry}/accept', 'accept')->name('doubler.accept');