d4ve-r/livewire-resource-time-grid
A Livewire component for Laravel that renders a resource-based time grid, making it easy to schedule and visualize events across multiple resources with configurable time slots and a customizable calendar-style interface.
This package provides a Livewire component that renders a resource-by-time grid — typically used for booking calendars (rooms, staff, equipment) where resources occupy one axis and time slots the other.
v0.0.1 release, install with an explicit constraint ("d4ve-r/livewire-resource-time-grid": "^0.0.1") rather than a floating dev-* constraint, so a mid-cycle change doesn't silently break your calendar.stable branch referenced in the changelog — the two are not interchangeable.0.0.x there is usually no formal API docs; the example Livewire component and Blade view in the repo are the de facto specification for the props, slot-selection events, and callback names.php artisan vendor:publish --tag=...). You will almost certainly need to override the Blade view for styling — a time grid's default markup rarely matches an existing design system.RoomBookingCalendar Livewire component that lists Room models as resources and Booking models as events, render it on one page, and click a slot to confirm the event payload contains the resource + datetime you expect. Do this before wiring any persistence.Wrap, don't embed. Create a thin Livewire component of your own (CalendarComponent) that composes the package component in its Blade view. Keep your queries, authorization, and validation in your component and pass the finished data down — this gives you a seam to swap the package out later, which at 0.0.x is a realistic possibility.
Feed it query results, not relationships. Resolve resources and events in mount()/render() with explicit ->with() eager loads and a date-window whereBetween on your start/end columns. Grids invite N+1 queries because every resource renders its own slots; a hundred resources will surface this immediately.
Handle slot selection as an event, then validate server-side. The typical flow is: user clicks an empty cell → package emits an event with resource id + timestamp → your listener opens a form → on submit you re-query for overlap and reject with a validation error. Never trust the client-side slot payload as proof the slot is free; concurrent bookings will race.
Keep the grid stateless and re-render on navigation. Rather than mutating rows in JS, drive previousWeek() / nextWeek() style navigation through public properties on your component so the grid is a pure function of (startDate, resources, events). This makes Livewire::test() assertions straightforward and avoids hydration surprises.
Use policies for per-resource permissions. If some users can only book certain resources, filter the resource collection in PHP rather than hiding cells in the view; a grid that renders disabled cells still leaks the existence of resources and their occupancy.
Normalize timezones at the boundary. Store UTC, render in the user's timezone by converting your event models before handing them to the component. Mixing the two is the single most common source of "my 9am meeting shows at 4pm" bugs in calendar integrations.
0.0.x bump can rename props or change event payloads. Lock the version in composer.json, and after any upgrade click through a booking end-to-end before deploying.stable branch, expect to update: $emit() → $this->dispatch(), dispatchBrowserEvent() → dispatch() with browser-event naming, wire:model now deferred by default (use wire:model.live where the grid needs immediate sync), and any Alpine x-init/@entangle wiring. Also confirm @livewireStyles/@livewireScripts (or @assets) are present, or the grid will render as an unstyled table.wire:model is the most likely silent breakage. A filter dropdown wired with plain wire:model in a Livewire 3 app won't re-render the grid until the next request. Switch those bindings to .live.php artisan config:clear after edits — cached config is a routine cause of "my changes to the grid settings do nothing."Livewire::test(CalendarComponent::class)->call('nextWeek')->assertSee(...) plus an overlap-rejection test will catch most upgrade regressions and costs little to maintain.How can I help you explore Laravel packages today?