diff --git a/app/Http/Controllers/Admin/DrawController.php b/app/Http/Controllers/Admin/DrawController.php
new file mode 100644
index 0000000..6578e94
--- /dev/null
+++ b/app/Http/Controllers/Admin/DrawController.php
@@ -0,0 +1,68 @@
+drawService = $drawService;
+ }
+
+ public function index(Request $request)
+ {
+ $events = Event::with('auditions')->get();
+ // $drawnAuditionsExist is true if any audition->hasFlag('drawn') is true
+ $drawnAuditionsExist = Audition::whereHas('flags', function ($query) {
+ $query->where('flag_name', 'drawn');
+ })->exists();
+
+ return view('admin.draw.index', compact('events', 'drawnAuditionsExist'));
+ }
+
+ public function store(RunDrawRequest $request)
+ {
+ $auditions = Audition::with('flags')->findMany(array_keys($request->input('audition', [])));
+
+ if ($this->drawService->checkCollectionForDrawnAuditions($auditions)) {
+ return to_route('admin.draw.index')->with('error',
+ 'Invalid attempt to draw an audition that has already been drawn');
+ }
+
+ $this->drawService->runDrawsOnCollection($auditions);
+
+ return to_route('admin.draw.index')->with('status', 'Draw completed successfully');
+ }
+
+ public function edit(Request $request)
+ {
+ $drawnAuditions = Audition::whereHas('flags', function ($query) {
+ $query->where('flag_name', 'drawn');
+ })->get();
+
+ return view('admin.draw.edit', compact('drawnAuditions'));
+ }
+
+ public function destroy(ClearDrawRequest $request)
+ {
+ $auditions = Audition::with('flags')->findMany(array_keys($request->input('audition', [])));
+ $this->drawService->clearDrawsOnCollection($auditions);
+
+ return to_route('admin.draw.index')->with('status', 'Draw completed successfully');
+
+ }
+}
diff --git a/app/Http/Requests/ClearDrawRequest.php b/app/Http/Requests/ClearDrawRequest.php
new file mode 100644
index 0000000..d4b12ee
--- /dev/null
+++ b/app/Http/Requests/ClearDrawRequest.php
@@ -0,0 +1,53 @@
+ ['required', 'array'],
+ ];
+ }
+
+ public function messages(): array
+ {
+ return [
+ 'audition.required' => 'No auditions were selected',
+ 'audition.array' => 'Invalid request format',
+ ];
+ }
+
+ public function withValidator($validator): void
+ {
+ $validator->after(function ($validator) {
+ foreach ($this->input('audition', []) as $auditionId => $value) {
+ if (! is_numeric($auditionId) || ! Audition::where('id', $auditionId)->exists()) {
+ $validator->errors()->add('audition', 'One or more invalid auditions were selected');
+ }
+ }
+ });
+
+ }
+
+ protected function failedValidation(Validator $validator)
+ {
+ $msg = $validator->errors()->get('audition')[0];
+
+ return to_route('admin.draw.index')->with('error', $msg);
+ }
+}
diff --git a/app/Http/Requests/RunDrawRequest.php b/app/Http/Requests/RunDrawRequest.php
new file mode 100644
index 0000000..dfb0e22
--- /dev/null
+++ b/app/Http/Requests/RunDrawRequest.php
@@ -0,0 +1,53 @@
+ ['required', 'array'],
+ ];
+ }
+
+ public function messages(): array
+ {
+ return [
+ 'audition.required' => 'No auditions were selected',
+ 'audition.array' => 'Invalid request format',
+ ];
+ }
+
+ public function withValidator($validator): void
+ {
+ $validator->after(function ($validator) {
+ foreach ($this->input('audition', []) as $auditionId => $value) {
+ if (! is_numeric($auditionId) || ! Audition::where('id', $auditionId)->exists()) {
+ $validator->errors()->add('audition', 'One or more invalid auditions were selected');
+ }
+ }
+ });
+
+ }
+
+ protected function failedValidation(Validator $validator)
+ {
+ $msg = $validator->errors()->get('audition')[0];
+
+ return to_route('admin.draw.index')->with('error', $msg);
+ }
+}
diff --git a/app/Models/Event.php b/app/Models/Event.php
index 2df0d6a..b8b9726 100644
--- a/app/Models/Event.php
+++ b/app/Models/Event.php
@@ -13,7 +13,7 @@ class Event extends Model
public function auditions(): HasMany
{
- return $this->hasMany(Audition::class);
+ return $this->hasMany(Audition::class)->orderBy('score_order');
}
public function ensembles(): HasMany
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index 8d6a8d7..6d1eea9 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -36,6 +36,7 @@ use App\Observers\SubscoreDefinitionObserver;
use App\Observers\UserObserver;
use App\Services\AuditionService;
use App\Services\DoublerService;
+use App\Services\DrawService;
use App\Services\EntryService;
use App\Services\ScoreService;
use App\Services\SeatingService;
@@ -43,6 +44,7 @@ use App\Services\TabulationService;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;
+
class AppServiceProvider extends ServiceProvider
{
/**
@@ -50,6 +52,10 @@ class AppServiceProvider extends ServiceProvider
*/
public function register(): void
{
+ $this->app->singleton(DrawService::class, function () {
+ return new DrawService();
+ });
+
$this->app->singleton(AuditionService::class, function () {
return new AuditionService();
});
diff --git a/app/Services/DrawService.php b/app/Services/DrawService.php
new file mode 100644
index 0000000..53d162c
--- /dev/null
+++ b/app/Services/DrawService.php
@@ -0,0 +1,54 @@
+where('audition_id', $audition->id)->update(['draw_number' => null]);
+
+ $randomizedEntries = $audition->entries->shuffle();
+ foreach ($randomizedEntries as $index => $entry) {
+ $entry->draw_number = $index + 1;
+ $entry->save();
+ }
+ $audition->addFlag('drawn');
+ }
+
+ public function runDrawsOnCollection($auditions): void
+ {
+ $auditions->each(fn ($audition) => $this->runOneDraw($audition));
+ }
+
+ public function checkCollectionForDrawnAuditions($auditions): bool
+ {
+
+ $auditions->loadMissing('flags');
+
+ return $auditions->contains(fn ($audition) => $audition->hasFlag('drawn'));
+ }
+
+ public function clearDrawForAudition(Audition $audition): void
+ {
+ $audition->removeFlag('drawn');
+ DB::table('entries')->where('audition_id', $audition->id)->update(['draw_number' => null]);
+ }
+
+ public function clearDrawsOnCollection($auditions): void
+ {
+ $auditions->each(fn ($audition) => $this->clearDrawForAudition($audition));
+ }
+}
diff --git a/resources/views/admin/draw/clear-draw-modal-confirm.blade.php b/resources/views/admin/draw/clear-draw-modal-confirm.blade.php
new file mode 100644
index 0000000..56ee072
--- /dev/null
+++ b/resources/views/admin/draw/clear-draw-modal-confirm.blade.php
@@ -0,0 +1,117 @@
+@php
+/**
+ * @var int $size=20 Size of the icon
+ */
+@endphp
+@props(['size' => 20])
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Really Clear the draw??
+
+
+
+ Click confirm below if you're sure. After doing so, be sure to destroy any materials you may have printed for those
+ auditions to avoid any chance of confusion on audition day.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/views/admin/draw/clear-draw-warning.blade.php b/resources/views/admin/draw/clear-draw-warning.blade.php
new file mode 100644
index 0000000..ba9c916
--- /dev/null
+++ b/resources/views/admin/draw/clear-draw-warning.blade.php
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
Caution!!!
+
+
+
This will clear any existing draw numbers
+
Any cards, sign in sheets or other materials you've printed will be invalid
+
This action cannot be undone
+
+
+
+
+
diff --git a/resources/views/admin/draw/drawn-auditions-exist-notification.blade.php b/resources/views/admin/draw/drawn-auditions-exist-notification.blade.php
new file mode 100644
index 0000000..7a5d53d
--- /dev/null
+++ b/resources/views/admin/draw/drawn-auditions-exist-notification.blade.php
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
Some auditions have already been drawn.
+ Click here
+ to clear previous draws.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/views/admin/draw/edit.blade.php b/resources/views/admin/draw/edit.blade.php
new file mode 100644
index 0000000..28e6eaa
--- /dev/null
+++ b/resources/views/admin/draw/edit.blade.php
@@ -0,0 +1,37 @@
+@php
+ /**
+ * @var \App\Models\Audition[] $drawnAuditions A collection of all auditions that have been drawn
+ */
+@endphp
+
+
+ @include('admin.draw.clear-draw-warning')
+
+
+
+
+ Previously Drawn Auditions
+
+
+
+
+
+
+ @foreach($drawnAuditions as $audition)
+
+
+ {{$audition->name}}
+
+ @endforeach
+
+
+
+
+ Clear Draw
+
+
+ @include('admin.draw.clear-draw-modal-confirm')
+
+
+
+
diff --git a/resources/views/admin/draw/index.blade.php b/resources/views/admin/draw/index.blade.php
new file mode 100644
index 0000000..ad9e992
--- /dev/null
+++ b/resources/views/admin/draw/index.blade.php
@@ -0,0 +1,41 @@
+@php
+ /**
+ * @var \App\Models\Event[] $events A collection of all events with auditions
+ * @var bool $drawnAuditionsExist A boolean value indicating if there are any drawn auditions
+ */
+@endphp
+
+
+ @if($drawnAuditionsExist)
+ @include('admin.draw.drawn-auditions-exist-notification')
+ @endif
+
+ @foreach($events as $event)
+ @continue($event->auditions->isEmpty())
+
+
+ {{ $event->name }}
+
+
+
+
+
+
+ @foreach($event->auditions as $audition)
+ @continue($audition->hasFlag('drawn'))
+