Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Livewire Resource Time Grid Laravel Package

asantibanez/livewire-resource-time-grid

A Laravel Livewire component for displaying resources in a configurable time grid. Schedule and visualize events or reservations across days, weeks, or custom time slots, with model integration, date ranges, and customizable views for booking and resource-planning interfaces.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package with Composer; there are no migrations or required asset builds:

composer require asantibanez/livewire-resource-time-grid

As of v1.6.0 the package supports Laravel 12 (alongside the earlier supported majors), so it can be used on a current Laravel app without a composer.json constraint workaround. The package is a single Livewire component. You either render it directly with arrays or, more commonly, extend its component class and supply the two data sources it needs: a list of resources (columns — rooms, technicians, machines) and a list of events (blocks placed on a resource at a time range for the displayed day). The fastest first use case is a "today" scheduling board: one column per room, one row per hour, bookings rendered as blocks.

namespace App\Livewire;

use App\Models\Booking;
use App\Models\Room;
use Asantibanez\LivewireResourceTimeGrid\LivewireResourceTimeGrid;

class RoomSchedule extends LivewireResourceTimeGrid
{
    public function resources(): array
    {
        return Room::orderBy('name')->get()
            ->map(fn ($room) => ['id' => $room->id, 'title' => $room->name])
            ->all();
    }

    public function events(): array
    {
        return Booking::with('room')
            ->whereDate('starts_at', today())
            ->get()
            ->map(fn ($booking) => [
                'id' => $booking->id,
                'resourceId' => $booking->room_id,
                'title' => $booking->title,
                'start' => $booking->starts_at->toDateTimeString(),
                'end' => $booking->ends_at->toDateTimeString(),
            ])
            ->all();
    }
}

Then render it like any Livewire component (<livewire:room-schedule />). Where to look first: the package README for the exact prop names and event array shape in your installed version, then src/LivewireResourceTimeGrid.php and its Blade view — the source is small enough to read end-to-end in ten minutes, which is the best way to understand the click hooks (onEventClick, onTimeSlotClick, onResourceClick or their equivalents) and the hour-range/height configuration props. Wire one click hook to dd() before writing any UI.

Implementation Patterns

Subclass for data, keep the parent for rendering. Override resources() and events() rather than passing big arrays from a parent component; it keeps the grid self-contained and lets Livewire re-query on each round trip. If your version supports props, passing :resources/:events is fine for read-only dashboards.

Treat the grid as a view, not a form. The typical workflow is: click an empty slot → open a modal prefilled with resourceId + time → save → the component re-renders and re-queries events(). Click an event → open an edit/delete modal. Keep the modal in the same component (or a child) so the grid refresh is automatic.

public function onTimeSlotClick($resourceId, $time): void
{
    $this->dispatch('booking-create-requested', roomId: $resourceId, startsAt: $time);
}

public function onEventClick($eventId): void
{
    $this->dispatch('booking-edit-requested', bookingId: $eventId);
}

Scope everything server-side. Filter resources by the authenticated user's permissions and events by the visible date in the query itself — never in Blade. The component receives IDs from the browser, so re-validate ownership/availability in the save handler, not just in the click callback.

Date navigation. For multi-day use, add a public $date property, use it in the events() query, and render one grid per selected day (with wire:key including the date). Avoid showing a week in one grid unless you've confirmed the package supports it; the component is built around a single day with resource columns.

Testing. The component is testable with Livewire::test(RoomSchedule::class); assert the rendered output contains event titles and that click hooks dispatch the expected events (assertDispatched on Livewire 3, assertEmitted on v2). Seed two resources and one overlapping booking to catch layout issues early.

Composition over inheritance. If you need the grid inside a larger dashboard, wrap it in a parent component and communicate via dispatched events rather than overriding every hook — this keeps the package upgrade surface small.

Gotchas and Tips

  • Plain arrays, not models or Collections. Both resources() and events() must return arrays of arrays with the exact keys the view expects. ->get() instead of ->all() is the most common silent failure.
  • ID types must match. If resourceId is an integer in events but a string in resources (or vice versa), blocks land in the wrong column or vanish. Cast consistently.
  • Time format and timezone. Events are matched to slots by their datetime strings; use one timezone (your app's) for storage and rendering, and parse with Carbon only inside your hooks. Off-by-one-hour bugs are almost always a UTC/local mismatch.
  • Events outside the hour window disappear. Setting a starting/ending hour (e.g. 8–18) silently hides bookings that start earlier or end later. Clamp or extend the range when data can fall outside it.
  • Every click is a full round trip. Keep events() constrained to the displayed day, eager-load relations used in the mapping, and avoid loading hundreds of bookings. If the grid feels slow, the query is the problem, not the component.
  • Styling. The view ships with Tailwind classes; if your build purges them, add the package's view path to content in tailwind.config.js or publish/override the Blade view. Publishing views is also the cleanest extension point for custom event colors or labels.
  • Framework and Livewire version constraints. v1.6.0 is the first release to support Laravel 12; on older tags the composer.json constraints will block the install. Event dispatch APIs differ between Livewire 2 and 3, so after adding Laravel 12 support, confirm the resolved package version still matches your Livewire major and pin accordingly.
  • Untrusted click payloads. IDs and times originating from the browser must be re-validated (resource exists, slot is free, user is authorized) before persisting.
  • Maintenance risk. This is a small, single-maintainer package with a narrow user base, and the v1.6.0 change is purely a compatibility bump — no new features. Read the source, pin the version in composer.json, and be prepared to fork or override the Blade view if you need behavior the component doesn't expose — the codebase is small enough that forking is a realistic fallback rather than a last resort.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core