Participant resource

This commit is contained in:
Anna-Sara Sélea 2025-11-15 17:06:44 +01:00
parent 29b3b75119
commit 84162b577d
12 changed files with 746 additions and 0 deletions

View file

@ -0,0 +1,32 @@
<?php
namespace App\Filament\Resources\Participants\Pages;
use App\Filament\Resources\Participants\ParticipantResource;
use Filament\Resources\Pages\CreateRecord;
use App\Models\Participant;
use App\Models\Version;
class CreateParticipant extends CreateRecord
{
protected static string $resource = ParticipantResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$count = Participant::where('is_visiting', false)->count();
if ($count < 1 && !$data['is_visiting']) {
$data['status'] = "lan";
}
else if ($data['is_visiting']) {
$data['status'] = "besök";
}
else {
$data['status'] = "reserv";
}
return $data;
}
}

View file

@ -0,0 +1,20 @@
<?php
namespace App\Filament\Resources\Participants\Pages;
use App\Filament\Resources\Participants\ParticipantResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditParticipant extends EditRecord
{
protected static string $resource = ParticipantResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}

View file

@ -0,0 +1,20 @@
<?php
namespace App\Filament\Resources\Participants\Pages;
use App\Filament\Resources\Participants\ParticipantResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListParticipants extends ListRecords
{
protected static string $resource = ParticipantResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View file

@ -0,0 +1,51 @@
<?php
namespace App\Filament\Resources\Participants;
use App\Filament\Resources\Participants\Pages\CreateParticipant;
use App\Filament\Resources\Participants\Pages\EditParticipant;
use App\Filament\Resources\Participants\Pages\ListParticipants;
use App\Filament\Resources\Participants\Schemas\ParticipantForm;
use App\Filament\Resources\Participants\Tables\ParticipantsTable;
use App\Models\Participant;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use DiscoveryDesign\FilamentGaze\Forms\Components\GazeBanner;
class ParticipantResource extends Resource
{
protected static ?string $model = Participant::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
protected static ?string $recordTitleAttribute = 'first_name';
public static function form(Schema $schema): Schema
{
return ParticipantForm::configure($schema);
}
public static function table(Table $table): Table
{
return ParticipantsTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListParticipants::route('/'),
'create' => CreateParticipant::route('/create'),
//'edit' => EditParticipant::route('/{record}/edit'),
];
}
}

View file

@ -0,0 +1,102 @@
<?php
namespace App\Filament\Resources\Participants\Schemas;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
use Filament\Forms\Components\Radio;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Schemas\Components\Grid;
use DiscoveryDesign\FilamentGaze\Forms\Components\GazeBanner;
class ParticipantForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
GazeBanner::make()
->pollTimer(10)
->hideOnCreate(),
Grid::make()
->columnSpan('full')
->columns(2)
->schema([
Grid::make()
->columns(1)
->schema([
Radio::make('is_visiting')
->label('Participating type')
->boolean(falseLabel: 'LAN', trueLabel: 'Visit'),
]),
Grid::make()
->columns(2)
->schema([
Grid::make()
->columns(1)
->schema([
Toggle::make('emailed')
->required()
->onColor('success')
->offColor('danger'),
Toggle::make('member')
->required()
->onColor('success')
->offColor('danger'),
]),
Grid::make()
->columns(1)
->schema([
Toggle::make('paid')
->required()
->onColor('success')
->offColor('danger'),
Toggle::make('gdpr')
->required()
->onColor('success')
->offColor('danger'),
])
]),
]),
TextInput::make('lan_id')
->integer(),
Select::make('status')
->options([
'lan' => 'Ordinarie',
'reserv' => 'Reserv',
'besök' => 'Besök',
]),
TextInput::make('first_name')
->required(),
TextInput::make('surname')
->required(),
TextInput::make('grade')
->integer()
->columnSpan('full')
->required(),
TextInput::make('phone')
->tel()
->default(null),
TextInput::make('email')
->label('Email address')
->email()
->default(null),
TextInput::make('guardian_name')
->required(),
TextInput::make('guardian_phone')
->tel()
->required(),
TextInput::make('guardian_email')
->required(),
TextInput::make('special_diet')
->default(null),
TextInput::make('friends')
->default(null)
->columnSpan('full'),
Textarea::make('comment')
->columnSpan('full'),
]);
}
}

View file

@ -0,0 +1,174 @@
<?php
namespace App\Filament\Resources\Participants\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use App\Models\Participant;
use App\Models\Mailtemplate;
use Filament\Tables\Columns\SelectColumn;
use Filament\Actions\Action;
use Filament\Forms\Components\Select;
use Illuminate\Support\Facades\Mail;
use App\Mail\LanMail;
use Filament\Support\Icons\Heroicon;
use App\Filament\Exports\ParticipantExporter;
use Filament\Actions\ExportAction;
use Filament\Tables\Columns\TextInputColumn;
use Filament\Tables\Grouping\Group;
use Filament\Tables\Columns\Summarizers\Count;
class ParticipantsTable
{
public static function configure(Table $table): Table
{
return $table
->groups([
Group::make('status')
->label('Status')
->collapsible(),
])
->defaultGroup('status')
//->groupsOnly()
->recordAction(null)
->headerActions([
ExportAction::make()
->exporter(ParticipantExporter::class),
])
->columns([
TextColumn::make('lan_id')
->label('ID')
->searchable()
->sortable(),
TextColumn::make('status')
->label('Status')
->badge()
->summarize(Count::make()->label(''))
->color(fn (string $state): string => match ($state) {
'lan' => 'success',
'reserv' => 'warning',
'besök' => 'gray'
})
->formatStateUsing(fn (string $state): string => __(ucfirst($state))),
IconColumn::make('paid')
->boolean()
->sortable(),
IconColumn::make('emailed')
->boolean()
->sortable(),
TextColumn::make('first_name')
->searchable()
->sortable(),
TextColumn::make('surname')
->searchable()
->sortable(),
TextColumn::make('grade')
->searchable()
->sortable(),
TextColumn::make('phone')
->searchable()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('email')
->label('Email address')
->searchable()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('guardian_name')
->searchable()
->sortable(),
TextColumn::make('guardian_phone')
->searchable()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('guardian_email')
->searchable()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('is_visiting')
->label('Type')
->formatStateUsing(fn (string $state): string => $state?'visit':'lan')
->searchable()
->sortable()
->badge()
->color('gray')
->toggleable(isToggledHiddenByDefault: true),
IconColumn::make('member')
->boolean()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('comment')
->sortable()
->toggleable(isToggledHiddenByDefault: true),
IconColumn::make('gdpr')
->boolean()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('friends')
->searchable()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('special_diet')
->searchable()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make()
->modalWidth()
->slideOver(),
Action::make('sendEmail')
->label('Send email')
->icon(Heroicon::Envelope)
->schema([
Select::make('mailtemplate')
->label('Mailtemplate')
->options(Mailtemplate::all()->pluck('title', 'id'))
])
->action(function (array $data, Participant $record) {
$mailContent = Mailtemplate::where('id', $data['mailtemplate'])->get();
Mail::to($record->guardian_email)
->send(new LanMail($mailContent, $record));
Participant::where('id', $record->id)->update(['emailed' => true]);
})
->hidden(fn($record) => $record->emailed),
Action::make('sendRemindEmail')
->label('Send remind email')
->icon(Heroicon::Envelope)
->schema([
Select::make('mailtemplate')
->label('Mailtemplate')
->options(Mailtemplate::all()->pluck('title', 'id'))
])
->action(function (array $data, Participant $record) {
$mailContent = Mailtemplate::where('id', $data['mailtemplate'])->get();
Mail::to($record->guardian_email)
->send(new LanMail($mailContent, $record));
Participant::where('id', $record->id)->update(['emailed' => true]);
})
->hidden(fn($record) => !$record->emailed)
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View file

@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\Users\Pages;
use App\Filament\Resources\Users\UserResource;
use Filament\Resources\Pages\CreateRecord;
class CreateUser extends CreateRecord
{
protected static string $resource = UserResource::class;
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Users\Pages;
use App\Filament\Resources\Users\UserResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditUser extends EditRecord
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Users\Pages;
use App\Filament\Resources\Users\UserResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListUsers extends ListRecords
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View file

@ -0,0 +1,174 @@
<?php
namespace App\Http\Controllers;
use App\Models\Participant;
use App\Models\Volunteer;
use App\Models\Version;
use Illuminate\Http\Request;
class ParticipantController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
$ability = $request->ability;
if ($ability === "key_1") {
$participants = Participant::all()->makeHidden(['comment', 'emailed', 'paid', 'member', 'gdpr']);
$volunteers = Volunteer::all()->makeHidden(['gdpr']);
$dataArr = [
'participant' => $participants,
'volunteer' => $volunteers
];
return $dataArr;
}
if ($ability === "key_2") {
$participants = Participant::all()->select('participant_id', 'first_name', 'surname');
$volunteers = Volunteer::all()->select('first_name', 'surname');
$dataArr = [
'participant' => $participants,
'volunteer' => $volunteers
];
return $dataArr;
}
if ($ability === "key_3") {
$participants = Participant::all()->makeHidden(['comment', 'emailed', 'paid', 'member', 'gdpr']);
return $participants;
}
if ($ability === "key_4") {
$participants = Participant::all()->select('participant_id', 'first_name', 'surname');
return $participants;
}
return false;
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$ability = $request->ability;
if ($ability === "key_1") {
$request->validate([
'member' => 'required',
'first_name' => 'required',
'surname' => 'required',
'grade' => 'required',
'phone' => 'nullable',
'email' => 'nullable',
'guardian_name' => 'required',
'guardian_phone' => 'required',
'guardian_email' => 'required',
'visiting' => 'required',
'gdpr' => 'required',
'friends' => 'nullable',
'special_diet' => 'nullable',
]);
$count = Participant::where('visiting', 0)->count();
$status = "";
if ($count < 2 && $request->visiting === 0) {
$status = "lan";
}
else if ($request->visiting === 1) {
$status = "besök";
}
else {
$status = "reserv";
}
Participant::create([
'member' => $request->member,
'first_name' => $request->first_name,
'surname' => $request->surname,
'grade' => $request->grade,
'phone' => $request->phone,
'email' => $request->email,
'guardian_name' => $request->guardian_name,
'guardian_phone' => $request->guardian_phone,
'guardian_email' => $request->guardian_email,
'visiting' => $request->visiting,
'gdpr' => $request->gdpr,
'friends' => $request->friends,
'special_diet' => $request->special_diet,
'status' => $status
]);
return response()->json([
'success' => true, 'message' => 'Participant was created successfully'
]);
}
return response()->json([
'success' => false, 'message' => 'Unauthorized'
]);
}
/**
* Display the specified resource.
*/
public function show(Participant $participant)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Participant $participant)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Participant $participant)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Participant $participant)
{
//
}
}

