Coder Social home page Coder Social logo

filament-fullcalendar's Introduction

Filament FullCalendar

Latest Version on Packagist Total Downloads

Filament FullCalendar

Features

  • Highly customizable
  • Modals for viewing, creating, editing and deleteing events Powered by Filament Actions
  • Filament-y theme
  • and much more!

Table of contents


Installation

You can install the package via composer:

composer require saade/filament-fullcalendar:^3.0

Usage

  1. First, create a Filament Widget:
php artisan make:filament-widget CalendarWidget

This will create a new widget class in your project.


  1. 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.

Sponsor Saade

filament-fullcalendar's People

Contributors

alwayshopeless avatar ashleyhood avatar atmonshi avatar autocreation avatar billmn avatar boriswild avatar cawecoy avatar chengkangzai avatar chickgit avatar dependabot[bot] avatar diegoldev avatar fauzie811 avatar github-actions[bot] avatar glennjacobs avatar guuhgalvao avatar invaders-xx avatar khairulazmi21 avatar kidran avatar lam0819 avatar laravel-shift avatar maisur avatar mansoorkhan96 avatar markcameron avatar miguelurtado avatar saade avatar sitenzo avatar sjoerd24 avatar steveadamsfixedit avatar tiagof avatar wychoong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

filament-fullcalendar's Issues

No dispatch events when use filament-fullcalendar--goto

In the onDateSelect function when I detect the type of view I want to make it go to that specific day. But when I launch the event it doesn't go to that day. I don't know if it's a mistake or if I'm doing something wrong.

This is my code:

public function onDateSelect(string $start, ?string $end, bool $allDay, ?array $view, ?array $resource): void
    {
        if($view['type'] === 'dayGridMonth') {
            $this->dispatch('filament-fullcalendar--goto', date: $start);
        } else {
            if($end) {
                [$start, $end] = $this->calculateTimezoneOffset($start, $end, $allDay);

                $this->mountAction('create', [
                    'type' => 'select',
                    'start' => $start,
                    'end' => $end,
                    'allDay' => $allDay,
                    'resource' => $resource,
                ]);
            }
        }
    }

My default view is resourceTimeGridDay and I have a button in the toolbar to show the month on the calendar. I want to detect if it is a month view that goes to that day without launching the create reservation modal.

This is my config:

public function config(): array
    {
        return [
//            'firstDay' => 1,
//            'initialView' => 'timeGridWeek',
            'timeZone' => Filament::getTenant()->timezone,
            'initialView' => 'resourceTimeGridDay',
            'allDaySlot' => false,
            'nowIndicator' => true,
            'headerToolbar' => [
                'left' => 'prev,next',
                'center' => 'title',
                'right' => 'today,dayGridMonth',
            ],
            'titleFormat' => [
                'weekday' => 'long',
                'month' => 'long',
                'day' => 'numeric',
                'year' => 'numeric'
            ],
            //'height' => 700,
            'stickyHeaderDates' => true,
            'dayMaxEvents' => 1,
            'selectMirror' => true,
            'selectOverlap' => false,
            'navLinks' => true,
            'navLinkDayClick' => 'resourceTimeGridDay',
//            'eventMinHeight' => 35,
            'slotLabelFormat' => [
                'hour' => '2-digit',
                'minute' => '2-digit'
            ],
            'slotMinTime' => '09:00:00',
            'slotMaxTime' => '21:00:00',
//            'views' => [
//                'timeGridWeek' => [
//                    'slotMinTime' => '09:00:00'
//                ]
//            ],
            'resourceOrder' => 'store,title',
            'resources' => $this->getResources(),
        ];
    }

With this configuration, having navLinks = true and navLinkDayClick = 'resourceTimeGridDay' when clicking on the day, the day view appears correctly, but I want to be able to click on the entire square of the day, not just the number.

Bug with BelongsToMany repeator on edit

Hello,
I tried to use Repeator with BelongsToMany relationship. The classes are "Event (object in calendar)" -> "Reservation" <- "User (student)".
If I use the same code in a classical FilamentPHP Edit page, my "Repeator" function looks fine. When I click on "Save" I've this issue :

Call to a member function reservations() on null

Docs :
https://filamentphp.com/docs/3.x/forms/fields/repeater

My getFormSchema() function :

