This project demonstrates how to build a Gantt-style fleet availability calendar as a Filament dashboard widget. The widget displays a 14-day grid where each row is a car and each cell is color-coded by availability status — available, booked, buffer/cleaning, maintenance, or inactive. It uses eager-loaded relationships for bookings and maintenance logs, a priority-based status resolver with per-car buffer periods, and a custom Blade view with a sticky first column, today highlighting, and dark mode support.
This project consists of two components: a Filament widget class that builds the availability data and resolves each cell's status, and a Blade view that renders the Gantt-style grid.
The widget extends Filament's Widget class with a custom Blade view. The getFleetData() method builds the entire grid in a single pass.
app/Filament/Widgets/FleetAvailability.php
class FleetAvailability extends Widget{ protected static ?int $sort = 2; protected int|string|array $columnSpan = 'full'; protected string $view = 'filament.widgets.fleet-availability'; public function getFleetData(): array { $today = Carbon::today(); $days = collect(range(0, 13))->map(fn (int $offset): Carbon => $today->copy()->addDays($offset)); $cars = Car::query() ->orderBy('name') ->with([ 'bookings' => function ($query) use ($today) { $query->whereNotIn('status', [BookingStatus::Cancelled, BookingStatus::NoShow]) ->where('dropoff_at', '>=', $today) ->where('pickup_at', '<=', $today->copy()->addDays(14)); }, 'maintenanceLogs' => function ($query) use ($today) { $query->where(function ($q) use ($today) { $q->where('ended_at', '>=', $today->toDateString()) ->orWhereNull('ended_at'); })->where('started_at', '<=', $today->copy()->addDays(14)->toDateString()); }, ]) ->get(); $grid = []; foreach ($cars as $car) { $row = [ 'car' => $car, 'cells' => [], ]; foreach ($days as $day) { $row['cells'][] = [ 'date' => $day, 'status' => $this->resolveCellStatus($car, $day), ]; } $grid[] = $row; } return [ 'days' => $days, 'grid' => $grid, ]; }}
The key points: