filament_inventory/app/Filament/Pages/Reserve.php
Anna-Sara Sélea 9e275aeeae Fix with mail
2026-09-01 08:11:52 +02:00

293 lines
12 KiB
PHP

<?php
namespace App\Filament\Pages;
use Filament\Pages\Page as BasePage;
use App\Filament\Resources\ItemResource\Pages;
use App\Models\Item;
use App\Models\User;
use App\Models\Category;
use Filament\Tables;
use Filament\Tables\Table;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Radio;
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Actions\CreateAction;
use App\Models\Reserveditem;
use Filament\Forms\Components\TextInput;
use Carbon\Carbon;
use Filament\Infolists\Components\TextEntry;
use Filament\Schemas\Components\Section;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Infolists\Components\ImageEntry;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Actions\Action;
use Filament\Tables\Columns\Layout\Stack;
use Filament\Support\Enums\FontWeight;
use Filament\Support\Enums\TextSize;
use Filament\Tables\Columns\Layout\Grid;
use Filament\Notifications\Notification;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use App\Mail\ReservationCreatedUser;
use App\Mail\ReservationCreated;
use Filament\Forms\Components\Checkbox;
use Throwable;
class Reserve extends BasePage implements HasTable
{
use InteractsWithTable;
protected static bool $shouldRegisterNavigation = false;
public static function getRoutePath(\Filament\Panel $panel): string
{
return '/';
}
protected string $view = 'filament.pages.reserve';
public function getTitle(): string
{
return __('Reserve games');
}
public static function table(Table $table): Table
{
return $table
->query( Item::where('can_be_loaned', true)->whereIn('type', ["game", "literature"]))
->emptyStateHeading(__('No results'))
->searchable(true)
->columns([
Grid::make()
->columns(1)
->schema([
Stack::make([
TextColumn::make('reserved')
->weight(FontWeight::Bold)
->formatStateUsing(fn (string $state): string => $state ? __('On loan') : __('Available'))
->color(fn($record) => $record->reserved ? 'danger' : 'success' )
->badge(),
ImageColumn::make('image')
->label(__('Image'))
->disk('public')
->size('100%')
->extraImgAttributes([
'class' => 'reserve-card-image',
'loading' => 'lazy'
]),
//->visibility('private'),
TextColumn::make('desc')
->label(__('Description'))
->sortable()
->searchable()
->weight(FontWeight::Bold)
->size(TextSize::Large),
Stack::make([
TextColumn::make('players')
->label(__('Players'))
->default(__('No information'))
->sortable()
->prefix(__('Players') . ': '),
//->suffix(' st'),
TextColumn::make('play_time')
->label(__('Play time'))
->sortable()
->default(__('No information'))
->prefix(__('Play time (min)') . ': '),
//->suffix(' min'),
TextColumn::make('age')
->label(__('Age'))
->sortable()
->default(__('No information'))
->prefix(__('Age') . ': ')
//->suffix(' år'),
])
->extraAttributes(['class' => 'reserve-card-meta'])
->hidden(fn ($record) => $record->type === 'literature'),
])->extraAttributes(['class' => 'reserve-card'])
])
])
//->defaultSort('desc', 'asc')
->defaultSort(function (Builder $query): Builder {
return $query
->orderBy('reserved', 'asc')
->orderBy('desc', 'asc');
})
->defaultPaginationPageOption(12)
->paginated([12, 25, 50, 100, 'all'])
->contentGrid([
'sm' => 2,
'md' => 3,
'xl' => 4,
])
->filters([
Filter::make('filters')
->form([
Select::make('type')
->label(__('Type'))
->live()
->options([
'game' => __('Game'),
'literature' => __('Literature')
]),
Select::make('category_id')
->multiple()
->label(__('Category literature'))
->options(Category::all()->whereIn('type', 'literature')->pluck('name', 'id'))
->hidden(fn ($get): string => $get('type') == 'game' || $get('type') == ''),
Select::make('category_id')
->multiple()
->label(__('Category games'))
->options(Category::all()->whereIn('type', 'game')->pluck('name', 'id'))
->hidden(fn ($get): string => $get('type') == 'literature' || $get('type') == ''),
])
->query(function (Builder $query, array $data): Builder {
return $query
->when(
$data['type'],
fn (Builder $query, $type): Builder => $query->where('type', $type),
)
->when(
$data['category_id'],
fn (Builder $query, $category_id): Builder => $query->whereIn('category_id', $category_id),
);
})
->columns([
'deafult' => 1,
'md' => 2,
])
->columnSpan(2),
Filter::make('reserved')
->label(__('Available'))
->query(fn (Builder $query): Builder => $query->where('reserved', false))
->columnSpanFull()
->toggle()
],layout: FiltersLayout::AboveContent)
->actions([
Action::make('reserve')
->label(__('Reserve'))
->button()
->color('primary')
->form([
TextInput::make('username')
->label(__('Name'))
->required(),
TextInput::make('email')
->label(__('Email'))
->email()
->required(),
TextInput::make('phone')
->label(__('Phone'))
->tel()
->required(),
Checkbox::make('gdpr')
->label(__('By checking this box you agree that we store your email address and phone number.'))
->accepted(),
])
->action(function (array $data, Item $record): void {
$reservation = Reserveditem::create([
'item_id' => $record->id,
'reserved_date' => Carbon::now(),
'username' => $data['username'],
'email' => $data['email'],
'phone' => $data['phone']
]);
Item::where('id', $record->id)->update(['reserved' => true]);
// The reservation is already saved, so a mail failure must never
// take down the response for the visitor.
$mailSent = true;
try {
Mail::to($data['email'])
->send(new ReservationCreatedUser($reservation));
} catch (Throwable $exception) {
$mailSent = false;
Log::error('Could not send reservation email to the visitor: ' . $exception->getMessage(), [
'reservation_id' => $reservation->id,
]);
}
if ($adminAddress = config('mail.to_address')) {
try {
Mail::to($adminAddress)
->send(new ReservationCreated($reservation));
} catch (Throwable $exception) {
Log::error('Could not send reservation email to staff: ' . $exception->getMessage(), [
'reservation_id' => $reservation->id,
]);
}
} else {
Log::warning('mail.to_address is not set, no reservation email sent to staff.', [
'reservation_id' => $reservation->id,
]);
}
Notification::make()
->title(__('The game is reserved!'))
->body($mailSent
? __('A confirmation email has been sent to the address you provided. Read it for more information about collecting the game.')
: __('We could not send a confirmation email, but your reservation is registered and we will contact you.'))
->success()
->seconds(10)
->send();
})
->hidden(fn ($record) => $record->reserved),
Action::make('More info')
->translateLabel()
->modalSubmitAction(false)
->infolist([
Section::make('')
->schema([
ImageEntry::make('image')
->translateLabel()
->disk('public')
->width(300)
->height('auto'),
TextEntry::make('desc')
->label('Description')
->translateLabel(),
TextEntry::make('category.name')
->translateLabel(),
TextEntry::make('players')
->translateLabel(),
TextEntry::make('play_time')
->translateLabel(),
TextEntry::make('age')
->translateLabel(),
])
->columns()
->hidden(fn ($record) => $record->type === 'literature'),
Section::make('')
->translateLabel()
->schema([
ImageEntry::make('image')
->translateLabel()
->disk('public'),
TextEntry::make('desc')
->label('Description')
->translateLabel(),
TextEntry::make('category.name')
->translateLabel(),
])
->columns()
->hidden(fn ($record) => $record->type === "game"),
]),
])
->bulkActions([
]);
}
}