Admin settings for auditions complete

This commit is contained in:
Matt Young 2024-06-03 23:57:31 -05:00
parent 1948bdb85f
commit 7c62168ec5
10 changed files with 219 additions and 55 deletions

View File

@ -4,42 +4,112 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Audition; use App\Models\Audition;
use App\Models\Event;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use function abort;
use function redirect;
use function request;
use function response; use function response;
use function route;
class AuditionController extends Controller class AuditionController extends Controller
{ {
public function index() public function index()
{ {
if(! Auth::user()->is_admin) abort(403); if(! Auth::user()->is_admin) abort(403);
$auditions = Audition::with(['event','entries'])->orderBy('score_order')->get(); $auditions = Audition::with(['event','entries'])->orderBy('score_order')->orderBy('created_at','desc')->get();
return view('admin.auditions.index', ['auditions' => $auditions] ); return view('admin.auditions.index', ['auditions' => $auditions] );
} }
public function create() public function create()
{ {
if(! Auth::user()->is_admin) abort(403); if(! Auth::user()->is_admin) abort(403);
return view('admin.auditions.create'); $events = Event::orderBy('name')->get();
return view('admin.auditions.create',['events'=> $events]);
}
public function store(Request $request)
{
if(! Auth::user()->is_admin) abort(403);
$validData = request()->validate([
'event_id' => ['required', 'exists:events,id'],
'name' => ['required'],
'entry_deadline' => ['required', 'date'],
'entry_fee' => ['required', 'numeric'],
'minimum_grade' => ['required', 'integer'],
'maximum_grade' => 'required|numeric|gt:minimum_grade',
], [
'maximum_grade.gt' => 'The maximum grade must be greater than the minimum grade.',
]);
Audition::create([
'event_id' => $validData['event_id'],
'name' => $validData['name'],
'entry_deadline' => $validData['entry_deadline'],
'entry_fee' => $validData['entry_fee'] * 100,
'minimum_grade' => $validData['minimum_grade'],
'maximum_grade' => $validData['maximum_grade'],
]);
return redirect('/admin/auditions');
} }
public function edit(Audition $audition) public function edit(Audition $audition)
{ {
if(! Auth::user()->is_admin) abort(403); if(! Auth::user()->is_admin) abort(403);
return view('admin.auditions.edit', ['audition' => $audition]); $events = Event::orderBy('name')->get();
return view('admin.auditions.edit', ['audition' => $audition,'events'=> $events]);
}
public function update(Audition $audition)
{
if(! Auth::user()->is_admin) abort(403);
$validData = request()->validate([
'event_id' => ['required', 'exists:events,id'],
'name' => ['required'],
'entry_deadline' => ['required', 'date'],
'entry_fee' => ['required', 'numeric'],
'minimum_grade' => ['required', 'integer'],
'maximum_grade' => 'required|numeric|gt:minimum_grade',
], [
'maximum_grade.gt' => 'The maximum grade must be greater than the minimum grade.',
]);
$audition->update([
'event_id' => $validData['event_id'],
'name' => $validData['name'],
'entry_deadline' => $validData['entry_deadline'],
'entry_fee' => $validData['entry_fee'] * 100,
'minimum_grade' => $validData['minimum_grade'],
'maximum_grade' => $validData['maximum_grade'],
]);
return redirect('/admin/auditions');
} }
public function reorder(Request $request) public function reorder(Request $request)
{ {
if(! Auth::user()->is_admin) abort(403);
$order = $request->order; $order = $request->order;
foreach ($order as $index => $id) { foreach ($order as $index => $id) {
$audition = Audition::find($id); $audition = Audition::find($id);
#$audition->score_order = $index;
#return response()->json(['status' => $index]);
#$item->save();
$audition->update(['score_order' => $index]); $audition->update(['score_order' => $index]);
} }
return response()->json(['status' => 'success']); return response()->json(['status' => 'success']);
} }
public function destroy(Audition $audition)
{
if(! Auth::user()->is_admin) abort(403);
// if($audition->entries->count() > 0) abort(403, 'Cannot delete an audition with entries.'
if($audition->entries->count() > 0) {
return redirect()->route('adminAuditionIndex')->with('error', 'Cannot delete an audition with entries.');
}
$audition->delete();
return redirect('/admin/auditions');
}
} }