View file

@ -0,0 +1,79 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Version;
class Participant extends Model
{
protected $fillable = [
'member',
'lan_id',
'first_name',
'surname',
'grade',
'phone',
'email',
'guardian_name',
'guardian_phone',
'guardian_email',
'is_visiting',
'gdpr',
'friends',
'special_diet',
'status',
'emailed',
'comment',
'paid'
];
protected static function booted()
{
static::created(function ($post) {
$latest_version = Version::where('table', 'participants')->latest()->first();
if($latest_version) {
Version::create([
'table' => 'participants',
'version' => $latest_version->version + 1,
]);
} else {
Version::create([
'table' => 'participants',
'version' => 1,
]);
}
});
static::updated(function ($post) {
$latest_version = Version::where('table', 'participants')->latest()->first();
if($latest_version) {
Version::create([
'table' => 'participants',
'version' => $latest_version->version + 1,
]);
} else {
Version::create([
'table' => 'participants',
'version' => 1,
]);
}
});
static::deleted(function ($post) {
$latest_version = Version::where('table', 'participants')->latest()->first();
if($latest_version) {
Version::create([
'table' => 'participants',
'version' => $latest_version->version + 1,
]);
} else {
Version::create([
'table' => 'participants',
'version' => 1,
]);
}
});
}
}

View file

@ -0,0 +1,45 @@
<?php
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('participants', function (Blueprint $table) {
$table->id();
$table->integer('lan_id')->nullable();
$table->boolean('member');
$table->string('first_name');
$table->string('surname');
$table->string('grade');
$table->string('phone')->nullable();
$table->string('email')->nullable();
$table->string('guardian_name');
$table->string('guardian_phone');
$table->string('guardian_email');
$table->boolean('is_visiting')->default(false);
$table->boolean('gdpr')->default(false);
$table->string('friends')->nullable();
$table->string('special_diet')->nullable();
$table->string('status')->nullable();
$table->boolean('paid')->default(false);
$table->boolean('emailed')->default(false);
$table->string('comment')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('participants');
}
};