Require confirmation for making a scored entry a no-show

This commit is contained in:
Matt Young 2024-07-07 22:12:36 -05:00
parent 0f18a7c62e
commit 03a2dd2e1d
7 changed files with 97 additions and 19 deletions

View File

@ -21,21 +21,42 @@ class EntryFlagController extends Controller
$validData = $request->validate([ $validData = $request->validate([
'entry_id' => 'required|exists:entries,id', 'entry_id' => 'required|exists:entries,id',
]); ]);
$entry = Entry::with('flags')->find($validData['entry_id']); $entry = Entry::with('flags')->withCount('scoreSheets')->find($validData['entry_id']);
if ($entry->hasFlag('no_show')) { if ($entry->hasFlag('no_show')) {
$formId = 'no-show-cancellation-form'; $formId = 'no-show-cancellation-form';
$buttonName = 'Remove No Show'; $buttonName = 'Remove No Show';
$submitRouteName = 'entry-flags.enterNoShow'; $submitRouteName = 'entry-flags.undoNoShow';
$cardHeading = 'Undo No Show'; $cardHeading = 'Undo No-Show';
$method = 'DELETE';
} else { } else {
$formId = 'no-show-confirmation-form'; $formId = 'no-show-confirmation-form';
$buttonName = 'Confirm No Show'; $buttonName = 'Confirm No Show';
$submitRouteName = 'entry-flags.enterNoShow'; $submitRouteName = 'entry-flags.enterNoShow';
$cardHeading = 'Confirm No Show'; $cardHeading = 'Confirm No-Show';
$method = 'POST';
}
$scores = [];
if($entry->score_sheets_count > 0) {
$scores = $entry->scoreSheets;
$scores->load('judge');
} }
return view('tabulation.no_show_confirm', return view('tabulation.no_show_confirm',
compact('entry', 'formId', 'buttonName', 'submitRouteName', 'cardHeading')); compact('entry',
'formId',
'buttonName',
'submitRouteName',
'cardHeading',
'method',
'scores'));
}
public function enterNoShow(Entry $entry)
{
//
}
public function undoNoShow(Entry $entry)
{
//
} }
} }

View File

@ -4,7 +4,6 @@ namespace Database\Seeders;
use App\Models\ScoreSheet; use App\Models\ScoreSheet;
use App\Models\User; use App\Models\User;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
class ScoreAllAuditions extends Seeder class ScoreAllAuditions extends Seeder
@ -16,23 +15,23 @@ class ScoreAllAuditions extends Seeder
{ {
$judges = User::all(); $judges = User::all();
foreach ($judges as $judge) { foreach ($judges as $judge) {
foreach( $judge->rooms as $room) { foreach ($judge->rooms as $room) {
foreach ($room->auditions as $audition){ foreach ($room->auditions as $audition) {
$scoringGuide = $audition->scoringGuide; $scoringGuide = $audition->scoringGuide;
$subscores = $scoringGuide->subscores; $subscores = $scoringGuide->subscores;
foreach ($audition->entries as $entry){ foreach ($audition->entries as $entry) {
$scoreArray = []; $scoreArray = [];
foreach ($subscores as $subscore) { foreach ($subscores as $subscore) {
$scoreArray[$subscore->id] = [ $scoreArray[$subscore->id] = [
'score' => mt_rand(0,100), 'score' => mt_rand(0, 100),
'subscore_id' => $subscore->id, 'subscore_id' => $subscore->id,
'subscore_name' => $subscore->name 'subscore_name' => $subscore->name,
]; ];
} }
ScoreSheet::create([ ScoreSheet::create([
'user_id' => $judge->id, 'user_id' => $judge->id,
'entry_id' => $entry->id, 'entry_id' => $entry->id,
'subscores' => $scoreArray 'subscores' => $scoreArray,
]); ]);
} }
} }

View File

@ -2,7 +2,7 @@
<div x-data="{ toggle: {{ $checked ? 'true':'false'}} }" class="flex items-center"> <div x-data="{ toggle: {{ $checked ? 'true':'false'}} }" class="flex items-center">
<label {{ $attributes->merge(['class'=>'relative inline-flex items-center cursor-pointer']) }}>{{ $slot }} <label {{ $attributes->merge(['class'=>'relative inline-flex items-center cursor-pointer']) }}>{{ $slot }}
<input type="checkbox" x-model="toggle" name="{{ $name }}" class="sr-only" {{ $checked ? 'checked':''}} value="1" > <input type="checkbox" x-model="toggle" name="{{ $name }}" class="sr-only" {{ $checked ? 'checked':''}} value="1" >
<div :class="toggle ? 'bg-blue-600' : 'bg-gray-200'" class="w-11 h-6 rounded-full transition-colors duration-300"></div> <div :class="toggle ? 'bg-indigo-600' : 'bg-gray-200'" class="w-11 h-6 rounded-full transition-colors duration-300"></div>
<div :class="toggle ? 'translate-x-6' : 'translate-x-1'" class="absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition-transform duration-300"></div> <div :class="toggle ? 'translate-x-6' : 'translate-x-1'" class="absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition-transform duration-300"></div>
</label> </label>
@error($name) @error($name)

View File

@ -1,5 +1,30 @@
<x-layout.app> <x-layout.app x-data="{ showButton: {{ $scores ? 'false':'true' }} }">
<x-card.card class="mx-auto max-w-md"> @if($scores)
<x-card.card class="mx-auto max-w-2xl mb-3">
<x-card.heading class="text-red-600">
WARNING: Entry has existing scores
</x-card.heading>
<div class="grid md:grid-cols-3 px-4 space-x-3 pb-6">
@foreach($scores as $score)
<div>
<div class="my-3 border-b">{{ $score->judge->full_name() }}</div>
<ul>
@foreach($score->subscores as $subscore)
<div class="grid grid-cols-2 gap-x-8 border-b">
<span>{{ $subscore['subscore_name'] }}</span>
<span>{{ $subscore['score'] }}</span>
</div>
@endforeach
</ul>
</div>
@endforeach
</div>
<div class="pb-5 pl-5 flex gap-1">
<x-form.checkbox name="confirm" x-model="showButton" /> I understand that marking this entry as a no-show will delete existing scores. The scores cannot be recovered.
</div>
</x-card.card>
@endif
<x-card.card class="mx-auto max-w-md" x-show="showButton" x-cloak>
<x-card.heading>{{ $cardHeading }}</x-card.heading> <x-card.heading>{{ $cardHeading }}</x-card.heading>
<x-card.list.body> <x-card.list.body>
<x-card.list.row> <x-card.list.row>
@ -11,8 +36,8 @@
</x-card.list.row> </x-card.list.row>
</x-card.list.body> </x-card.list.body>
<x-form.footer class="mb-4"> <x-form.footer class="mb-4">
<x-form.form method="POST" action="{{route($submitRouteName, $entry)}}" id="{{ $formId }}"> <x-form.form method="{{ $method }}" action="{{route($submitRouteName, $entry)}}" id="{{ $formId }}">
<x-form.button type="submit">{{ $buttonName }}</x-form.button> <x-form.button type="submit" >{{ $buttonName }}</x-form.button>
</x-form.form> </x-form.form>
</x-form.footer> </x-form.footer>
</x-card.card> </x-card.card>

View File

@ -0,0 +1,6 @@
<div class="flex items-center">
<label class="'relative inline-flex items-center cursor-pointer'">{{ $slot }}
<input type="checkbox" x-model="toggle" name="{{ $name }}" class="sr-only" {{ $checked ? 'checked':''}} value="1" >
<div :class="toggle ? 'bg-indigo-600' : 'bg-gray-200'" class="w-11 h-6 rounded-full transition-colors duration-300"></div>
<div :class="toggle ? 'translate-x-6' : 'translate-x-1'" class="absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition-transform duration-300"></div>
</label>

View File

@ -19,6 +19,7 @@ Route::middleware(['auth', 'verified', CheckIfCanTab::class])->group(function ()
Route::get('/choose_no_show', 'noShowSelect')->name('entry-flags.noShowSelect'); Route::get('/choose_no_show', 'noShowSelect')->name('entry-flags.noShowSelect');
Route::get('/propose-no-show', 'noShowConfirm')->name('entry-flags.confirmNoShow'); Route::get('/propose-no-show', 'noShowConfirm')->name('entry-flags.confirmNoShow');
Route::post('/no-show/{entry}', 'enterNoShow')->name('entry-flags.enterNoShow'); Route::post('/no-show/{entry}', 'enterNoShow')->name('entry-flags.enterNoShow');
Route::delete('/no-show/{entry}', 'undoNoShow')->name('entry-flags.undoNoShow');
}); });
// Generic Tabulation Routes // Generic Tabulation Routes

View File

@ -1,7 +1,13 @@
<?php <?php
use App\Models\Audition;
use App\Models\Entry; use App\Models\Entry;
use App\Models\Room;
use App\Models\ScoringGuide;
use App\Models\SubscoreDefinition;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Artisan;
use Sinnbeck\DomAssertions\Asserts\AssertForm; use Sinnbeck\DomAssertions\Asserts\AssertForm;
use function Pest\Laravel\get; use function Pest\Laravel\get;
@ -64,3 +70,23 @@ it('posts to entry-flags.undoNoShow and has a remove button if the entry is alre
->hasCSRF(); ->hasCSRF();
}); });
}); });
it('shows a box with scores if the entry is scored', function () {
// Arrange
$judges = User::factory()->count(3)->create();
$room = Room::factory()->create();
$judges->each(fn ($judge) => $room->addJudge($judge->id));
$scoringGuide = ScoringGuide::factory()->create();
SubscoreDefinition::factory()->count(5)->create(['scoring_guide_id' => $scoringGuide->id]);
$audition = Audition::factory()->create(['room_id' => $room->id, 'scoring_guide_id' => $scoringGuide->id]);
$entry = Entry::factory()->create(['audition_id' => $audition->id]);
// Run the ScoreAllAuditions seeder
Artisan::call('db:seed', ['--class' => 'ScoreAllAuditions']);
// Act & Assert
actAsTab();
$response = get(route('entry-flags.confirmNoShow', ['entry_id' => $entry->id]));
$response->assertOk()
->assertSee('WARNING')
->assertSee('existing scores');
$judges->each(fn ($judge) => $response->assertSee($judge->full_name()));
});