Skip to content

Commit

Permalink
Wildcard participants (#58)
Browse files Browse the repository at this point in the history
* Allow to cancel a race

* Identify wildcard when participant register

* Include wildcard info in details and export for timekeeping
  • Loading branch information
avvertix authored Apr 24, 2024
1 parent 9445a36 commit eb51b7b
Show file tree
Hide file tree
Showing 29 changed files with 2,357 additions and 21 deletions.
34 changes: 34 additions & 0 deletions app/Actions/Wildcard/AttributeWildcardBasedOnFirstRace.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace App\Actions\Wildcard;

use App\Models\Race;
use App\Models\Participant;

class AttributeWildcardBasedOnFirstRace
{
/**
* Identify if a participant should have the wildcard status in a race within a championship
*
* @param \App\Models\Participant $participant
* @param \App\Models\Race $race
* @return bool|null the wildcard status
*/
public function __invoke(Participant $participant, Race $race): ?bool
{
$firstRace = $race->championship->races()->closed()->first();

if(is_null($firstRace)){
return false;
}

if($firstRace->is($race)){
return false;
}

return true;
}



}
14 changes: 14 additions & 0 deletions app/Data/WildcardSettingsData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace App\Data;

use App\Models\WildcardStrategy;
use Spatie\LaravelData\Data;

class WildcardSettingsData extends Data
{
public function __construct(
public bool $enabled = false,
public ?WildcardStrategy $strategy = null,
) {}
}
4 changes: 2 additions & 2 deletions app/Exports/RaceParticipantsForTimingExport.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,15 @@ public function map($participant): array

return [
$participant->bib,
$categoryConfiguration->get('timekeeper_label', $categoryConfiguration->name),
$categoryConfiguration->get('timekeeper_label', $categoryConfiguration->name) . ($participant->wildcard ? ' W' : ''),
str($participant->first_name)->lower()->swap($swap)->upper()->toString(),
str($participant->last_name)->lower()->swap($swap)->upper()->toString(),
$registration_identifier,
$registration_identifier,
$transponders->first(),
$transponders->skip(1)->last(),
"",
"",
$participant->wildcard ? 'WILDCARD': '',
($this->race->isZonal() && isset($participant->properties['out_of_zone']) && $participant->properties['out_of_zone']) ? __('Out of zone') : "",
$this->race->event_start_at->toDateString(),
$participant->licence_type->localizedName(),
Expand Down
8 changes: 7 additions & 1 deletion app/Http/Controllers/RaceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ public function update(Request $request, Race $race)
*/
public function destroy(Race $race)
{
//
$race->canceled_at = now();
$race->save();

return to_route('races.show', $race)
->with('flash.banner', __(':race canceled.', [
'race' => $race->title,
]));
}
}
35 changes: 35 additions & 0 deletions app/Listeners/CheckParticipantForWildcard.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Listeners;

use App\Events\ParticipantRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class CheckParticipantForWildcard implements ShouldQueue
{
/**
* Create the event listener.
*/
public function __construct()
{
//
}

/**
* Handle the event.
*/
public function handle(ParticipantRegistered $event): void
{
$championship = $event->race->championship;

if(!$championship->wildcard?->enabled){
return ;
}

$evaluate = $championship->wildcard->strategy->resolve();

$event->participant->wildcard = $evaluate($event->participant, $event->race);
$event->participant->save();
}
}
32 changes: 32 additions & 0 deletions app/Listeners/CheckParticipantIsWildcard.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace App\Listeners;

use App\Events\ParticipantRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class CheckParticipantIsWildcard
{
/**
* Create the event listener.
*/
public function __construct()
{
//
}

/**
* Handle the event.
*/
public function handle(ParticipantRegistered $event): void
{
// $bonus = $event->race->championship->bonuses()->licenceHash($event->participant->driver_licence)->first();

// $useBonus = $bonus?->hasRemaining() ?? false;

if($bonus && $useBonus){
$event->participant->update(['wildcard' => true]);
}
}
}
90 changes: 90 additions & 0 deletions app/Livewire/WildcardSettings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

namespace App\Livewire;

use App\Models\Championship;
use App\Models\WildcardStrategy;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\Enum;
use Laravel\Jetstream\Jetstream;
use Livewire\Attributes\Locked;
use Livewire\Component;

class WildcardSettings extends Component
{

/**
* The create API token form state.
*
* @var array
*/
public $wildcardForm = [
'enabled' => false,
'strategy' => null,
];

#[Locked]
public $championship_id = null;

/**
* Mount the component.
*
* @return void
*/
public function mount(Championship $championship)
{
$this->championship_id = $championship->getKey();

$this->wildcardForm['enabled'] = $championship->wildcard?->enabled ?? false;
$this->wildcardForm['strategy'] = $championship->wildcard?->strategy?->value ?? null;
}

public function updateWildcardSettings()
{
$this->resetErrorBag();

Validator::make([
'wildcard_enabled' => $this->wildcardForm['enabled'],
'wildcard_strategy' => $this->wildcardForm['strategy'],
], [
'wildcard_enabled' => ['required', 'boolean'],
'wildcard_strategy' => ['required', 'integer', new Enum(WildcardStrategy::class)],
])->validateWithBag('updateWildcardSettings');

auth()->user()->can('update', $this->championship);

$this->championship->wildcard->enabled = $this->wildcardForm['enabled'];
$this->championship->wildcard->strategy = WildcardStrategy::from($this->wildcardForm['strategy']);
$this->championship->save();

$this->dispatch('saved');
}

/**
* Get the current user of the application.
*
* @return mixed
*/
public function getUserProperty()
{
return Auth::user();
}


public function getChampionshipProperty()
{
return Championship::find($this->championship_id);
}

public function getStrategiesProperty()
{
return WildcardStrategy::cases();
}


public function render()
{
return view('livewire.wildcard-settings');
}
}
2 changes: 2 additions & 0 deletions app/Models/Championship.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Models;

use App\Data\WildcardSettingsData;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
Expand Down Expand Up @@ -41,6 +42,7 @@ class Championship extends Model
protected $casts = [
'start_at' => 'datetime',
'end_at' => 'datetime',
'wildcard' => WildcardSettingsData::class . ':default',
];

/**
Expand Down
1 change: 1 addition & 0 deletions app/Models/Participant.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class Participant extends Model implements HasLocalePreference
'consents' => AsArrayObject::class,
'use_bonus' => 'boolean',
'properties' => AsArrayObject::class,
'wildcard' => 'boolean',
];

/**
Expand Down
21 changes: 21 additions & 0 deletions app/Models/Race.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class Race extends Model
'event_end_at' => 'datetime',
'registration_opens_at' => 'datetime',
'registration_closes_at' => 'datetime',
'canceled_at' => 'datetime',
'tags' => AsCollection::class,
'properties' => AsArrayObject::class,
'hide' => 'boolean',
Expand Down Expand Up @@ -118,6 +119,10 @@ public function getIsRegistrationOpenAttribute()

public function getStatusAttribute()
{
if(!is_null($this->canceled_at)){
return 'canceled';
}

$todayStartOfDay = today();
$todayEndOfDay = today()->endOfDay();

Expand Down Expand Up @@ -169,10 +174,26 @@ public function scopeActive($query)
$now = now();

return $query
->whereNull('canceled_at')
->where('registration_closes_at', '<=', $now)
->where('event_end_at', '>=', $now);
}

/**
* Filter closed and completed races
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeClosed($query)
{
$now = now();

return $query
->whereNull('canceled_at')
->where('event_end_at', '<', $now);
}

/**
* Filter only visible races
*
Expand Down
29 changes: 29 additions & 0 deletions app/Models/WildcardStrategy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace App\Models;

use App\Actions\Wildcard\AttributeWildcardBasedOnFirstRace;
use Illuminate\Support\Str;

enum WildcardStrategy: int
{
/**
* First non canceled race in championship is used to derive partecipants that can gain points for the championship
*/
case BASED_ON_FIRST_RACE = 10;

// case BASED_ON_BIB_RESERVATION = 20;

// case BASED_ON_BONUS = 30;

public function localizedName(): string
{
return trans("wildcard-options.{$this->name}");
}


public function resolve()
{
return app()->make(AttributeWildcardBasedOnFirstRace::class);
}
}
8 changes: 7 additions & 1 deletion app/Providers/EventServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
namespace App\Providers;

use App\Events\ParticipantRegistered;
use App\Events\ParticipantUpdated;
use App\Listeners\ApplyBonusToParticipant;
use App\Listeners\CheckParticipantForWildcard;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
Expand All @@ -27,7 +29,11 @@ class EventServiceProvider extends ServiceProvider
],
ParticipantRegistered::class => [
ApplyBonusToParticipant::class,
]
CheckParticipantForWildcard::class,
],
ParticipantUpdated::class => [
CheckParticipantForWildcard::class,
],
];

/**
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"livewire/livewire": "^3.0",
"rinvex/countries": "^9.0",
"spatie/laravel-activitylog": "^4.7",
"spatie/laravel-data": "^4.5",
"timokoerber/laravel-one-time-operations": "^1.4",
"vitorccs/laravel-csv": "^1.0"
},
Expand Down
Loading

0 comments on commit eb51b7b

Please sign in to comment.