[
            View::make('forms.components.title-event'),
            DateTimePicker::make('start')
                ->label('Dรฉbut')
                ->default(now())
                ->seconds(false)
                ->required(),
            DateTimePicker::make('end')
                ->label('Fin')
                ->default(now())
                ->seconds(false)
                ->required(),
            Repeater::make('reservations')
                ->relationship()
                ->schema([
                    Select::make('student_id')
                        ->label('Participant')
                        ->required()
                        ->relationship('student', 'name')
                        ->options(User::all()->sortBy('name')->pluck('name', 'id'))
                        ->searchable()
                        ->default(null),
                    Toggle::make('has_participated')
                        ->label('A participรฉ'),
                    Toggle::make('is_paid')
                        ->label('Payรฉ'),
                ])
                ->columns(1)
        ]

Full classes : https://github.com/sheepbild/filament-viewcolumn-bug/tree/main/belongsToMany-repeater

Error if the event ID is a UUID

Using a UUID, instead of an auto-incremental ID, results in the following error when clicking on an event:

Cannot assign string to property Saade\FilamentFullCalendar\Widgets\FullCalendarWidget::$event_id of type ?int

This because in CanManageEvents trait, the $event_id property is typed as an integer.
I think it can be typed as a string without causing any BC.

Invalid license key

Hi
This message appear at the botom of the calendar

"Your license key is invalid. [More Info]"
There is a way to downgrade the package?

Problem with `cachedEventIds` in the `fetchEvents` function

I am getting events disappearing when I use the fetchEvents() method to load calendar events.

If I comment out the line the caches the event ids in the fullcalendar.blade.php file, it works as expected.

const fetchEvents = function ({ start, end }, successCallback, failureCallback) {
    @if( $this::canFetchEvents() )
        return $wire.fetchEvents({ start, end }, cachedEventIds)
            .then(events => {
                // Cache fetched events
                //cachedEventIds.push(...events.map(event => event.id)); <--- comment out this line fixes the issue

                return successCallback(events);
            })
            .catch( failureCallback );
    @else
        return successCallback([]);
    @endif
}

I think this is due to the way Fullcalendar calls Event Sources that are a function.

From the Fullcalendar docs:

events (as a function)
...
FullCalendar will call this function whenever it needs new event data. This is triggered when the user clicks prev/next or switches views.

Is this line needed? I am not getting any duplication of events if it is commented out.

refreshEvents not working

Hi,
I'm using the last version. The $this->refreshEvents(); method doesn't do anything. as example :

    public function editEvent(array $data): void
    {
       $this->event->start_date = $data['start'];
       $this->event->end_date = $data['end'];
       $this->event->requested_resources = $data['extendedProps']['requested_resources'];
       $participants = Human::whereIn('name',$data['extendedProps']['participants'])->get();
       $this->event->participants()->syncWithoutDetaching($participants);
       $this->event->save();
       $this->refreshEvents();
    }

after the function, the page isn't refreshed.
thx

ResourceTimeline View - Alpine Expression Error: t is undefined

Hi ๐Ÿ‘‹

I'm trying to figure out how to set up the resourceTimeline view added by @steveadamsfixedit and encountered some issues:

fullcalendar_t_error

I think there is something missing while registering the calendarComponent plugin in Alpine. I was thinking that maybe the initialDate should be added to filament-fullcalendar config file additionally, but it did not fix it.

Do you have some ideas where to start? Thank you in advance!

My config file:
<?php

// ...

return [
    'timeZone' => config('app.timezone'),
    'locale' => config('app.locale'),
    'resources' => [],
    'plugins' => ['dayGridPlugin, timeGridPlugin, listPlugin, resourceTimelinePlugin, interactionPlugin, momentPlugin, momentTimezonePlugin'],
    'initialView' => 'resourceTimelineMonth',
    'initialDate' => Carbon::now()->format('Y-m-d'),
    'headerToolbar' => [
        'left' => 'prev,next today',
        'center' => 'title',
        'right' => 'dayGridMonth,dayGridWeek,dayGridDay',
    ],
    'views' => [
        'timelineMonth' => [
            'type' => 'resourceTimeline',
            'duration' => [ 'month' => 1 ],
            'buttonText' =>'Resources',
        ],
    ],
    'navLinks' => true,
    'editable' => true,
    'selectable' => true,
    'dayMaxEvents' => true,
];

V3 compatibility

Discussed in #86

Originally posted by tonypartridge May 25, 2023
Any plans for Filament V3 yet?

Using this widget in a resource's page

I have different plannings and I would like to add this widget in a resource. but there is a conflict in using $this->record as this property is used in Filament widget's resource to refer to the record edited or viewed.

Model labels not working