View File

@ -0,0 +1,25 @@
<x-layout.app>
<x-slot:page_title>Auditions</x-slot:page_title>
<x-card.card class="max-w-lg mx-auto">
<x-card.heading>
Create Audition
</x-card.heading>
<x-form.form method="POST" action="/admin/auditions">
<x-form.body-grid columns="12" class="pb-1 pt-3">
<x-form.field name="name" label_text="Audition Name" colspan="12" />
<x-form.select name="event_id" colspan="12">
<x-slot:label>Event</x-slot:label>
@foreach($events as $event)
<option value="{{ $event->id }}">{{ $event->name }}</option>
@endforeach
</x-form.select>
<x-form.field name="entry_deadline" label_text="Entry Deadline" type="date" colspan="6"/>
<x-form.field name="entry_fee" label_text="Entry Fee" type="number" colspan="6" />
<x-form.field name="minimum_grade" label_text="Minimum Grade" type="number" colspan="6" />
<x-form.field name="maximum_grade" label_text="Maximum Grade" type="number" colspan="6" />
</x-form.body-grid>
<x-form.footer submit-button-text="Create Audition" class="pb-4"/>
</x-form.form>
</x-card.card>
</x-layout.app>

View File

@ -0,0 +1,34 @@
<x-layout.app>
<x-slot:page_title>Auditions</x-slot:page_title>
<x-card.card class="max-w-lg mx-auto">
<x-card.heading>
Edit Audition
</x-card.heading>
<x-form.form method="PATCH" action="/admin/auditions/{{ $audition->id }}">
<x-form.body-grid columns="12" class="pb-1 pt-3">
<x-form.field name="name" label_text="Audition Name" colspan="12" value="{{ $audition->name }}" />
<x-form.select name="event_id" colspan="12">
<x-slot:label>Event</x-slot:label>
@foreach($events as $event)
<option value="{{ $event->id }}" {{ ($event->id == $audition->event_id) ? "selected":'' }}>{{ $event->name }}</option>
@endforeach
</x-form.select>
<x-form.field name="entry_deadline" label_text="Entry Deadline" type="date" colspan="6" value="{{ $audition->entry_deadline }}"/>
<x-form.field name="entry_fee" label_text="Entry Fee" type="number" colspan="6" value="{{ $audition->entry_fee / 100 }}" />
<x-form.field name="minimum_grade" label_text="Minimum Grade" type="number" colspan="6" value="{{ $audition->minimum_grade }}" />
<x-form.field name="maximum_grade" label_text="Maximum Grade" type="number" colspan="6" value="{{ $audition->maximum_grade }}" />
</x-form.body-grid>
<x-form.footer submit-button-text="Update Audition" class="pb-4 !justify-between">
<div>
<x-form.red-trash-button size="20"></x-form.red-trash-button>
</div>
<div>
<x-form.button>Edit Audition</x-form.button>
</div>
</x-form.footer>
</x-form.form>
<x-form.delete-form action="/admin/auditions/{{ $audition->id }}"></x-form.delete-form>
</x-card.card>
</x-layout.app>

View File

