Start work on tabulation pages

This commit is contained in:
Matt Young 2024-06-06 07:13:44 -05:00
parent e82bb8c457
commit f49c10821a
15 changed files with 261 additions and 16 deletions

View File

@ -0,0 +1,10 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ScoreSheetController extends Controller
{
//
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Http\Controllers\Tabulation;
use App\Http\Controllers\Controller;
use App\Models\Audition;
use App\Models\Entry;
use Illuminate\Http\Request;
class TabulationController extends Controller
{
public function chooseEntry(Request $request)
{
return view('tabulation.choose_entry');
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
use function redirect;
class CheckIfCanTab
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if (Auth::check() && Auth::user()->is_admin) {
return $next($request);
}
if (Auth::check() && Auth::user()->is_tab) {
return $next($request);
}
return redirect('/')->with('error', 'You do not have access to score tabulation.');
}
}

11
app/Models/ScoreSheet.php Normal file
View File

@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ScoreSheet extends Model
{
use HasFactory;
}

View File

@ -118,4 +118,9 @@ class User extends Authenticatable implements MustVerifyEmail
}
return SchoolEmailDomain::with('school')->where('domain','=',$this->emailDomain())->get();
}
public function canTab() {
if ($this->is_admin) return true;
return $this->is_tab;
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace App\Policies;
use App\Models\ScoreSheet;
use App\Models\User;
use Illuminate\Auth\Access\Response;
class ScoreSheetPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
//
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, ScoreSheet $scoreSheet): bool
{
//
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
//
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, ScoreSheet $scoreSheet): bool
{
//
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, ScoreSheet $scoreSheet): bool
{
//
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, ScoreSheet $scoreSheet): bool
{
//
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, ScoreSheet $scoreSheet): bool
{
//
}
}

View File

@ -0,0 +1,32 @@
<?php
use App\Models\Entry;
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('score_sheets', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(User::class)->constrained()->cascadeOnUpdate()->cascadeOnDelete();
$table->foreignIdFor(Entry::class)->constrained()->cascadeOnDelete()->cascadeOnUpdate();
$table->json('subscores');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('score_sheets');
}
};

View File

@ -0,0 +1,17 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class ScoreSheetSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
//
}
}

View File

@ -38,7 +38,7 @@
<x-form.field name="first_name_filter" colspan="6" label_text="First Name" value="{{ ($filters['first_name'] ?? null) }}"/>
<x-form.field name="last_name_filter" colspan="6" label_text="Last Name" value="{{ ($filters['last_name'] ?? null) }}"/>
</x-form.body-grid>
<x-form.footer>
<x-form.footer class="pb-4">
<x-form.button-nocolor href="filters/admin_entry_filter/clear">Clear Filters</x-form.button-nocolor>
<x-form.button>Apply Filters</x-form.button>
</x-form.footer>

View File

@ -29,16 +29,6 @@
<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>
<form method="POST" action="/logout">
@csrf
<button
class="block p-2 hover:text-indigo-600"
role="menuitem"
tabindex="-1"
id="user-menu-item-2">
Sign out
</button>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,27 @@
<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">
<span>Tabulation</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="/tabulation/enter_scores" class="block p-2 hover:text-indigo-600">Enter Scores</a>
</div>
</div>
</div>

View File

@ -21,6 +21,9 @@
@if(Auth::user()->is_admin)
@include('components.layout.navbar.menus.admin')
@endif
@if(Auth::user()->canTab())
@include('components.layout.navbar.menus.tabulation')
@endif
</div>
</div>
</div>

View File

@ -0,0 +1,18 @@
<x-layout.app>
<x-slot:page_title>Choose Entry</x-slot:page_title>
<x-card.card class="mx-auto max-w-sm">
<x-card.heading>Choose Entry</x-card.heading>
<div class="">
<x-form.form method="GET" action="#" class="mb-4 mt-3">
<x-form.field name="entry_id" label_text="Entry ID"></x-form.field>
</x-form.form>
<x-form.footer class="px-4 sm:px-8 pb-4">
<x-form.button>Select</x-form.button>
</x-form.footer>
</div>
</x-card.card>
</x-layout.app>
d

View File

@ -3,7 +3,13 @@
<x-slot:page_title>Test Page</x-slot:page_title>
@php
$scores =[
['subcoreID' => 13, 'score' => 93],
['subcoreID' => 23, 'score' => 91],
['subcoreID' => 42, 'score' => 81],
['subcoreID' => 78, 'score' => 16],
['subcoreID' => 74, 'score' => 23],
];
@endphp

View File

@ -9,21 +9,33 @@ use App\Http\Controllers\StudentController;
use App\Http\Controllers\TestController;
use App\Http\Controllers\UserController;
use App\Http\Middleware\CheckIfAdmin;
use App\Http\Middleware\CheckIfCanTab;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
Route::get('/test',[TestController::class,'flashTest'])->middleware('auth','verified');
Route::post('/admin/scoring/assign_guide_to_audition',[\App\Http\Controllers\Admin\AuditionController::class,'scoringGuideUpdate']); // needs to move inside of admin group
Route::view('/','welcome')->middleware('guest');
// Score Tabulation Routes
Route::middleware(['auth','verified',CheckIfCanTab::class])->prefix('tabulation/')->group(function() {
// Generic Tabulation Routes
Route::controller(\App\Http\Controllers\Tabulation\TabulationController::class)->group(function() {
Route::get('/enter_scores','chooseEntry');
Route::get('/record_noshow','chooseEntry');
});
});
// Admin Routes
Route::middleware(['auth','verified',CheckIfAdmin::class])->prefix('admin/')->group(function() {
Route::view('/','admin.dashboard');
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
// Rooms
// Admin Rooms Routes
Route::prefix('rooms')->controller(\App\Http\Controllers\Admin\RoomController::class)->group(function() {
Route::get('/','index');
Route::get('/create','create');
@ -36,7 +48,7 @@ Route::middleware(['auth','verified',CheckIfAdmin::class])->prefix('admin/')->gr
});
// Scoring
// Admin Scoring Guides
Route::prefix('scoring')->controller(\App\Http\Controllers\Admin\ScoringGuideController::class)->group(function() {
Route::get('/','index'); // Scoring Setup Homepage
Route::post('/guides','store'); // Save a new scoring guide
@ -47,7 +59,6 @@ Route::middleware(['auth','verified',CheckIfAdmin::class])->prefix('admin/')->gr
Route::post('/reorder-tiebreak','reorder_tiebreak');
});
// Admin Auditions Routes
Route::prefix('auditions')->controller(\App\Http\Controllers\Admin\AuditionController::class)->group(function() {
Route::get('/','index')->name('adminAuditionIndex');