Skip to content

Commit

Permalink
Merge pull request #11 from saade/feature/event-modals
Browse files Browse the repository at this point in the history
feature: Modals for creating / editing events
  • Loading branch information
saade authored Jun 27, 2022
2 parents 9b34d83 + 2de02ab commit f212d26
Show file tree
Hide file tree
Showing 13 changed files with 405 additions and 73 deletions.
162 changes: 119 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@

- Accepts all configurations from [FullCalendar](https://fullcalendar.io/docs#toc)
- Event click and drop events

### Upcoming
- Modal view when clicking on an event
- Tailwindcss theme 💙
- Modals for creating and editing events <sup>New in v1.0</sup>

<br>

Expand All @@ -41,36 +38,6 @@ You can publish the config file with:
php artisan vendor:publish --tag="filament-fullcalendar-config"
```

This is the contents of the published config file:

```php
<?php

/**
* Consider this file the root configuration object for FullCalendar.
* Any configuration added here, will be added to the calendar.
* @see https://fullcalendar.io/docs#toc
*/

return [
'timeZone' => config('app.timezone'),

'locale' => config('app.locale'),

'headerToolbar' => [
'left' => 'prev,next today',
'center' => 'title',
'right' => 'dayGridMonth,dayGridWeek,dayGridDay'
],

'navLinks' => true,

'editable' => true,

'dayMaxEvents' => true
];
```

<br>

# Usage
Expand Down Expand Up @@ -131,7 +98,7 @@ class CalendarWidget extends FullCalendarWidget
This is the contents of the default config file.

You can use any property that FullCalendar uses on its root object.
Please refer to: [FullCalendar Docs](https://fullcalendar.io/docs#toc) to see the available options. It supports all of them, really.
Please refer to: [FullCalendar Docs](https://fullcalendar.io/docs#toc) to see the available options. It supports most of them.

```php
<?php
Expand Down Expand Up @@ -169,27 +136,136 @@ The only events supported right now are: [EventClick](https://fullcalendar.io/do

They're commented out by default so livewire does not spam requests without they being used. You are free to paste them in your `CalendarWidget` class. See: [FiresEvents](https://github.com/saade/filament-fullcalendar/blob/main/src/Widgets/Concerns/FiresEvents.php)

> Note: if you are overriding the event callbacks, be sure to call its parent function to garantee that all functions works properly.
```php
/**
* Triggered when the user clicks an event.
*
* Commented out so we can save some requests :) Feel free to extend it.
* @see https://fullcalendar.io/docs/eventClick
*/
public function onEventClick($event): void
{
//
parent::onEventClick($event);

// your code
}

/**
* Triggered when dragging stops and the event has moved to a different day/time.
*
* Commented out so we can save some requests :) Feel free to extend it.
* @see https://fullcalendar.io/docs/eventDrop
*/
public function onEventDrop($oldEvent, $newEvent, $relatedEvents): void
{
//
parent::onEventDrop($oldEvent, $newEvent, $relatedEvents);

// your code
}
```

<br>

# Creating and Editing events with modals.

Since [v1.0.0](https://github.com/saade/filament-fullcalendar/releases/tag/v1.0.0) you can create and edit events using a modal.

The process of saving and editing the event is up to you, since this plugin does not rely on a Model to save the calendar events.


## Creating Events:

Override the `createEvent` function in your widget class, and you are ready to go!

```php
public function createEvent(array $data): void
{
// Create the event with the provided $data.
}
```

If the default form does not fullfills your needs, you can override the `getCreateEventFormSchema` and use it like a normal Filament form.

```php
protected static function getCreateEventFormSchema(): array
{
return [
Forms\Components\TextInput::make('title')
->required(),
Forms\Components\DatePicker::make('start')
->required(),
Forms\Components\DatePicker::make('end')
->default(null),
];
}
```

<br>

## Editing Events:

Override the `editEvent` function in your widget class, and you are ready to go!

```php
public function editEvent(array $data): void
{
// Edit the event with the provided $data.
}
```

If the default form does not fullfills your needs, you can override the `getEditEventFormSchema` and use it like a normal Filament form.

```php
protected static function getEditEventFormSchema(): array
{
return [
Forms\Components\TextInput::make('title')
->required(),
Forms\Components\DatePicker::make('start')
->required(),
Forms\Components\DatePicker::make('end')
->default(null),
];
}
```

<br>

## Authorizing actions

If you want to authorize the `edit` or `create` action, you can override the default authorization methods that comes with this package.

```php
public static function canCreate(): bool
{
// Returning 'false' will remove the 'Create' button on the calendar.
return true;
}

public static function canEdit(?array $event = null): bool
{
// Returning 'false' will disable the edit modal when clicking on a event.
return true;
}
```

If you want to disable all actions or keep the calendar as it was before [v1.0.0](https://github.com/saade/filament-fullcalendar/releases/tag/v1.0.0), you can return false for all the methods above, or use the convenient concern `CantManageEvents`. It will disable all calendar modals.

```php
class CalendarWidget extends FullCalendarWidget
{
use CantManageEvents;

// ...
}
```

<br>

# Refreshing calendar events

If you want to refresh the calendar events, you can call `$this->refreshEvents()` inside your widget class. This will call `getViewData()` and re-render the events on the calendar.

```php
public function yourMethod(): void
{
$this->refreshEvents();
}
```

Expand Down
17 changes: 17 additions & 0 deletions resources/views/components/create-event-modal.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<x-filament::modal id="fullcalendar--create-event-modal">
<x-slot name="heading">
{{ __('filament::resources/pages/create-record.title', ['label' => 'Event']) }}
</x-slot>

<x-filament::form wire:submit.prevent="onCreateEventSubmit">
{{ $this->createEventForm }}

<x-filament::button type="submit" form="onCreateEventSubmit">
{{ __('filament::resources/pages/create-record.form.actions.create.label') }}
</x-filament::button>

<x-filament::button color="secondary" x-on:click="isOpen = false">
{{ __('filament::resources/pages/create-record.form.actions.cancel.label') }}
</x-filament::button>
</x-filament::form>
</x-filament::modal>
17 changes: 17 additions & 0 deletions resources/views/components/edit-event-modal.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<x-filament::modal id="fullcalendar--edit-event-modal">
<x-slot name="heading">
{{ __('filament::resources/pages/edit-record.title', ['label' => 'Event']) }}
</x-slot>

<x-filament::form wire:submit.prevent="onEditEventSubmit">
{{ $this->editEventForm }}

<x-filament::button type="submit" form="onEditEventSubmit">
{{ __('filament::resources/pages/edit-record.form.actions.save.label') }}
</x-filament::button>

<x-filament::button color="secondary" x-on:click="isOpen = false">
{{ __('filament::resources/pages/edit-record.form.actions.cancel.label') }}
</x-filament::button>
</x-filament::form>
</x-filament::modal>
Empty file.
79 changes: 57 additions & 22 deletions resources/views/fullcalendar.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,66 @@

<x-filament::widget>
<x-filament::card>
<div wire:ignore x-data="" x-init='document.addEventListener("DOMContentLoaded", () => {
const calendar = new FullCalendar.Calendar($el, Object.assign(
@json($this->getConfig()),
{
locale: "{{ $locale }}",
events: @json($events),
eventClick: ({ event, jsEvent }) => {
if(event.url) {
@if( $this::canCreate() )
<div class="flex items-center justify-end">
<x-filament::button wire:click="onCreateEventClick">
{{ __('filament::resources/pages/create-record.form.actions.create.label') }}
</x-filament::button>
</div>

<x-filament::hr />
@endif

<div
wire:ignore
x-data=""
x-init='
document.addEventListener("DOMContentLoaded", function() {
const config = @json($this->getConfig());
const events = @json($events);
const locale = "{{ $locale }}";
const eventClick = function ({ event, jsEvent }) {
if( event.url ) {
jsEvent.preventDefault();
window.open(event.url, event.extendedProps.shouldOpenInNewTab ? "_blank" : "_self");
return false;
}
@js($this->isListeningClickEvent()) && window.livewire.find("{{ $this->id }}").onEventClick(event)
},
eventDrop: ({ event, oldEvent, relatedEvents }) => @js($this->isListeningDropEvent()) && window.livewire.find("{{ $this->id }}").onEventDrop(event, oldEvent, relatedEvents),
}
));
calendar.render();
window.addEventListener("fullcalendar::refresh", event => {
calendar.removeAllEvents();
event.detail.data.map(event => calendar.addEvent(event));
});
})'>
</div>
@if ($this::isListeningClickEvent())
$wire.onEventClick(event)
@endif
}
const eventDrop = function ({ event, oldEvent, relatedEvents }) {
@if($this::isListeningDropEvent())
$wire.onEventDrop(event, oldEvent, relatedEvents)
@endif
}
const calendar = new FullCalendar.Calendar($el, {
...config,
locale,
events,
eventClick,
eventDrop
});
calendar.render();
window.addEventListener("filament-fullcalendar:refresh", (event) => {
calendar.removeAllEvents();
event.detail.data.map(event => calendar.addEvent(event));
});
})
'></div>
</x-filament::card>

@if($this::canCreate())
<x:filament-fullcalendar::create-event-modal />
@endif

@if($this::canEdit())
<x:filament-fullcalendar::edit-event-modal />
@endif
</x-filament::widget>
21 changes: 21 additions & 0 deletions src/Widgets/Concerns/AuthorizesActions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Saade\FilamentFullCalendar\Widgets\Concerns;

trait AuthorizesActions
{
public static function canCreate(): bool
{
return true;
}

public static function canEdit(?array $event = null): bool
{
return true;
}

public static function canDelete(?array $event = null): bool
{
return true;
}
}
Loading

0 comments on commit f212d26

Please sign in to comment.