@ -1,19 +1,17 @@
<x-layout.app> <x-layout.app>
<x-slot:page_title>Audition Administration</x-slot:page_title> <x-slot:page_title>Audition Administration</x-slot:page_title>
<x-card.card> <x-card.card>
<x-table.table with_title_area> <x-table.table with_title_area>
<x-slot:title class="ml-3">Auditions</x-slot:title> <x-slot:title class="ml-3">Auditions</x-slot:title>
<x-slot:subtitle class="ml-3">Click name to edit</x-slot:subtitle> <x-slot:subtitle class="ml-3">Drag to reorder. Double click to edit.</x-slot:subtitle>
<x-slot:title_block_right class="mr-3"> <x-slot:title_block_right class="mr-3">
<x-form.button href="/admin/entries/create">New Audition</x-form.button> <x-form.button href="/admin/auditions/create">New Audition</x-form.button>
</x-slot:title_block_right> </x-slot:title_block_right>
<thead> <thead>
<tr> <tr>
<x-table.th>Event</x-table.th> <x-table.th>Event</x-table.th>
<x-table.th>Name</x-table.th> <x-table.th>Name</x-table.th>
<x-table.th>Order</x-table.th>
<x-table.th>Deadline</x-table.th> <x-table.th>Deadline</x-table.th>
<x-table.th>Entry Fee</x-table.th> <x-table.th>Entry Fee</x-table.th>
<x-table.th>Grade Range</x-table.th> <x-table.th>Grade Range</x-table.th>
@ -25,10 +23,9 @@
<div x-data="sortableList()" x-init="init"> <div x-data="sortableList()" x-init="init">
<x-table.body id="sortable-list"> <x-table.body id="sortable-list">
@foreach($auditions as $audition) @foreach($auditions as $audition)
<tr data-id="{{ $audition->id }}"> <tr data-id="{{ $audition->id }}" @dblclick="window.location.href='/admin/auditions/{{ $audition->id }}/edit'">
<x-table.td>{{ $audition->event->name }}</x-table.td> <x-table.td>{{ $audition->event->name }}</x-table.td>
<x-table.td>{{ $audition->name }}</x-table.td> <x-table.td>{{ $audition->name }}</x-table.td>
<x-table.td>{{ $audition->score_order }}</x-table.td>
<x-table.td>{{ $audition->entry_deadline }}</x-table.td> <x-table.td>{{ $audition->entry_deadline }}</x-table.td>
<x-table.td>{{ $audition->dislpay_fee() }}</x-table.td> <x-table.td>{{ $audition->dislpay_fee() }}</x-table.td>
<x-table.td>{{ $audition->minimum_grade }} - {{ $audition->maximum_grade }}</x-table.td> <x-table.td>{{ $audition->minimum_grade }} - {{ $audition->maximum_grade }}</x-table.td>

View File

@ -1,8 +1,18 @@
{{--Send messages with Session::flash('msg|MESSAGE HERE','success, caution or danger');--}}
{{--Can also use helper fuction: sendMessage('Test Message','danger')--}}
@props(['message','messageType']) @props(['message','messageType'])
@php @php
$div_classes = 'flex justify-between mx-auto max-w-2xl text-sm rounded-md px-3 py-1 mb-2 font-medium ring-1 ring-inset '; $messages = [
'success' => session()->get('success'),
'error' => session()->get('error'),
'caution' => session()->get('caution')
];
@endphp
@foreach($messages as $messageType => $message)
@continue(!$message)
@php
$div_classes = 'flex justify-between mx-auto max-w-2xl text-sm rounded-md px-3 py-1 mb-5 font-medium ring-1 ring-inset ';
$button_classes = 'group relative mr-1 h-5 w-5 rounded-sm '; $button_classes = 'group relative mr-1 h-5 w-5 rounded-sm ';
$svg_classes = 'h-5 w-5 '; $svg_classes = 'h-5 w-5 ';
switch($messageType) { switch($messageType) {
@ -12,20 +22,20 @@
$svg_classes .= 'stroke-yellow-700/50 group-hover:stroke-yellow-700/75'; $svg_classes .= 'stroke-yellow-700/50 group-hover:stroke-yellow-700/75';
break; break;
case 'danger': case 'error':
$div_classes .= 'bg-red-50 text-red-700 ring-red-600/40'; $div_classes .= 'bg-red-50 text-red-700 ring-red-600/40';
$button_classes .= 'hover:bg-red-600/20'; $button_classes .= 'hover:bg-red-600/20';
$svg_classes .= 'stroke-red-600/50 group-hover:stroke-red-600/75'; $svg_classes .= 'stroke-red-600/50 group-hover:stroke-red-600/75';
break; break;
default: case 'success':
$div_classes .= 'bg-green-50 text-green-700 ring-green-600/40 '; $div_classes .= 'bg-green-50 text-green-700 ring-green-600/40 ';
$button_classes .= 'hover:bg-green-600/20'; $button_classes .= 'hover:bg-green-600/20';
$svg_classes .= 'stroke-green-700/50 group-hover:stroke-green-700/75'; $svg_classes .= 'stroke-green-700/50 group-hover:stroke-green-700/75';
break; break;
} }
@endphp @endphp
<div class="{{ $div_classes }}" x-data="{ shown: true }" x-show="shown"> <div class="{{ $div_classes }}" x-data="{ shown: true }" x-show="shown">
<div>{{ $message }}</div> <div>{{ $message }}</div>
<div> <div>
<button type="button" class="{{ $button_classes }}" x-on:click=" shown = false"> <button type="button" class="{{ $button_classes }}" x-on:click=" shown = false">
@ -36,4 +46,5 @@
<span class="absolute -inset-1"></span> <span class="absolute -inset-1"></span>
</button> </button>
</div> </div>
</div> </div>
@endforeach