image
Using the label fields $modelLabel and $pluralModelLabel is not working, the title of the modal is being made of the class name, after doing some research it looks like there is a conflict with the InteractsWithRecords trait

Inconsistence between the code and the README.md

in here you mentioned that to open url in new tab by providing 'shouldOpenUrlInNewTab' => true

but in this code

if (event.url) {
return window.open(event.url, event.extendedProps.shouldOpenInNewTab ? '_blank' : '_self')
}

the 'shouldOpenUrlInNewTab' is inside extendedProps.

right now im using 'shouldOpenUrlInNewTab' inside extendedProps so that event can opened in new tab.

Event form with repeater

My event form as a Repeater with relation. It does not work, I have an error related to relation Call to a member function relation_name on null

Problem with DatePicker & TimePicker on creation popup

Hello
I'm not able to use "default()" and "minDate()" functions for DatePicker/TimePicker on getCreateEventFormSchema() while it works on plain FilamentPHP form (Eg. on Resource::form() function). I tried with several formats but it is not working :
protected static function getCreateEventFormSchema(): array { return [ DatePicker::make('journee') ->required() ->label('Journรฉe') ->default(now()) ->minDate(now()->subDay(1)), TimePicker::make('start') ->label('Dรฉbut') ->default(now()) ->seconds(false) ->required(), TimePicker::make('end') ->label('Fin') ->default(now()) ->seconds(false) ->required(), Select::make('user') ->label('Elรจve') ->options(User::all()->sortBy('name')->pluck('name', 'id')) ->searchable() ->default(null), Toggle::make('is_paid') ->label('Est payรฉ') ]; }

image

Version of the package : ^3.0.0-beta

Using event form with relations

I am not able to make it working with an event form using relations : a select or repeater.
Simple form :

protected static function getCreateEventFormSchema(): array
    {
        return [
            Forms\Components\Select::make('planning_id')
                ->label(__('Planning'))
                ->validationAttribute(__('Planning'))
                ->searchable()
                ->relationship('planning', 'name')
                ->preload()
                ->required(),
            Forms\Components\DatePicker::make('start_at')
                ->required(),
            Forms\Components\DatePicker::make('end_at')
                ->default(null),
        ];
    }

I got : Call to a member function planning() on null
Event if the relation exists

eventDidMount doesn't work

Hi. I am developing the event tooltip with eventDidMount and Tooltip.js like in the official FullCalendar Demo

I've changed a little bit their Codepen moving the tooltip function to the function eventTooltip(info) and in the FullCalendar configuration I've changed the eventDidMount render hook to eventDidMount: eventTooltip. And it works fine: https://codepen.io/cawecoy/pen/jOJgjay

So, I want to implement it through this Filament plugin. That's what I did:

public function panel(Panel $panel): Panel
{
    return $panel->plugins([
        FilamentFullCalendarPlugin::make()->config(['eventDidMount' => 'eventTooltip']),
    ]);
}

I have the function eventTooltip(info) in a JS file that is loaded perfectly.

But it's not working.

The events are not even displayed on the calendar (they were being displayed before I added ['eventDidMount' => 'eventTooltip'] to the plugin ->config()):

image

I can see that the plugin config is loaded in the HTML:

<div class="filament-fullcalendar fc fc-media-screen fc-direction-ltr fc-theme-standard" wire:ignore="" ax-load="" ax-load-src="http://localhost/js/saade/filament-fullcalendar/components/filament-fullcalendar-alpine.js?v=3.1.3.0" ax-load-css="http://localhost/css/saade/filament-fullcalendar/filament-fullcalendar-styles.css?v=3.1.3.0" x-data="fullcalendar({
                locale: 'pl',
                plugins: JSON.parse('[\u0022dayGrid\u0022,\u0022timeGrid\u0022,\u0022interaction\u0022,\u0022list\u0022,\u0022moment\u0022,\u0022momentTimezone\u0022]'),
                schedulerLicenseKey: null,
                timeZone: 'UTC',
                config: JSON.parse('{\u0022eventDidMount\u0022:\u0022eventTooltip\u0022}'),
                editable: false,
                selectable: false,
})">
    ...
</div>

I see my config here: JSON.parse('{\u0022eventDidMount\u0022:\u0022eventTooltip\u0022}')

So how can I use eventDidMount through this plugin?

I guess that config is redered as string like "eventDidMount": "eventTooltip", but for this config to work it should be rendered like "eventDidMount": eventTooltip.

