saade / filament-fullcalendar
The Most Popular JavaScript Calendar integrated with Filament 💛
Fund package maintenance!
saade
Installs: 232 903
Dependents: 2
Suggesters: 0
Security: 0
Stars: 299
Watchers: 7
Forks: 89
Open Issues: 14
Requires
- php: ^8.1
- filament/filament: ^3.0
- illuminate/contracts: ^10.0|^11.0
- spatie/laravel-package-tools: ^1.13.5
Requires (Dev)
- nunomaduro/collision: ^7.0|^8.0
- nunomaduro/larastan: ^2.0
- phpstan/extension-installer: ^1.1
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-phpunit: ^1.0
- spatie/laravel-ray: ^1.26
This package is auto-updated.
Last update: 2024-12-12 02:22:27 UTC
README
Features
- Highly customizable
- Modals for viewing, creating, editing and deleteing events Powered by Filament Actions
- Filament-y theme
- and much more!
Table of contents
- Filament FullCalendar
- Features
- Table of contents
- Installation
- Usage
- Configuration
- Interacting with actions
- Intercepting events
- Render Hooks
- Tricks
- Changelog
- Contributing
- Security Vulnerabilities
- Credits
- License
Installation
You can install the package via composer:
composer require saade/filament-fullcalendar:^3.0
Usage
- First, create a Filament Widget:
php artisan make:filament-widget CalendarWidget
This will create a new widget class in your project.
- Your newly created widget should extends the
Saade\FilamentFullCalendar\Widgets\FullCalendarWidget
class of this package
Warning
Don't forget to remove
protected static string $view
from the generated class!
Your widget should look like this:
<?php namespace App\Filament\Widgets; use Saade\FilamentFullCalendar\Widgets\FullCalendarWidget; class CalendarWidget extends FullCalendarWidget { /** * FullCalendar will call this function whenever it needs new event data. * This is triggered when the user clicks prev/next or switches views on the calendar. */ public function fetchEvents(array $fetchInfo): array { // You can use $fetchInfo to filter events by date. // This method should return an array of event-like objects. See: https://github.com/saade/filament-fullcalendar/blob/3.x/#returning-events // You can also return an array of EventData objects. See: https://github.com/saade/filament-fullcalendar/blob/3.x/#the-eventdata-class return []; } }
Returning events
The fetchEvents
method should return an array of event-like objects. See: FullCalendar Docs
<?php namespace App\Filament\Widgets; use Saade\FilamentFullCalendar\Widgets\FullCalendarWidget; use App\Filament\Resources\EventResource; use App\Models\Event; class CalendarWidget extends FullCalendarWidget { public function fetchEvents(array $fetchInfo): array { return Event::query() ->where('starts_at', '>=', $fetchInfo['start']) ->where('ends_at', '<=', $fetchInfo['end']) ->get() ->map( fn (Event $event) => [ 'title' => $event->id, 'start' => $event->starts_at, 'end' => $event->ends_at, 'url' => EventResource::getUrl(name: 'view', parameters: ['record' => $event]), 'shouldOpenUrlInNewTab' => true ] ) ->all(); } }
The EventData class
If you want a fluent way to return events, you can use the Saade\FilamentFullCalendar\Data\EventData
class.
<?php namespace App\Filament\Widgets; use Saade\FilamentFullCalendar\Widgets\FullCalendarWidget; use App\Filament\Resources\EventResource; use App\Models\Event; class CalendarWidget extends FullCalendarWidget { public function fetchEvents(array $fetchInfo): array { return Event::query() ->where('starts_at', '>=', $fetchInfo['start']) ->where('ends_at', '<=', $fetchInfo['end']) ->get() ->map( fn (Event $event) => EventData::make() ->id($event->uuid) ->title($event->name) ->start($event->starts_at) ->end($event->ends_at) ->url( url: EventResource::getUrl(name: 'view', parameters: ['record' => $event]), shouldOpenUrlInNewTab: true ) ) ->toArray(); } }
Configuration
Before you can configure the calendar, you'll need to add FilamentFullcalendarPlugin
to your panel's plugins
array.
<?php namespace App\Providers\Filament; use Filament\Panel; use Filament\PanelProvider; use Saade\FilamentFullCalendar\FilamentFullCalendarPlugin; class AdminPanelProvider extends PanelProvider { public function panel(Panel $panel): Panel { return $panel ->default() ->id('admin') ->path('admin') ... ->plugin( FilamentFullCalendarPlugin::make() ->schedulerLicenseKey() ->selectable() ->editable() ->timezone() ->locale() ->plugins() ->config() ); } }
<?php namespace App\Filament\Widgets; use Saade\FilamentFullCalendar\Widgets\FullCalendarWidget; use App\Models\Event; class CalendarWidget extends FullCalendarWidget { public Model | string | null $model = Event::class; public function config(): array { return [ 'firstDay' => 1, 'headerToolbar' => [ 'left' => 'dayGridWeek,dayGridDay', 'center' => 'title', 'right' => 'prev,next today', ], ]; } }
Available methods
schedulerLicenseKey(string
| null
$licenseKey)
Your FullCalendar Premium License Key. (Only required if you're using premium plugins)
licenceKey
(Default: null
)
selectable(bool
$selectable)
Allows a user to highlight multiple days or timeslots by clicking and dragging. See: selectable
selectable
(Default: false
)
editable(bool
$editable)
This determines if the events can be dragged and resized. See: editable
editable
(Default: false
)
timezone(string
| null
$timezone)
The timezone to use when displaying dates. See: timezone
timezone
(Default: config('app.timezone')
)
locale(string
| null
$locale)
The locale to use when displaying texts and dates. See: locale
locale
(Default: config('app.locale')
)
plugins(array
$plugins, bool
$merge)
The plugins to enable. You can add more plugins if you wish, or replace the default ones by passing false
as the second param for the method.
Avaliable: interaction, dayGrid, timeGrid, list, multiMonth, scrollGrid, timeline, adaptive, resource, resourceDayGrid, resourceTimeline, resourceTimeGrid, rrule, moment, momentTimezone
See: plugins
plugins
Default: ['dayGrid', 'timeGrid']
merge
Default: true
config(array
$config)
The configuration of the calendar. Not all configurations have a dedicated fluent method to interact with it, therefore you can pass pretty much any configuration listed in the FullCalendar's TOC. See: FullCalendar Docs
config
(Default: []
)
Interacting with actions
This packages leverages the power of Filament Actions to allow you to view, create, edit and delete events.
To get started, you'll need to tell the widget which model it should use to perform the actions, and define a form schema for the view, create and edit actions.
<?php namespace App\Filament\Widgets; use Saade\FilamentFullCalendar\Widgets\FullCalendarWidget; use App\Models\Event; class CalendarWidget extends FullCalendarWidget { public Model | string | null $model = Event::class; public function getFormSchema(): array { return [ Forms\Components\TextInput::make('name'), Forms\Components\Grid::make() ->schema([ Forms\Components\DateTimePicker::make('starts_at'), Forms\Components\DateTimePicker::make('ends_at'), ]), ]; } }
Note Please note that the form schema does not need to contain the same fields as the FullCalendar event object. You can add as many fields as your model has.
That's it! Now you can view, create, edit and delete events.
Customizing actions
If you want to customize the actions, you can override the default actions that comes with this package. Actions behaves like any other Filament Action, therefore you can customize them as you wish the same way you would customize any other Filament Action.
<?php namespace App\Filament\Widgets; use Saade\FilamentFullCalendar\Widgets\FullCalendarWidget; use Saade\FilamentFullCalendar\Actions; use App\Models\Event; class CalendarWidget extends FullCalendarWidget { public Model | string | null $model = Event::class; protected function headerActions(): array { return [ Actions\CreateAction::make(), ]; } protected function modalActions(): array { return [ Actions\EditAction::make(), Actions\DeleteAction::make(), ]; } protected function viewAction(): Action { return Actions\ViewAction::make(); } public function getFormSchema(): array { return [ Forms\Components\TextInput::make('name'), Forms\Components\Grid::make() ->schema([ Forms\Components\DateTimePicker::make('starts_at'), Forms\Components\DateTimePicker::make('ends_at'), ]), ]; } }
Authorizing actions
Action authorization behaves like any other Filament Action, therefore you can customize them as you wish the same way you would customize any other Filament Action.
Intercepting events
If you want to intercept events, you can override the default methods that comes with this package.
Warning If you override any of the methods below, you'll need to call the parent method to keep the calendar working as expected.
See the InteractsWithEvents for all the available event listeners.
Render Hooks
If you want to customize the calendar's event rendering, you can use Fullcalendar's built in Render Hooks for that. All the hooks are supported.
Here's an example of how you can use the eventDidMount
hook to add a custom implementation:
public function eventDidMount(): string { return <<<JS function({ event, timeText, isStart, isEnd, isMirror, isPast, isFuture, isToday, el, view }){ // Write your custom implementation here } JS; }
For another example, see the Event tooltip on hover trick.
Tricks
Editing event after drag and drop
You can fill the form with the event's new data by using the mountUsing
method on the EditAction
.
protected function modalActions(): array { return [ Actions\EditAction::make() ->mountUsing( function (Event $record, Forms\Form $form, array $arguments) { $form->fill([ 'name' => $record->name, 'starts_at' => $arguments['event']['start'] ?? $record->starts_at, 'ends_at' => $arguments['event']['end'] ?? $record->ends_at ]); } ), Actions\DeleteAction::make(), ]; }
Creating events on day selection
You can fill the form with the selected day's date by using the mountUsing
method on the CreateAction
.
use Saade\FilamentFullCalendar\Actions\CreateAction; protected function headerActions(): array { return [ Actions\CreateAction::make() ->mountUsing( function (Forms\Form $form, array $arguments) { $form->fill([ 'starts_at' => $arguments['start'] ?? null, 'ends_at' => $arguments['end'] ?? null ]); } ) ]; }
Creating events with additional data
You can add additional data to the event by using the mutateFormDataUsing
method on the CreateAction
.
protected function headerActions(): array { return [ Actions\CreateAction::make() ->mutateFormDataUsing(function (array $data): array { return [ ...$data, 'calendar_id' => $this->record->id ]; }) ]; }
Event tooltip on hover
You can add a tooltip to fully show the event title when the user hovers over the event via JavaScript on the eventDidMount
method:
public function eventDidMount(): string { return <<<JS function({ event, timeText, isStart, isEnd, isMirror, isPast, isFuture, isToday, el, view }){ el.setAttribute("x-tooltip", "tooltip"); el.setAttribute("x-data", "{ tooltip: '"+event.title+"' }"); } JS; }
The JavaScript code returned by eventDidMount()
will be added to the FullCalendar's eventDidMount
event render hook.
Adding the widget to a Blade view
Follow the Filament Docs to know how to add the widget to a Blade view.
Share your tricks
If you have any tricks that you want to share, please open a PR and add it to this section.
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.