Initial work on events index.

This commit is contained in:
Matt Young 2024-06-18 11:20:06 -05:00
parent 3290687ba7
commit 1421afab5a
8 changed files with 137 additions and 57 deletions

View File

@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Event;
use Illuminate\Http\Request;
use function compact;
class EventController extends Controller
{
public function index() {
$events = Event::all();
return view('admin.event.index',compact('events'));
}
}

View File

@ -22,18 +22,6 @@ class Audition extends Model
protected $fully_scored; // Set by TabulationService protected $fully_scored; // Set by TabulationService
protected $scored_entries_count; //Set by TabulationService protected $scored_entries_count; //Set by TabulationService
public static function getCompleteAuditions()
{
if (self::$completeAuditions) return self::$completeAuditions;
$auditions = Audition::with(['entries' => function($query) {
$query->withCount('scoreSheets');
},'room.judges'])->get();
self::$completeAuditions = $auditions->filter(function ($audition) {
return $audition->scoringIsComplete();
});
return self::$completeAuditions;
}
public static function deadlineNotPast() public static function deadlineNotPast()
{ {
@ -157,7 +145,7 @@ class Audition extends Model
); );
} }
/* /**
* Ensures judges_count property is always available * Ensures judges_count property is always available
*/ */
public function getJudgesCountAttribute() public function getJudgesCountAttribute()
@ -168,43 +156,4 @@ class Audition extends Model
return $this->attributes['judges_count']; return $this->attributes['judges_count'];
} }
public function scoredEntries()
{
return $this->entries->filter(function($entry) {
return $entry->score_sheets_count >= $this->judges()->count();
});
}
public function rankedEntries()
{
if (! $this->rankedEntries) {
$entries = $this->entries()->with(['audition.scoringGuide.subscores', 'scoreSheets.judge'])->get();
$entries = $entries->all();
usort($entries, function ($a, $b) {
$aScores = $a->finalScoresArray();
$bScores = $b->finalScoresArray();
$length = min(count($aScores), count($bScores));
for ($i = 0; $i < $length; $i++) {
if ($aScores[$i] !== $bScores[$i]) {
return $bScores[$i] - $aScores[$i];
}
}
return 0;
});
$collection = new \Illuminate\Database\Eloquent\Collection($entries);
$this->rankedEntries = $collection;
}
return $this->rankedEntries;
}
public function scoringIsComplete()
{
if (self::$completeAuditions) {
// check and see if this audition is in the list of complete auditions
return self::$completeAuditions->contains('id', $this->id);
}
return $this->scoredEntries()->count() == $this->entries->count();
}
} }

View File

@ -0,0 +1,39 @@
<x-layout.app>
<x-slot:page_title>Events</x-slot:page_title>
<x-card.card class="mx-auto max-w-md">
<x-card.heading>
Manage Events
<x-slot:right_side>
<x-help-modal>
<x-slot:title>About Events in AuditionAdmin</x-slot:title>
<ul class="text-sm text-gray-600 list-disc ml-5 space-y-2">
{{-- move help text to a popout modal --}}
<li>Events generally refer to the performance for a group of auditions</li>
<li>Every audition is assigned to one event</li>
<li>An event cannot be deleted without first deleting all of its auditions</li>
<li>Students will not be allowed to be seated in multiple auditions for the same event</li>
<li>If no student will ever be able to accept more than one seat, all auditions should be in one event</li>
<li>If you have, for example, concert bands and jazz bands that perform at different times, and a student can make both, you should create the concert auditions in one event, and the jazz auditions in another event.</li>
</ul>
</x-help-modal>
</x-slot:right_side>
<x-slot:subheading>
</x-slot:subheading>
</x-card.heading>
<x-card.list.body>
@foreach($events as $event)
<x-card.list.row>
<div class="flex items-baseline justify-between">
<span>{{ $event->name }}</span> <span class="text-sm text-gray-500">, {{ $event->auditions()->count() }} Auditions</span>
</div>
</x-card.list.row>
@endforeach
{{-- The final row will allow for the creation of an event --}}
<x-card.list.row>
</x-card.list.row>
</x-card.list.body>
</x-card.card>
</x-layout.app>

View File

@ -0,0 +1,42 @@
<div
x-data="{ 'showModal': false }"
@keydown.escape="showModal = false"
>
<!-- Trigger for Modal -->
<button type="button" @click="showModal = true">
{{-- circled ? modal --}}
<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.529 9.988a2.502 2.502 0 1 1 5 .191A2.441 2.441 0 0 1 12 12.582V14m-.01 3.008H12M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/>
</svg>
</button>
<!-- Modal -->
<div
class="fixed inset-0 z-30 flex items-center justify-center overflow-auto bg-black bg-opacity-50"
x-show="showModal"
>
<!-- Modal inner -->
<div
class="max-w-3xl px-6 py-4 mx-auto text-left bg-white rounded shadow-lg"
@click.away="showModal = false"
x-transition:enter="motion-safe:ease-out duration-300"
x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100"
>
<!-- Title / Close-->
<div class="flex items-center justify-between border-b mb-2">
<h5 class="mr-3 text-black max-w-none">{{ $title ?? '' }}</h5>
<button type="button" class="z-50 cursor-pointer" @click="showModal = false">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<!-- content -->
<div>{{ $slot }}</div>
</div>
</div>
</div>

