Draw Index complete
This commit is contained in:
parent
9a9ca4f916
commit
575ce9854b
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Event;
|
||||||
|
|
||||||
|
class DrawController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$events = Event::with('auditions')->get();
|
||||||
|
|
||||||
|
return view('admin.draw.index', compact('events'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,7 +13,7 @@ class Event extends Model
|
||||||
|
|
||||||
public function auditions(): HasMany
|
public function auditions(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(Audition::class);
|
return $this->hasMany(Audition::class)->orderBy('score_order');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ensembles(): HasMany
|
public function ensembles(): HasMany
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
@php
|
||||||
|
/**
|
||||||
|
* @var \App\Models\Event[] $events A collection of all events with auditions
|
||||||
|
*/
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<x-layout.app>
|
||||||
|
<x-form.form action="{{ route('admin.draw.store') }}" method="POST" id="draw-form">
|
||||||
|
@foreach($events as $event)
|
||||||
|
@continue($event->auditions->isEmpty())
|
||||||
|
<x-card.card class="mb-5 mx-auto max-w-3xl" id="event-section-{{$event->id}}" x-data="{ checked{{$event->id}}: false }">
|
||||||
|
<x-card.heading>
|
||||||
|
{{ $event->name }}
|
||||||
|
<x-slot:right_side>
|
||||||
|
<button @click="checked{{$event->id}} = true" class="rounded bg-indigo-50 px-2 py-1 text-xs font-semibold text-indigo-600 shadow-sm hover:bg-indigo-100 mr-3" type="button">Check All</button>
|
||||||
|
<button @click="checked{{$event->id}} = false" class="rounded bg-indigo-50 px-2 py-1 text-xs font-semibold text-indigo-600 shadow-sm hover:bg-indigo-100" type="button">Uncheck All</button>
|
||||||
|
</x-slot:right_side>
|
||||||
|
</x-card.heading>
|
||||||
|
<div class="grid gap-y-3 md:grid-cols-2 lg:grid-cols-3 px-5 my-3 pb-3 border-b border-gray-100">
|
||||||
|
@foreach($event->auditions as $audition)
|
||||||
|
<div id="auditiongroup-{{$audition->id}}" class="flex align-middle">
|
||||||
|
<x-form.checkbox id="auditionCheckbox-{{$audition->id}}" name="audition[{{$audition->id}}]" x-bind:checked="checked{{$event->id}}"/>
|
||||||
|
{{$audition->name}}
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
<div class="flex w-full justify-between ">
|
||||||
|
<div></div>
|
||||||
|
<div class="mb-5 mr-10 ">
|
||||||
|
<x-form.button type="submit" class="ml-auto">Run Draw</x-form.button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-card.card>
|
||||||
|
@endforeach
|
||||||
|
</x-form.form>
|
||||||
|
</x-layout.app>
|
||||||
|
|
@ -1,7 +1,16 @@
|
||||||
@props(['name','label' => false,'description' => '', 'checked' => false])
|
@props(['name',
|
||||||
|
'label' => false,
|
||||||
|
'description' => '',
|
||||||
|
'checked' => false,
|
||||||
|
'id' => false])
|
||||||
|
@php
|
||||||
|
if(! $id):
|
||||||
|
$id = $name;
|
||||||
|
endif;
|
||||||
|
@endphp
|
||||||
<div class="relative flex items-start">
|
<div class="relative flex items-start">
|
||||||
<div class="flex h-6 items-center">
|
<div class="flex h-6 items-center">
|
||||||
<input id="{{ $name }}"
|
<input id="{{ $id }}"
|
||||||
aria-describedby="comments-description"
|
aria-describedby="comments-description"
|
||||||
name="{{ $name }}"
|
name="{{ $name }}"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|
@ -10,7 +19,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-3 text-sm leading-6">
|
<div class="ml-3 text-sm leading-6">
|
||||||
@if($label)
|
@if($label)
|
||||||
<label for="{{ $name }}" class="font-medium text-gray-900">{{ $label }}</label>
|
<label for="{{ $id }}" class="font-medium text-gray-900">{{ $label }}</label>
|
||||||
<p id="comments-description" class="text-gray-500">{{ $description }}</p>
|
<p id="comments-description" class="text-gray-500">{{ $description }}</p>
|
||||||
@endif
|
@endif
|
||||||
@error($name)
|
@error($name)
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
<x-layout.navbar.menus.menu-item :href="route('admin.scoring.index')">Scoring</x-layout.navbar.menus.menu-item>
|
<x-layout.navbar.menus.menu-item :href="route('admin.scoring.index')">Scoring</x-layout.navbar.menus.menu-item>
|
||||||
<x-layout.navbar.menus.menu-item :href="route('admin.rooms.index')">Rooms</x-layout.navbar.menus.menu-item>
|
<x-layout.navbar.menus.menu-item :href="route('admin.rooms.index')">Rooms</x-layout.navbar.menus.menu-item>
|
||||||
<x-layout.navbar.menus.menu-item :href="route('admin.rooms.judgingAssignment')">Judges</x-layout.navbar.menus.menu-item>
|
<x-layout.navbar.menus.menu-item :href="route('admin.rooms.judgingAssignment')">Judges</x-layout.navbar.menus.menu-item>
|
||||||
<x-layout.navbar.menus.menu-item :href="route('admin.auditions.runDraw')">Run Draw</x-layout.navbar.menus.menu-item>
|
<x-layout.navbar.menus.menu-item :href="route('admin.draw.index')">Run Draw</x-layout.navbar.menus.menu-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,15 @@ Route::middleware(['auth', 'verified', CheckIfAdmin::class])->prefix('admin/')->
|
||||||
Route::patch('/{audition}', 'update')->name('admin.auditions.update');
|
Route::patch('/{audition}', 'update')->name('admin.auditions.update');
|
||||||
Route::post('/reorder', 'reorder')->name('admin.auditions.reorder');
|
Route::post('/reorder', 'reorder')->name('admin.auditions.reorder');
|
||||||
Route::delete('/{audition}', 'destroy')->name('admin.auditions.destroy');
|
Route::delete('/{audition}', 'destroy')->name('admin.auditions.destroy');
|
||||||
Route::get('/run_draw', 'prepareDraw')->name('admin.auditions.prepareDraw');
|
#Route::get('/run_draw', 'prepareDraw')->name('admin.auditions.prepareDraw');
|
||||||
Route::post('/run_draw', 'runDraw')->name('admin.auditions.runDraw');
|
#Route::post('/run_draw', 'runDraw')->name('admin.auditions.runDraw');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Admin Audition Draw Routes
|
||||||
|
Route::prefix('draw')->controller(\App\Http\Controllers\Admin\DrawController::class)->group(function () {
|
||||||
|
Route::get('/', 'index')->name('admin.draw.index');
|
||||||
|
Route::post('/', 'store')->name('admin.draw.store');
|
||||||
|
Route::delete('/', 'destroy')->name('admin.draw.destroy');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Admin Entries Routes
|
// Admin Entries Routes
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ uses(RefreshDatabase::class);
|
||||||
|
|
||||||
it('has auditions', function () {
|
it('has auditions', function () {
|
||||||
$event = Event::factory()->create();
|
$event = Event::factory()->create();
|
||||||
$ddAudition = Audition::factory()->create(['event_id' => $event->id, 'name' => 'Digereedoo']);
|
Audition::factory()->create(['event_id' => $event->id, 'name' => 'Digereedoo','score_order' => 0]);
|
||||||
Audition::factory()->count(7)->create(['event_id' => $event->id]);
|
Audition::factory()->count(7)->create(['event_id' => $event->id]);
|
||||||
|
|
||||||
expect($event->auditions->count())->toBe(8)
|
expect($event->auditions->count())->toBe(8)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Audition;
|
||||||
|
use App\Models\Event;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Sinnbeck\DomAssertions\Asserts\AssertElement;
|
||||||
|
use Sinnbeck\DomAssertions\Asserts\AssertForm;
|
||||||
|
|
||||||
|
uses(RefreshDatabase::class);
|
||||||
|
|
||||||
|
it('only allows admin users to manage the draw', function () {
|
||||||
|
// Act & Assert
|
||||||
|
$this->get(route('admin.draw.index'))->assertRedirect(route('home'));
|
||||||
|
actAsNormal();
|
||||||
|
$this->get(route('admin.draw.index'))
|
||||||
|
->assertSessionHas('error', 'You are not authorized to perform this action')
|
||||||
|
->assertRedirect(route('dashboard'));
|
||||||
|
|
||||||
|
});
|
||||||
|
it('returns the view admin.draw.index', function () {
|
||||||
|
actAsAdmin();
|
||||||
|
$response = $this->get(route('admin.draw.index'));
|
||||||
|
$response->assertViewIs('admin.draw.index');
|
||||||
|
});
|
||||||
|
it('has a section for each event that has auditions', function () {
|
||||||
|
// Arrange
|
||||||
|
$events = Event::factory()->count(3)->create();
|
||||||
|
Audition::factory()->create(['event_id' => $events[0]->id]);
|
||||||
|
Audition::factory()->create(['event_id' => $events[1]->id]);
|
||||||
|
actAsAdmin();
|
||||||
|
// Act
|
||||||
|
$response = $this->get(route('admin.draw.index'));
|
||||||
|
// Assert
|
||||||
|
foreach ($events as $event) {
|
||||||
|
if ($event->auditions->count() > 0) {
|
||||||
|
$response->assertElementExists('#event-section-'.$event->id);
|
||||||
|
} else {
|
||||||
|
$response->assertDontSee('id="event-section-'.$event->id, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it('lists auditions in each section', function () {
|
||||||
|
// Arrange
|
||||||
|
$events = Event::factory()->count(2)->create();
|
||||||
|
foreach ($events as $event) {
|
||||||
|
Audition::factory()->count(5)->create(['event_id' => $event->id]);
|
||||||
|
}
|
||||||
|
actAsAdmin();
|
||||||
|
// Act
|
||||||
|
$response = $this->get(route('admin.draw.index'));
|
||||||
|
// Assert
|
||||||
|
foreach ($events as $event) {
|
||||||
|
$response->assertElementExists('#event-section-'.$event->id, function (AssertElement $element) use ($event) {
|
||||||
|
foreach ($event->auditions as $audition) {
|
||||||
|
$element->contains('#auditiongroup-'.$audition->id);
|
||||||
|
$element->containsText($audition->name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it('each audition has a checkbox with its name', function () {
|
||||||
|
// Arrange
|
||||||
|
$events = Event::factory()->count(2)->create();
|
||||||
|
foreach ($events as $event) {
|
||||||
|
Audition::factory()->count(5)->create(['event_id' => $event->id]);
|
||||||
|
}
|
||||||
|
actAsAdmin();
|
||||||
|
// Act
|
||||||
|
$response = $this->get(route('admin.draw.index'));
|
||||||
|
$response->assertOk();
|
||||||
|
// Assert
|
||||||
|
foreach ($events as $event) {
|
||||||
|
$response->assertElementExists('#event-section-'.$event->id, function (AssertElement $element) use ($event) {
|
||||||
|
foreach ($event->auditions as $audition) {
|
||||||
|
$element->contains('#auditiongroup-'.$audition->id, function (AssertElement $element) use ($audition) {
|
||||||
|
$element->containsText($audition->name);
|
||||||
|
});
|
||||||
|
$element->contains('#auditionCheckbox-'.$audition->id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it('lists auditions in score order', function () {
|
||||||
|
// Arrange
|
||||||
|
$event = Event::factory()->create();
|
||||||
|
$third = Audition::factory()->create(['event_id' => $event->id, 'score_order' => 3]);
|
||||||
|
$first = Audition::factory()->create(['event_id' => $event->id, 'score_order' => 1]);
|
||||||
|
$fourth = Audition::factory()->create(['event_id' => $event->id, 'score_order' => 4]);
|
||||||
|
$second = Audition::factory()->create(['event_id' => $event->id, 'score_order' => 2]);
|
||||||
|
actAsAdmin();
|
||||||
|
// Act & Assert
|
||||||
|
$response = $this->get(route('admin.draw.index'));
|
||||||
|
$response->assertOk();
|
||||||
|
$response->assertSeeInOrder([
|
||||||
|
e($first->name),
|
||||||
|
e($second->name),
|
||||||
|
e($third->name),
|
||||||
|
e($fourth->name),
|
||||||
|
], false);
|
||||||
|
});
|
||||||
|
it('has a form wrapping all event sections', function () {
|
||||||
|
// Arrange
|
||||||
|
$events = Event::factory()->count(2)->create();
|
||||||
|
foreach ($events as $event) {
|
||||||
|
Audition::factory()->count(5)->create(['event_id' => $event->id]);
|
||||||
|
}
|
||||||
|
actAsAdmin();
|
||||||
|
// Act
|
||||||
|
$response = $this->get(route('admin.draw.index'));
|
||||||
|
// Assert
|
||||||
|
$response
|
||||||
|
->assertOk()
|
||||||
|
->assertElementExists('#draw-form', function (AssertElement $element) use ($events) {
|
||||||
|
foreach ($events as $event) {
|
||||||
|
$element->contains('#event-section-'.$event->id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
it('has a submit button in each event section', function () {
|
||||||
|
// Arrange
|
||||||
|
$events = Event::factory()->count(3)->create();
|
||||||
|
Audition::factory()->create(['event_id' => $events[0]->id]);
|
||||||
|
Audition::factory()->create(['event_id' => $events[1]->id]);
|
||||||
|
actAsAdmin();
|
||||||
|
// Act
|
||||||
|
$response = $this->get(route('admin.draw.index'));
|
||||||
|
// Assert
|
||||||
|
foreach ($events as $event) {
|
||||||
|
if ($event->auditions->count() > 0) {
|
||||||
|
$response->assertElementExists('#event-section-'.$event->id, function (AssertElement $element) {
|
||||||
|
$element->contains('button[type="submit"]');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it('submits to the route admin.draw.store and has CSRF protection', function () {
|
||||||
|
// Arrange
|
||||||
|
$events = Event::factory()->count(3)->create();
|
||||||
|
foreach ($events as $event) {
|
||||||
|
Audition::factory()->create(['event_id' => $event->id]);
|
||||||
|
}
|
||||||
|
actAsAdmin();
|
||||||
|
// Act
|
||||||
|
$response = $this->get(route('admin.draw.index'));
|
||||||
|
// Assert
|
||||||
|
$response
|
||||||
|
->assertOk()
|
||||||
|
->assertFormExists('#draw-form', function (AssertForm $form) {
|
||||||
|
$form->hasAction(route('admin.draw.store'));
|
||||||
|
$form->hasCSRF();
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue