Sorting working on scoring guides

This commit is contained in:
Matt Young 2024-06-04 02:12:10 -05:00
parent eb68a5fc2b
commit 43647583e7
7 changed files with 230 additions and 73 deletions

View File

@ -10,6 +10,7 @@ use Illuminate\Support\Facades\Auth;
use function abort;
use function dd;
use function request;
use function response;
use function sendMessage;
class ScoringGuideController extends Controller
@ -36,11 +37,16 @@ class ScoringGuideController extends Controller
return redirect('/admin/scoring');
}
public function edit(ScoringGuide $guide)
public function edit(Request $request, ScoringGuide $guide)
{
if (! Auth::user()->is_admin) abort(403);
$tab = $request->query('tab') ?? 'detail';
if ($tab == 'tiebreakOrder') {
$subscores = SubscoreDefinition::where('scoring_guide_id', $guide->id)->orderBy('tiebreak_order')->get();
} else {
$subscores = SubscoreDefinition::where('scoring_guide_id', $guide->id)->orderBy('display_order')->get();
return view('admin.scoring.edit',['guide'=>$guide,'subscores'=>$subscores]);
}
return view('admin.scoring.edit',['guide'=>$guide,'subscores'=>$subscores, 'tab'=>$tab]);
}
public function update(ScoringGuide $guide)
@ -64,8 +70,6 @@ class ScoringGuideController extends Controller
'name' => ['required'],
'max_score' => ['required','integer'],
'weight'=>['required','integer'],
'display_order'=>['required','integer'],
'tiebreak_order'=>['required','integer'],
'for_seating'=>['nullable','boolean'],
'for_advance'=>['nullable','boolean'],
]);
@ -73,17 +77,44 @@ class ScoringGuideController extends Controller
$for_seating = $request->has('for_seating') ? (bool) $request->input('for_seating') : false;
$for_advance = $request->has('for_advance') ? (bool) $request->input('for_advance') : false;
$display_order = SubscoreDefinition::where('scoring_guide_id','=',$guide->id)->max('display_order') + 1;
$tiebreak_order = SubscoreDefinition::where('scoring_guide_id','=',$guide->id)->max('tiebreak_order') + 1;
$subscore = SubscoreDefinition::create([
'scoring_guide_id' => $guide->id,
'name' => $validateData['name'],
'max_score' => $validateData['max_score'],
'weight' => $validateData['weight'],
'display_order' => $validateData['display_order'],
'tiebreak_order' => $validateData['tiebreak_order'],
'display_order' => $display_order,
'tiebreak_order' => $tiebreak_order,
'for_seating' => $for_seating,
'for_advance' => $for_advance,
]);
return redirect('/admin/scoring/guides/' . $guide->id . '/edit' )->with('success','Subscore added');
}
public function reorder_display(Request $request)
{
if(! Auth::user()->is_admin) abort(403);
$order = $request->order;
foreach ($order as $index => $id) {
$subscore = SubscoreDefinition::find($id);
$subscore->update(['display_order' => $index]);
}
return response()->json(['status'=>'success']);
}
public function reorder_tiebreak(Request $request)
{
if(! Auth::user()->is_admin) abort(403);
$order = $request->order;
foreach ($order as $index => $id) {
$subscore = SubscoreDefinition::find($id);
$subscore->update(['tiebreak_order' => $index]);
}
return response()->json(['status'=>'success']);
}
}

View File

@ -0,0 +1,56 @@
@php use App\Settings; @endphp
<x-table.table with_title_area >
<x-slot:title>Subscore Details</x-slot:title>
<thead>
<tr>
<x-table.th>Name</x-table.th>
<x-table.th>Max Score</x-table.th>
<x-table.th>Weight</x-table.th>
<x-table.th>For Seating</x-table.th>
@if(Settings::advanceTo())
<x-table.th>For {{ Settings::advanceTo() }}</x-table.th>
@endif
<x-table.th spacer_only></x-table.th>
</tr>
</thead>
<x-table.body>
@foreach ($subscores as $subscore)
<tr>
<x-table.td>{{ $subscore->name }}</x-table.td>
<x-table.td>{{ $subscore->max_score }}</x-table.td>
<x-table.td>{{ $subscore->weight }}</x-table.td>
<x-table.td>{{ $subscore->for_seating ? 'Yes' : 'No' }}</x-table.td>
@if(Settings::advanceTo())
<x-table.td>{{ $subscore->for_advance ? 'Yes' : 'No' }}</x-table.td>
@endif
<x-table.td>
{{-- This came from AI, consider--}}
{{-- <x-form.form method="PATCH" action="/admin/scoring/guides/{{ $guide->id }}/subscore/{{ $subscore->id }}">--}}
{{-- <x-table.button>Save</x-table.button>--}}
{{-- <x-table.button @click="if(confirm('Are you sure?')) { $dispatch('delete', {id: {{ $subscore->id }} }) }">Delete</x-table.button>--}}
{{-- <x-table.button @click="rename = ! rename">Rename</x-table.button>--}}
{{-- </x-form.form>--}}
&nbsp;
</x-table.td>
</tr>
{{-- WHERE DID THIS EVEN COME FROM???--}}
{{-- <template x-on:delete.window="document.querySelector('form[action=\'/admin/scoring/guides/{{ $guide->id }}/subscore/\'+event.detail.id+\'\']').submit()"></template>--}}
@endforeach
</x-table.body>
<tfoot>
<tr><x-table.th class="!pb-0">Add Subscore</x-table.th></tr><tr>
<x-form.form method="POST" action="/admin/scoring/guides/{{ $guide->id }}/subscore">
<x-table.td><x-form.field name="name"></x-form.field></x-table.td>
<x-table.td><x-form.field name="max_score" type="number"></x-form.field></x-table.td>
<x-table.td><x-form.field name="weight" type="number"></x-form.field></x-table.td>
<x-table.td><x-form.toggle-checkbox name="for_seating" checked></x-form.toggle-checkbox></x-table.td>
@if(Settings::advanceTo())
<x-table.td><x-form.toggle-checkbox name="for_advance" checked></x-form.toggle-checkbox></x-table.td>
@endif
<td><x-table.button>Save</x-table.button></td>
</x-form.form>
</tr>
</tfoot>
</x-table.table>

View File

@ -0,0 +1,45 @@
@php use App\Settings; @endphp
<x-table.table with_title_area >
<x-slot:title class="-mb-5">Subscore Display Order</x-slot:title>
<div x-data="sortableListForTiebreak('/admin/scoring/reorder-display')" x-init="init">
<x-table.body id="sortable-list">
@foreach ($subscores as $subscore)
<tr data-id="{{ $subscore->id }}">
<x-table.td>{{ $subscore->name }}</x-table.td>
</tr>
@endforeach
</x-table.body>
</div>
</x-table.table>
<script>
function sortableListForTiebreak(submitLink) {
return {
init() {
let el = document.getElementById('sortable-list');
let sortable = Sortable.create(el, {
onEnd: function (evt) {
let order = Array.from(el.children).map((item, index) => item.getAttribute('data-id'));
fetch(submitLink, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify({ order })
}).then(response => response.json())
.then(data => {
if (data.status === 'success') {
console.log('Order updated successfully');
}
else {
console.log(data.status);
}
});
}
});
}
}
}
</script>

View File

@ -0,0 +1,25 @@
@php
$normal_classes = 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 w-1/4 border-b-2 py-4 px-1 text-center text-sm font-medium';
$active_classes = 'border-indigo-500 text-indigo-600 w-1/4 border-b-2 py-4 px-1 text-center text-sm font-medium';
@endphp
<div>
<div class="sm:hidden">
<label for="tabs" class="sr-only">Select a tab</label>
<!-- TODO Use an "onChange" listener to redirect the user to the selected tab URL. -->
<select id="tabs" name="tabs" class="block w-full rounded-md border-gray-300 focus:border-indigo-500 focus:ring-indigo-500">
<option>Details</option>
<option selected>Display Order</option>
<option>Tiebreak Order</option>
</select>
</div>
<div class="hidden sm:block">
<div class="border-b border-gray-200">
<nav class="-mb-px flex" aria-label="Tabs">
<!-- Current: "border-indigo-500 text-indigo-600", Default: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700" -->
<a href="{{ request()->getPathInfo() }}?tab=detail" class="{{ $tab == 'detail' ? $active_classes : $normal_classes }}">Details</a>
<a href="{{ request()->getPathInfo() }}?tab=displayOrder" class="{{ $tab == 'displayOrder' ? $active_classes : $normal_classes }}">Display Order</a>
<a href="{{ request()->getPathInfo() }}?tab=tiebreakOrder" class="{{ $tab == 'tiebreakOrder' ? $active_classes : $normal_classes }}">Tiebreak Order</a>
</nav>
</div>
</div>
</div>

View File

@ -0,0 +1,45 @@
@php use App\Settings; @endphp
<x-table.table with_title_area >
<x-slot:title class="-mb-5">Subscore Display Order</x-slot:title>
<div x-data="sortableListForDisplay('/admin/scoring/reorder-tiebreak')" x-init="init">
<x-table.body id="sortable-list">
@foreach ($subscores as $subscore)
<tr data-id="{{ $subscore->id }}">
<x-table.td>{{ $subscore->name }}</x-table.td>
</tr>
@endforeach
</x-table.body>
</div>
</x-table.table>
<script>
function sortableListForDisplay(endpoint) {
return {
init() {
let el = document.getElementById('sortable-list');
let sortable = Sortable.create(el, {
onEnd: function (evt) {
let order = Array.from(el.children).map((item, index) => item.getAttribute('data-id'));
fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify({ order })
}).then(response => response.json())
.then(data => {
if (data.status === 'success') {
console.log('Order updated successfully');
}
else {
console.log(data.status);
}
});
}
});
}
}
}
</script>

View File

@ -1,73 +1,27 @@
@php use App\Settings; @endphp
<x-layout.app x-data="{ rename: false }">
<x-slot:page_title>Scoring Rules</x-slot:page_title>
{{-- MAIN CARD--}}
<x-card.card x-show="! rename">
<x-card.card x-show="! rename" class="max-w-xl mx-auto">
<x-card.heading>
<x-slot:subheading @click="rename = ! rename">Click here to rename</x-slot:subheading>
Scoring Guide: {{ $guide->name }}
</x-card.heading>
<div class="ml-6 -mt-2 mr-6">
<x-table.table with_title_area >
<x-slot:title>Subscores</x-slot:title>
<thead>
<tr>
<x-table.th>Name</x-table.th>
<x-table.th>Max Score</x-table.th>
<x-table.th>Weight</x-table.th>
<x-table.th>Display Order</x-table.th>
<x-table.th>Tiebreak Order</x-table.th>
<x-table.th>For Seating</x-table.th>
@if(Settings::advanceTo())
<x-table.th>For {{ Settings::advanceTo() }}</x-table.th>
@endif
<x-table.th spacer_only></x-table.th>
</tr>
</thead>
<x-table.body>
@foreach ($subscores as $subscore)
<tr>
<x-table.td>{{ $subscore->name }}</x-table.td>
<x-table.td>{{ $subscore->max_score }}</x-table.td>
<x-table.td>{{ $subscore->weight }}</x-table.td>
<x-table.td>{{ $subscore->display_order }}</x-table.td>
<x-table.td>{{ $subscore->tiebreak_order }}</x-table.td>
<x-table.td>{{ $subscore->for_seating ? 'Yes' : 'No' }}</x-table.td>
@if(Settings::advanceTo())
<x-table.td>{{ $subscore->for_advance ? 'Yes' : 'No' }}</x-table.td>
@endif
<x-table.td>
{{-- This came from AI, consider--}}
{{-- <x-form.form method="PATCH" action="/admin/scoring/guides/{{ $guide->id }}/subscore/{{ $subscore->id }}">--}}
{{-- <x-table.button>Save</x-table.button>--}}
{{-- <x-table.button @click="if(confirm('Are you sure?')) { $dispatch('delete', {id: {{ $subscore->id }} }) }">Delete</x-table.button>--}}
{{-- <x-table.button @click="rename = ! rename">Rename</x-table.button>--}}
{{-- </x-form.form>--}}
&nbsp;
</x-table.td>
</tr>
<template x-on:delete.window="document.querySelector('form[action=\'/admin/scoring/guides/{{ $guide->id }}/subscore/\'+event.detail.id+\'\']').submit()"></template>
@endforeach
</x-table.body>
<tfoot>
<tr><x-table.th class="!pb-0">Add Subscore</x-table.th></tr><tr>
<x-form.form method="POST" action="/admin/scoring/guides/{{ $guide->id }}/subscore">
<x-table.td><x-form.field name="name"></x-form.field></x-table.td>
<x-table.td><x-form.field name="max_score" type="number"></x-form.field></x-table.td>
<x-table.td><x-form.field name="weight" type="number"></x-form.field></x-table.td>
<x-table.td><x-form.field name="display_order"></x-form.field></x-table.td>
<x-table.td><x-form.field name="tiebreak_order"></x-form.field></x-table.td>
<x-table.td><x-form.toggle-checkbox name="for_seating" checked></x-form.toggle-checkbox></x-table.td>
@if(Settings::advanceTo())
<x-table.td><x-form.toggle-checkbox name="for_advance"></x-form.toggle-checkbox></x-table.td>
@endif
<td><x-table.button>Save</x-table.button></td>
</x-form.form>
</tr>
</tfoot>
</x-table.table>
</x-card.heading>
@include('admin.scoring.edit-tabs')
<div class="ml-6 -mt-2 mr-6">
@switch($tab)
@case('detail')
@include('admin.scoring.edit-detail')
@break
@case('displayOrder')
@include('admin.scoring.edit-display-order')
@break
@case('tiebreakOrder')
@include('admin.scoring.edit-tiebreak-order')
@break
@endswitch
</div>
</x-card.card>
@ -81,6 +35,5 @@
</x-form.form>
</x-card.card>
<div class="mt-20">
@php(dump($guide))
</div>
</x-layout.app>

View File

@ -26,6 +26,8 @@ Route::middleware(['auth','verified',CheckIfAdmin::class])->prefix('admin/')->gr
Route::get('/guides/{guide}/edit','edit'); // Edit scoring guide
Route::patch('/guides/{guide}/edit','update'); // Save changes to audition guide (rename)
Route::post('/guides/{guide}/subscore','subscore_store'); // Save a new subscore
Route::post('/reorder-display','reorder_display');
Route::post('/reorder-tiebreak','reorder_tiebreak');
});