View File

@ -25,11 +25,6 @@
<a href="/admin/schools" class="block p-2 hover:text-indigo-600">Schools</a> <a href="/admin/schools" class="block p-2 hover:text-indigo-600">Schools</a>
<a href="/admin/students" class="block p-2 hover:text-indigo-600">Students</a> <a href="/admin/students" class="block p-2 hover:text-indigo-600">Students</a>
<a href="/admin/entries" class="block p-2 hover:text-indigo-600">Entries</a> <a href="/admin/entries" class="block p-2 hover:text-indigo-600">Entries</a>
<a href="/admin/auditions" class="block p-2 hover:text-indigo-600">Auditions</a>
<a href="/admin/scoring" class="block p-2 hover:text-indigo-600">Scoring</a>
<a href="/admin/rooms" class="block p-2 hover:text-indigo-600">Rooms</a>
<a href="/admin/rooms/judging_assignments" class="block p-2 hover:text-indigo-600">Judges</a>
<a href="/admin/auditions/run_draw" class="block p-2 hover:text-indigo-600">Run Draw</a>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,31 @@
<div x-data="{ open: false }" class="relative">
{{-- <button type="button" class="inline-flex items-center gap-x-1 text-sm font-semibold leading-6 text-gray-900" aria-expanded="false" @on:click=" open = ! open">--}}
<button type="button" class="inline-flex items-center gap-x-1 text-white rounded-md px-3 py-2 text-sm font-medium hover:bg-indigo-500 hover:bg-opacity-75" aria-expanded="false" @click=" open = ! open" @click.outside=" open = false">
<span>Setup</span>
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd" />
</svg>
</button>
<!--
Flyout menu, show/hide based on flyout menu state.
Entering: "transition ease-out duration-200"
From: "opacity-0 translate-y-1"
To: "opacity-100 translate-y-0"
Leaving: "transition ease-in duration-150"
From: "opacity-100 translate-y-0"
To: "opacity-0 translate-y-1"
-->
<div class="absolute left-1/2 z-10 mt-5 flex w-screen max-w-min -translate-x-1/2 px-4" x-show="open" x-cloak>
<div class="w-56 shrink rounded-xl bg-white p-4 text-sm font-semibold leading-6 text-gray-900 shadow-lg ring-1 ring-gray-900/5">
<a href="/admin/events" class="block p-2 hover:text-indigo-600">Events</a>
<a href="/admin/auditions" class="block p-2 hover:text-indigo-600">Auditions</a>
<a href="/admin/scoring" class="block p-2 hover:text-indigo-600">Scoring</a>
<a href="/admin/rooms" class="block p-2 hover:text-indigo-600">Rooms</a>
<a href="/admin/rooms/judging_assignments" class="block p-2 hover:text-indigo-600">Judges</a>
<a href="/admin/auditions/run_draw" class="block p-2 hover:text-indigo-600">Run Draw</a>
</div>
</div>
</div>

View File

@ -29,6 +29,7 @@
@endif @endif
@if(Auth::user()->is_admin) @if(Auth::user()->is_admin)
@include('components.layout.navbar.menus.admin') @include('components.layout.navbar.menus.admin')
@include('components.layout.navbar.menus.setup')
@endif @endif
@if(Auth::user()->canTab()) @if(Auth::user()->canTab())
@include('components.layout.navbar.menus.tabulation') @include('components.layout.navbar.menus.tabulation')

View File

@ -58,6 +58,11 @@ Route::middleware(['auth','verified',CheckIfAdmin::class])->prefix('admin/')->gr
Route::post('/auditions/roomUpdate',[\App\Http\Controllers\Admin\AuditionController::class,'roomUpdate']); // Endpoint for JS assigning auditions to rooms Route::post('/auditions/roomUpdate',[\App\Http\Controllers\Admin\AuditionController::class,'roomUpdate']); // Endpoint for JS assigning auditions to rooms
Route::post('/scoring/assign_guide_to_audition',[\App\Http\Controllers\Admin\AuditionController::class,'scoringGuideUpdate']); // Endpoint for JS assigning scoring guides to auditions Route::post('/scoring/assign_guide_to_audition',[\App\Http\Controllers\Admin\AuditionController::class,'scoringGuideUpdate']); // Endpoint for JS assigning scoring guides to auditions
// Admin Event Routes
Route::prefix('events')->controller(\App\Http\Controllers\Admin\EventController::class)->group(function() {
Route::get('/','index');
});
// Admin Rooms Routes // Admin Rooms Routes
Route::prefix('rooms')->controller(\App\Http\Controllers\Admin\RoomController::class)->group(function() { Route::prefix('rooms')->controller(\App\Http\Controllers\Admin\RoomController::class)->group(function() {
Route::get('/','index'); Route::get('/','index');
@ -137,6 +142,8 @@ Route::middleware(['auth','verified',CheckIfAdmin::class])->prefix('admin/')->gr
}); });
}); });
// Dashboard Related Routes // Dashboard Related Routes
Route::middleware(['auth','verified'])->group(function () { Route::middleware(['auth','verified'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'dashboard'])->name('dashboard'); Route::get('/dashboard', [DashboardController::class, 'dashboard'])->name('dashboard');