Decline button works on doublers on seating page

This commit is contained in:
Matt Young 2024-06-21 11:36:49 -05:00
parent f9e936fd07
commit b21902fc9a
5 changed files with 168 additions and 118 deletions

View File

@ -0,0 +1,40 @@
<?php
namespace App\Http\Controllers\Tabulation;
use App\Http\Controllers\Controller;
use App\Models\Entry;
use App\Models\EntryFlag;
use App\Services\DoublerService;
class DoublerDecisionController extends Controller
{
protected $doublerService;
public function __construct(DoublerService $doublerService)
{
$this->doublerService = $doublerService;
}
public function accept(Entry $entry)
{
//
}
public function decline(Entry $entry)
{
if ($entry->hasFlag('declined')) {
return redirect()->back()->with('caution', 'Entry is already declined');
}
EntryFlag::create([
'entry_id' => $entry->id,
'flag_name' => 'declined',
]);
$this->doublerService->refreshDoublerCache();
$returnMessage = $entry->student->full_name().' declined seating in '.$entry->audition->name;
return redirect()->back()->with('success', $returnMessage);
}
}

View File

@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
class EntryFlag extends Model class EntryFlag extends Model
{ {
protected $guarded = [];
// Possible flags include // Possible flags include
// - declined: used if a doubler declines a seat in this audition. Checked by DoublerService // - declined: used if a doubler declines a seat in this audition. Checked by DoublerService
public function entry(): BelongsTo public function entry(): BelongsTo

View File

@ -48,10 +48,13 @@ class DoublerService
/** /**
* Returns an array of information about each entry for a specific doubler. Info for each entry includes * Returns an array of information about each entry for a specific doubler. Info for each entry includes
* entryID
* auditionID * auditionID
* auditionName * auditionName
* rank => This student's rank in the given audition * rank => This student's rank in the given audition
* unscored => How many entries remain to be scored in this audition * unscored => How many entries remain to be scored in this audition
* limits => acceptance limits for this audition
* status => accepted, declined, or undecided
* *
* @param int $studentId The ID of the doubler * @param int $studentId The ID of the doubler
*/ */
@ -87,6 +90,7 @@ class DoublerService
$status = 'undecided'; $status = 'undecided';
} }
$info[$entry->id] = [ $info[$entry->id] = [
'entryID' => $entry->id,
'auditionID' => $entry->audition_id, 'auditionID' => $entry->audition_id,
'auditionName' => $this->auditionCacheService->getAudition($entry->audition_id)->name, 'auditionName' => $this->auditionCacheService->getAudition($entry->audition_id)->name,
'rank' => $this->tabulationService->entryRank($entry), 'rank' => $this->tabulationService->entryRank($entry),

View File

@ -1,6 +1,6 @@
@props(['doublerEntryInfo']) @props(['doublerEntryInfo'])
@php($doublerButtonClasses = 'hidden rounded-md bg-white px-2.5 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:block')
<ul role="list" class="divide-y divide-gray-100"> <ul role="list" class="divide-y divide-gray-200">
@foreach($doublerEntryInfo as $info) @foreach($doublerEntryInfo as $info)
<li class="flex items-center justify-between gap-x-6 py-5"> <li class="flex items-center justify-between gap-x-6 py-5">
@ -31,8 +31,13 @@
<div class="flex items-center gap-x-4"> <div class="flex items-center gap-x-4">
<a href="#" class="hidden rounded-md bg-white px-2.5 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:block">Accept</a> @if ($info['status'] === 'undecided')
<a href="#" class="hidden rounded-md bg-white px-2.5 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:block">Decline</a> <button class="{{ $doublerButtonClasses }}">Accept</button>
<form method="POST" action="{{ route('doubler.decline',['entry'=>$info['entryID']]) }}">
@csrf
<button class="{{ $doublerButtonClasses }}">Decline</button>
</form>
@endif
</div> </div>
</li> </li>
@endforeach @endforeach

View File

@ -1,13 +1,12 @@
<?php <?php
use App\Http\Controllers\Admin\AuditionController;
use App\Http\Controllers\DashboardController; use App\Http\Controllers\DashboardController;
use App\Http\Controllers\EntryController; use App\Http\Controllers\EntryController;
use App\Http\Controllers\FilterController; use App\Http\Controllers\FilterController;
use App\Http\Controllers\JudgingController; use App\Http\Controllers\JudgingController;
use App\Http\Controllers\SchoolController; use App\Http\Controllers\SchoolController;
use App\Http\Controllers\StudentController; use App\Http\Controllers\StudentController;
use App\Http\Controllers\Tabulation\TabulationController; use App\Http\Controllers\Tabulation\DoublerDecisionController;
use App\Http\Controllers\TestController; use App\Http\Controllers\TestController;
use App\Http\Controllers\UserController; use App\Http\Controllers\UserController;
use App\Http\Middleware\CheckIfAdmin; use App\Http\Middleware\CheckIfAdmin;
@ -15,193 +14,195 @@ use App\Http\Middleware\CheckIfCanJudge;
use App\Http\Middleware\CheckIfCanTab; use App\Http\Middleware\CheckIfCanTab;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
Route::get('rediscli', function() {
Route::get('rediscli', function () {
return \Illuminate\Support\Facades\Redis::ping(); return \Illuminate\Support\Facades\Redis::ping();
}); });
Route::get('/test',[TestController::class,'flashTest'])->middleware('auth','verified'); Route::get('/test', [TestController::class, 'flashTest'])->middleware('auth', 'verified');
Route::view('/','welcome')->middleware('guest')->name('home'); Route::view('/', 'welcome')->middleware('guest')->name('home');
// Judging Routes // Judging Routes
Route::middleware(['auth','verified',CheckIfCanJudge::class])->prefix('judging')->controller(JudgingController::class)->group(function() { Route::middleware(['auth', 'verified', CheckIfCanJudge::class])->prefix('judging')->controller(JudgingController::class)->group(function () {
Route::get('/','index'); Route::get('/', 'index');
Route::get('/audition/{audition}','auditionEntryList'); Route::get('/audition/{audition}', 'auditionEntryList');
Route::get('/entry/{entry}','entryScoreSheet'); Route::get('/entry/{entry}', 'entryScoreSheet');
Route::post('/entry/{entry}','saveScoreSheet'); Route::post('/entry/{entry}', 'saveScoreSheet');
Route::patch('/entry/{entry}','updateScoreSheet'); Route::patch('/entry/{entry}', 'updateScoreSheet');
}); });
// Tabulation Routes // Tabulation Routes
Route::middleware(['auth','verified',CheckIfCanTab::class])->group(function() { Route::middleware(['auth', 'verified', CheckIfCanTab::class])->group(function () {
// Score Management // Score Management
Route::prefix('scores/')->controller(\App\Http\Controllers\Tabulation\ScoreController::class)->group(function() { Route::prefix('scores/')->controller(\App\Http\Controllers\Tabulation\ScoreController::class)->group(function () {
Route::get('/choose_entry','chooseEntry')->name('scores.chooseEntry'); Route::get('/choose_entry', 'chooseEntry')->name('scores.chooseEntry');
Route::get('/entry','entryScoreSheet')->name('scores.entryScoreSheet'); Route::get('/entry', 'entryScoreSheet')->name('scores.entryScoreSheet');
Route::post('/entry/{entry}','saveEntryScoreSheet')->name('scores.saveEntryScoreSheet'); Route::post('/entry/{entry}', 'saveEntryScoreSheet')->name('scores.saveEntryScoreSheet');
Route::delete('/{score}',[\App\Http\Controllers\Tabulation\ScoreController::class,'destroyScore'])->name('scores.destroy'); Route::delete('/{score}', [\App\Http\Controllers\Tabulation\ScoreController::class, 'destroyScore'])->name('scores.destroy');
}); });
// Generic Tabulation Routes // Generic Tabulation Routes
Route::prefix('tabulation/')->controller(\App\Http\Controllers\Tabulation\TabulationController::class)->group(function() { Route::prefix('tabulation/')->controller(\App\Http\Controllers\Tabulation\TabulationController::class)->group(function () {
Route::get('/status','status'); Route::get('/status', 'status');
Route::get('/auditions/{audition}','auditionSeating'); Route::get('/auditions/{audition}', 'auditionSeating');
});
// Doubler decision routes
Route::prefix('doubler-decision')->controller(DoublerDecisionController::class)->group(function () {
Route::post('{entry}/accept', 'accept')->name('doubler.accept');
Route::post('{entry}/decline', 'decline')->name('doubler.decline');
}); });
}); });
// Admin Routes // Admin Routes
Route::middleware(['auth','verified',CheckIfAdmin::class])->prefix('admin/')->group(function() { Route::middleware(['auth', 'verified', CheckIfAdmin::class])->prefix('admin/')->group(function () {
Route::view('/','admin.dashboard'); Route::view('/', 'admin.dashboard');
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 Ensemble Routes // Admin Ensemble Routes
Route::prefix('ensembles')->controller(\App\Http\Controllers\Admin\EnsembleController::class)->group(function() { Route::prefix('ensembles')->controller(\App\Http\Controllers\Admin\EnsembleController::class)->group(function () {
Route::get('/','index')->name('admin.ensembles.index'); Route::get('/', 'index')->name('admin.ensembles.index');
Route::post('/','store')->name('admin.ensembles.store'); Route::post('/', 'store')->name('admin.ensembles.store');
Route::delete('/{ensemble}','destroy')->name('admin.ensembles.destroy'); Route::delete('/{ensemble}', 'destroy')->name('admin.ensembles.destroy');
Route::post('/updateEnsembleRank','updateEnsembleRank')->name('admin.ensembles.updateEnsembleRank'); Route::post('/updateEnsembleRank', 'updateEnsembleRank')->name('admin.ensembles.updateEnsembleRank');
Route::patch('/{ensemble}','updateEnsemble')->name('admin.ensembles.updateEnsemble'); Route::patch('/{ensemble}', 'updateEnsemble')->name('admin.ensembles.updateEnsemble');
Route::get('/seating-limits','seatingLimits')->name('admin.ensembles.seatingLimits'); Route::get('/seating-limits', 'seatingLimits')->name('admin.ensembles.seatingLimits');
Route::get('/seating-limits/{ensemble}','seatingLimits')->name('admin.ensembles.seatingLimits.ensemble'); Route::get('/seating-limits/{ensemble}', 'seatingLimits')->name('admin.ensembles.seatingLimits.ensemble');
Route::post('/seating-limits/{ensemble}','seatingLimitsSet')->name('admin.ensembles.seatingLimits.ensemble.set'); Route::post('/seating-limits/{ensemble}', 'seatingLimitsSet')->name('admin.ensembles.seatingLimits.ensemble.set');
}); });
// Admin Event Routes // Admin Event Routes
Route::prefix('events')->controller(\App\Http\Controllers\Admin\EventController::class)->group(function() { Route::prefix('events')->controller(\App\Http\Controllers\Admin\EventController::class)->group(function () {
Route::get('/','index')->name('admin.events.index'); Route::get('/', 'index')->name('admin.events.index');
Route::post('/','store')->name('admin.events.store'); Route::post('/', 'store')->name('admin.events.store');
Route::delete('/{event}','destroy')->name('admin.events.destroy'); Route::delete('/{event}', 'destroy')->name('admin.events.destroy');
}); });
// 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')->name('admin.rooms.index'); Route::get('/', 'index')->name('admin.rooms.index');
Route::get('/create','create')->name('admin.rooms.create'); Route::get('/create', 'create')->name('admin.rooms.create');
Route::post('/','store')->name('admin.rooms.store'); Route::post('/', 'store')->name('admin.rooms.store');
Route::post('/{room}/edit','edit')->name('admin.rooms.edit'); Route::post('/{room}/edit', 'edit')->name('admin.rooms.edit');
Route::patch('/{room}','update')->name('admin.rooms.update'); Route::patch('/{room}', 'update')->name('admin.rooms.update');
Route::delete('/{room}','destroy')->name('admin.rooms.destroy'); Route::delete('/{room}', 'destroy')->name('admin.rooms.destroy');
Route::get('/judging_assignments','judgingAssignment')->name('admin.rooms.judgingAssignment'); // Screen to assign judges to rooms Route::get('/judging_assignments', 'judgingAssignment')->name('admin.rooms.judgingAssignment'); // Screen to assign judges to rooms
Route::match(['post', 'delete'], '/{room}/judge', 'updateJudgeAssignment')->name('admin.rooms.updateJudgeAssignment'); Route::match(['post', 'delete'], '/{room}/judge', 'updateJudgeAssignment')->name('admin.rooms.updateJudgeAssignment');
}); });
// Admin Scoring Guides // Admin Scoring Guides
Route::prefix('scoring')->controller(\App\Http\Controllers\Admin\ScoringGuideController::class)->group(function() { Route::prefix('scoring')->controller(\App\Http\Controllers\Admin\ScoringGuideController::class)->group(function () {
Route::get('/','index')->name('admin.scoring.index'); // Scoring Setup Homepage Route::get('/', 'index')->name('admin.scoring.index'); // Scoring Setup Homepage
Route::post('/guides','store')->name('admin.scoring.store'); // Save a new scoring guide Route::post('/guides', 'store')->name('admin.scoring.store'); // Save a new scoring guide
Route::get('/guides/{guide}/edit','edit')->name('admin.scoring.edit'); // Edit scoring guide Route::get('/guides/{guide}/edit', 'edit')->name('admin.scoring.edit'); // Edit scoring guide
Route::patch('/guides/{guide}/edit','update')->name('admin.scoring.update'); // Save changes to audition guide (rename) Route::patch('/guides/{guide}/edit', 'update')->name('admin.scoring.update'); // Save changes to audition guide (rename)
Route::post('/guides/{guide}/subscore','subscore_store')->name('admin.scoring.subscore_store'); // Save a new subscore Route::post('/guides/{guide}/subscore', 'subscore_store')->name('admin.scoring.subscore_store'); // Save a new subscore
Route::post('/reorder-display','reorder_display')->name('admin.scoring.reorder_display'); Route::post('/reorder-display', 'reorder_display')->name('admin.scoring.reorder_display');
Route::post('/reorder-tiebreak','reorder_tiebreak')->name('admin.scoring.reorder_tiebreak'); Route::post('/reorder-tiebreak', 'reorder_tiebreak')->name('admin.scoring.reorder_tiebreak');
}); });
// 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')->name('admin.auditions.index'); Route::get('/', 'index')->name('admin.auditions.index');
Route::get('/create','create')->name('admin.auditions.create'); Route::get('/create', 'create')->name('admin.auditions.create');
Route::post('/','store')->name('admin.auditions.store'); Route::post('/', 'store')->name('admin.auditions.store');
Route::get('/{audition}/edit','edit')->name('admin.auditions.edit'); Route::get('/{audition}/edit', 'edit')->name('admin.auditions.edit');
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 Entries Routes // Admin Entries Routes
Route::prefix('entries')->controller(\App\Http\Controllers\Admin\EntryController::class)->group(function() { Route::prefix('entries')->controller(\App\Http\Controllers\Admin\EntryController::class)->group(function () {
Route::get('/','index'); Route::get('/', 'index');
Route::get('/create','create'); Route::get('/create', 'create');
Route::post('/','store'); Route::post('/', 'store');
Route::get('/{entry}/edit','edit'); Route::get('/{entry}/edit', 'edit');
Route::patch('/{entry}','update'); Route::patch('/{entry}', 'update');
}); });
// Admin Student Routes // Admin Student Routes
Route::prefix('students')->controller(\App\Http\Controllers\Admin\StudentController::class)->group(function() { Route::prefix('students')->controller(\App\Http\Controllers\Admin\StudentController::class)->group(function () {
Route::get('/','index'); Route::get('/', 'index');
Route::get('/create','create'); Route::get('/create', 'create');
Route::post('/','store'); Route::post('/', 'store');
Route::get('/{student}/edit','edit'); Route::get('/{student}/edit', 'edit');
Route::patch('/{student}','update'); Route::patch('/{student}', 'update');
}); });
// Admin School Routes // Admin School Routes
Route::prefix('schools')->controller(\App\Http\Controllers\Admin\SchoolController::class)->group(function() { Route::prefix('schools')->controller(\App\Http\Controllers\Admin\SchoolController::class)->group(function () {
Route::post('/{school}/add_domain','add_domain'); Route::post('/{school}/add_domain', 'add_domain');
Route::get('/','index'); Route::get('/', 'index');
Route::get('/create','create'); Route::get('/create', 'create');
Route::get('/{school}/edit','edit'); Route::get('/{school}/edit', 'edit');
Route::patch('/{school}','update'); Route::patch('/{school}', 'update');
Route::post('/','store'); Route::post('/', 'store');
Route::delete('/domain/{domain}','destroy_domain'); Route::delete('/domain/{domain}', 'destroy_domain');
}); });
// Admin User Routes // Admin User Routes
Route::prefix('users')->controller(\App\Http\Controllers\Admin\UserController::class)->group(function() { Route::prefix('users')->controller(\App\Http\Controllers\Admin\UserController::class)->group(function () {
Route::get('/','index'); Route::get('/', 'index');
Route::get('/create','create'); Route::get('/create', 'create');
Route::post('/','store'); Route::post('/', 'store');
Route::get('/{user}/edit','edit'); Route::get('/{user}/edit', 'edit');
Route::patch('/{user}','update'); Route::patch('/{user}', 'update');
Route::delete('/{user}','destroy'); Route::delete('/{user}', 'destroy');
}); });
}); });
// 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');
Route::get('/profile', [DashboardController::class, 'profile']); Route::get('/profile', [DashboardController::class, 'profile']);
Route::get('/my_school', [DashboardController::class, 'my_school']); Route::get('/my_school', [DashboardController::class, 'my_school']);
}); });
// Entry Related Routes // Entry Related Routes
Route::middleware(['auth','verified','can:create,App\Models\Entry'])->controller(EntryController::class)->group(function() { Route::middleware(['auth', 'verified', 'can:create,App\Models\Entry'])->controller(EntryController::class)->group(function () {
Route::get('/entries','index'); Route::get('/entries', 'index');
Route::get('/entries/create','create'); Route::get('/entries/create', 'create');
Route::post('/entries', 'store'); Route::post('/entries', 'store');
Route::delete('/entries/{entry}', 'destroy'); Route::delete('/entries/{entry}', 'destroy');
}); });
// User Related Routes // User Related Routes
Route::middleware(['auth','verified'])->controller(UserController::class)->group(function() { Route::middleware(['auth', 'verified'])->controller(UserController::class)->group(function () {
Route::patch('/users/{user}/set_school', 'set_school'); Route::patch('/users/{user}/set_school', 'set_school');
Route::patch('/users/{$user}', 'update'); Route::patch('/users/{$user}', 'update');
}); });
// Student Related Routes // Student Related Routes
Route::middleware(['auth','verified','can:create,App\Models\Student'])->controller(StudentController::class)->group(function() { Route::middleware(['auth', 'verified', 'can:create,App\Models\Student'])->controller(StudentController::class)->group(function () {
Route::get('/students','index'); Route::get('/students', 'index');
Route::post('students', 'store'); Route::post('students', 'store');
Route::get('/students/{student}/edit','edit'); Route::get('/students/{student}/edit', 'edit');
Route::patch('/students/{student}','update'); Route::patch('/students/{student}', 'update');
Route::delete('/students/{student}', 'destroy'); Route::delete('/students/{student}', 'destroy');
}); });
// School Related Routes // School Related Routes
Route::middleware(['auth','verified'])->controller(SchoolController::class)->group(function() { Route::middleware(['auth', 'verified'])->controller(SchoolController::class)->group(function () {
Route::get('/schools/create', 'create'); Route::get('/schools/create', 'create');
Route::post('/schools','store'); Route::post('/schools', 'store');
Route::get('/schools/{school}/edit','edit'); Route::get('/schools/{school}/edit', 'edit');
Route::get('/schools/{school}','show'); Route::get('/schools/{school}', 'show');
Route::patch('/schools/{school}','update'); Route::patch('/schools/{school}', 'update');
}); });
// Filter Related Routes // Filter Related Routes
Route::prefix('filters')->middleware(['auth','verified'])->controller(FilterController::class)->group(function() { Route::prefix('filters')->middleware(['auth', 'verified'])->controller(FilterController::class)->group(function () {
Route::post('/admin_entry_filter','adminEntryFilter'); Route::post('/admin_entry_filter', 'adminEntryFilter');
Route::get('/admin_entry_filter/clear','clearAdminEntryFilter'); Route::get('/admin_entry_filter/clear', 'clearAdminEntryFilter');
}); });
//Route::get('/my_school', [SchoolController::class, 'my_school'])->middleware('auth','verified'); //Route::get('/my_school', [SchoolController::class, 'my_school'])->middleware('auth','verified');
@ -210,5 +211,3 @@ Route::prefix('filters')->middleware(['auth','verified'])->controller(FilterCont
//Route::get('/schools/{school}/edit', [SchoolController::class, 'edit'])->middleware('auth','verified'); //Route::get('/schools/{school}/edit', [SchoolController::class, 'edit'])->middleware('auth','verified');
//Route::get('/schools/{school}', [SchoolController::class, 'show'])->middleware('auth','verified'); //Route::get('/schools/{school}', [SchoolController::class, 'show'])->middleware('auth','verified');
//Route::patch('/schools/{school}', [SchoolController::class, 'update'])->middleware('auth','verified'); //Route::patch('/schools/{school}', [SchoolController::class, 'update'])->middleware('auth','verified');