View File

@ -0,0 +1,13 @@
@props(['action'])
@php
$attribs = [
'method' => 'post',
'id' => 'deleteResource',
'action' => $action,
'name' => 'deleteResource'
];
@endphp
<form {{ $attributes->merge($attribs) }}>
@csrf
@method('DELETE')
</form>

View File

@ -1,6 +1,6 @@
@props([ @props([
'method' => 'POST', 'method' => 'POST',
'form_classes' => 'px-4 py-6 sm:p-8' 'form_classes' => 'px-4 sm:px-8'
]) ])
<form method="{{ ($method === 'GET' ? 'GET':'POST') }}" {{ $attributes->merge(['class' => $form_classes]) }}> <form method="{{ ($method === 'GET' ? 'GET':'POST') }}" {{ $attributes->merge(['class' => $form_classes]) }}>

View File

@ -0,0 +1,15 @@
@props(['size' => 25])
@php
$attribs = [
'form' => 'deleteResource',
'type' => 'submit',
'class' => 'rounded-lg bg-red-600 p-2 text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600'
];
@endphp
<button {{ $attributes->merge($attribs) }}>
<svg xmlns="http://www.w3.org/2000/svg" width="{{ $size }}" height="{{ $size }}" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0z"/>
<path d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4zM2.5 3h11V2h-11z"/>
</svg>
</svg>
</button>

View File

@ -33,9 +33,7 @@
<main {{ $attributes }}> <main {{ $attributes }}>
<div class="mx-auto max-w-7xl py-6 sm:px-6 lg:px-8"> <div class="mx-auto max-w-7xl py-6 sm:px-6 lg:px-8">
@foreach(getMessages() as $message) <x-flash_message></x-flash_message>
<x-flash_message :message="$message['message']" :messageType="$message['type']" />
@endforeach
{{ $slot }} {{ $slot }}
</div> </div>

View File

@ -31,12 +31,13 @@ Route::middleware(['auth','verified',CheckIfAdmin::class])->prefix('admin/')->gr
// Admin Auditions Routes // Admin Auditions Routes
Route::prefix('auditions')->controller(\App\Http\Controllers\Admin\AuditionController::class)->group(function() { Route::prefix('auditions')->controller(\App\Http\Controllers\Admin\AuditionController::class)->group(function() {
Route::get('/','index'); Route::get('/','index')->name('adminAuditionIndex');
Route::get('/create','create'); Route::get('/create','create');
Route::post('/','store'); Route::post('/','store');
Route::get('/{entry}/edit','edit'); Route::get('/{audition}/edit','edit');
Route::patch('/{entry}','update'); Route::patch('/{audition}','update');
Route::post('/reorder','reorder'); Route::post('/reorder','reorder');
Route::delete('/{audition}','destroy');
}); });
// Admin Entries Routes // Admin Entries Routes