Or maybe this plugin can have a dedicated method to Event Render Hooks (only for functions then rendered in Javascript always without quotes), as we have for locale, timezone, and so on. Then we just do:

public function panel(Panel $panel): Panel
{
    return $panel->plugins([
        FilamentFullCalendarPlugin::make()->renderHooks(['eventDidMount' => 'eventTooltip']),
    ]);
}

I might try to send a PR. Let me know.

Exception Plugin [filament-fullcalendar] is not registered for panel [app].

Laravel v10.28.0
Filament v3.0.73
filament-fullcalendar v3.0.3

I've upgraded Filament and then followed all of the steps in the README on here, and persistently get this error message when I load my dashboard.

I've got the plugin registered on the bottom of my AdminPanelProvider in the panel() method like this:

->plugin(
                FilamentFullCalendarPlugin::make()
                    ->selectable()
                    ->editable()
                    ->timezone('local')
                    ->locale('en')
                    ->plugins([])
                    ->config([])
            );

I've got the CalendarWidget registered properly in my Dashboard:

public function getWidgets(): array
    {
        return 
            RequestsByCountyChart::class,
            RequestsThroughTimeChart::class,
            NetRequestIncomeChart::class,
            CalendarWidget::class,
        ];
    }

I've used previously versions of the plugin and it's worked fine. Am I missing something or is there some other issue implicated here?

Failed to find '@fullcalendar/common/main.css'

Hi,

By upgrading from v1.8.0 to v1.9.0 my project (npm) broke.

I get the following error message, when executing the npm run dev command

ERROR in ./resources/css/app.css
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/postcss-loader/dist/cjs.js):
Error: Failed to find '@fullcalendar/common/main.css'

I'm making use of the customization feature described in your documentation's Styling-chapter, having the following line in my ./resources/css/app.css:

@import '../../vendor/saade/filament-fullcalendar/resources/css/filament-fullcalendar.css';

My webpack.mix.js looks like this:

mix.js('resources/js/app.js', 'public/js')
    .postCss('resources/css/app.css', 'public/css', [
        require('tailwindcss'),
    ])

I think the change you made to resources/css/filament-fullcalendar.css in your last commit, broke the building process.

Am I doing something wrong? How to fix this?

Option 'config' in 'AdminPanelProvider' overrides the 'config' method of the widget.

It is not possible to change the calendar settings in the widget, nor leave the config option empty in AdminPanelProvider to use the one from the widget.

Classes below:

teste
teste (2)

Of course, I have other functions related to my project, but here's what's important for the issue. Note that the config arrays are different, however, the AdminPanelProvider is not altered, and I need to change it in real-time in the view according to specific attributes of each client.

The previous month's event does not carry over to the next month.

I have 2 events:

  1. From July 27th to August 8th.
  2. From August 9th to August 17th.

For example, when I'm in July, the first event is visible from July 27th to August 9th, but when I move to August, the first event is not visible until August 9th. Only the second event is visible from August 9th to August 17th.

July
Screenshot 2024-06-10 at 22 00 57
August
Screenshot 2024-06-10 at 22 01 52

Strange bug, while returning array of EventData

Hello @saade

Firstly, I would like to thank you for this package, as it is a very handy helper tool

I tried to use it, according to the documentation and fell into the following issues.

While I am returning, an array of EventData objects, like below, calendars appears empty
image

However, it can be easily fixed, if I just transform each EventData to array
image

At this point, I am getting results.

But again I faced another issue.

In order these events to have the proper time, I need to translate it first at localString (I have tried of course to enforce timezone to calendar plugin, but no result)
image

I don't mind, a lot, as I got to a workaround, but seemed fair to report these minor issues

Thank you for your time here

Timezone

My event's dates (start and end) are stored in database in UTC. But I want to display those dates using user's timezone.

So I have a resource's view showing events table : as you can see the dates in table are displayed using the right timezone.
In the FullCalendar, we see that event are displayed using UTC event if i set :

public function getConfig(): array
    {
        return array_merge(parent::getConfig(), [
            'timeZone' => auth()->user()->timezone,
            'locale' => app()->getLocale(),
        ]);
    }

image

Typed property Saade\FilamentFullCalendar\Widgets\FullCalendarWidget::$record (on drag and drop)

Hi, thanks for making this plugin!

I've followed the readme and I'm trying to update the dates on drag and drop.

I have a Calendar page which has the CalendarWidget.php

I have at the top public Model | string | null $model = JobTask::class;, although have tried with and without it. I am hoping to target many models, let me know if this is an issue.

Using use Saade\FilamentFullCalendar\Actions; I get the error Typed property Saade\FilamentFullCalendar\Widgets\FullCalendarWidget::$record, with no model updates.

Using use Filament\Actions; it will work, although have App\Filament\Dashboard\Widgets\CalendarWidget::App\Filament\Dashboard\Widgets\{closure}(): Argument #1 ($record) must be of type Illuminate\Database\Eloquent\Model, null given, called in /var/www/laravel/vendor/filament/support/src/Concerns/EvaluatesClosures.php on line 35 after the event has finished.

image

I am using this code, note for the arguments I had appended |null for the use Filament\Actions; to work. Without them there is an error thrown as they do not exist.

I figured it's best to use use Saade\FilamentFullCalendar\Actions; but I must be overlooking something or missed a step with the setup. This is the CalendarWidget.php file. Note I had tried to work around this by using the switch and find model statements, but no luck.

<?php

namespace App\Filament\Dashboard\Widgets;

use App\Filament\Dashboard\Resources\JobResource;
use App\Filament\Dashboard\Resources\JobTaskResource;
use App\Models\Job;
use Carbon\Carbon;
use Filament\Actions;
use Filament\Forms\Form;
use Illuminate\Database\Eloquent\Model;
use Saade\FilamentFullCalendar\Widgets\FullCalendarWidget;
use App\Models\JobTask;

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 Model | string | null $model = JobTask::class;

    public function fetchEvents(array $info): array
    {
        // You can use $info 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

        $jobTasks = JobTask::query()
            ->where('start_date', '>=', $info['start'])
            ->where('end_date', '<=', $info['end'])
            ->get()
            ->map(
                fn (JobTask $event) => [
                    'id' => $event->id,
                    'calendar_type' => 'job-task',
                    'title' => $event->name,
                    'start' => $event->start_date,
//                    'end' => $event->end_date,
                    'backgroundColor' => 'blue',
                    'eventBorderColor' => 'blue',
                    'displayEventTime' => false,
                    'url' => JobTaskResource::getUrl(name: 'view', parameters: ['record' => $event]),
                ]
            )
            ->all();

        $jobs = Job::query()
            ->where('start_date', '>=', $info['start'])
            ->where('deadline_date', '<=', $info['end'])
            ->get()
            ->map(
                fn (Job $event) => [
                    'id' => $event->id,
                    'calendar_type' => 'job',
                    'title' => $event->name,
                    'start' => $event->start_date,
//                    'end' => $event->deadline_date,
                    'backgroundColor' => 'darkgrey',
                    'eventBorderColor' => 'darkgrey',
                    'displayEventTime' => false,
                    'url' => JobResource::getUrl(name: 'view', parameters: ['record' => $event]),
                ]
            )
            ->all();

        return array_merge($jobTasks, $jobs);
    }

    protected function modalActions(): array
    {
        return [
            Actions\EditAction::make()
                ->mountUsing(
                    function (Model|null $record, Form|null $form, array $arguments) {
                        dd($record,$form,$arguments);
                        switch ($arguments['event']['extendedProps']['calendar_type']) {
                            case 'job':
                                $record = Job::find($arguments['event']['id']);
                                $record ->update([
                                    'start_date' => Carbon::parse($arguments['event']['start']),
                                ]);
                                break;

                            case 'job-task':
                                $record = JobTask::find($arguments['event']['id']);
                                $record->update([
                                    'start_date' => Carbon::parse($arguments['event']['start']),
                                ]);
                                break;
                        }
                    }
                ),
        ];
    }

}

Typed property Saade\FilamentFullCalendar\Widgets\FullCalendarWidget::$record must not be accessed before initialization

I have a filament action within headerActions method for the calendar.

It is using a modal form which I want to run to filter the events, the error appears when trying to submit that form. Any ideas on how to fix this would be much appreciated.

return [ Action::make('filter') ->label(__('ev-bookings.actions.filter-locations')) ->icon('heroicon-s-funnel') ->modalWidth('sm') ->modalIcon('heroicon-o-funnel') ->modalCancelAction(false) ->modalSubmitActionLabel(__('ev-bookings.actions.filter-locations')) ->modalFooterActionsAlignment('center') ->form([ CheckboxListColor::make('color') ->label(__('ev-bookings.fields.locations')) ->hiddenLabel(true) ->options($locations) ->required() ->columns(2) ]) ->action(function (array $data): void { // will do something }) ];

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.