edissavov / filament-booking-calendar
A flexible booking calendar widget for Filament v3 built on FullCalendar
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/edissavov/filament-booking-calendar
Requires
- php: ^8.1|^8.2
- filament/filament: ^3.0
- saade/filament-fullcalendar: ^3.0
- spatie/laravel-package-tools: ^1.14
Requires (Dev)
- orchestra/testbench: ^8.0
- phpunit/phpunit: ^10.0
This package is auto-updated.
Last update: 2025-12-19 17:02:41 UTC
README
A flexible, feature-rich booking calendar widget for Filament v3 built on FullCalendar. Perfect for appointment scheduling, salon bookings, room reservations, and any booking-based system.
Features
- 📅 Full CRUD operations on calendar events
- 🎨 Status-based color coding (customizable)
- 📱 Mobile-responsive design with auto-view switching
- ⚙️ Highly configurable through config file
- 🔧 Extensible through widget inheritance
- 🌍 Multi-language support
- ⏰ Configurable business hours and timezones
- 📊 Multiple calendar views (Month, Week, Day, List)
- 💡 Event tooltips
- 🎯 Metadata support for domain-specific fields
Installation
Install the package via Composer:
composer require edissavov/filament-booking-calendar
Quick Start
1. Publish Configuration (Optional)
php artisan vendor:publish --tag=filament-booking-calendar-config
2. Run Migrations
If you don't have a bookings table:
php artisan vendor:publish --tag=filament-booking-calendar-migrations php artisan migrate
Note: If you already have a bookings table, skip this step and configure your own model in the config file.
3. Register the Widget
Option A: As a Page Widget
Create a Filament page:
// app/Filament/Pages/Calendar.php <?php namespace App\Filament\Pages; use Edissavov\FilamentBookingCalendar\Widgets\BookingCalendarWidget; use Filament\Pages\Page; class Calendar extends Page { protected static ?string $navigationIcon = 'heroicon-o-calendar-days'; protected static string $view = 'filament.pages.calendar'; protected static ?string $title = 'Calendar'; protected function getHeaderWidgets(): array { return [ BookingCalendarWidget::class, ]; } }
Create the view:
{{-- resources/views/filament/pages/calendar.blade.php --}} <x-filament-panels::page />
Option B: As a Dashboard Widget
Register in your Panel Provider:
// app/Providers/Filament/AdminPanelProvider.php ->widgets([ \Edissavov\FilamentBookingCalendar\Widgets\BookingCalendarWidget::class, ])
Configuration
Using Existing Booking Model
If you already have a Booking model, point to it in the config:
// config/filament-booking-calendar.php 'models' => [ 'booking' => \App\Models\Booking::class, ],
Minimum required fields:
name(string)phone(string)email(string, nullable)date(datetime)status(string)price(decimal, nullable)notes(text, nullable)
Customize Status Colors
'statuses' => [ 'pending' => [ 'label' => 'Pending Confirmation', 'color' => ['bg' => '#FFA500', 'border' => '#FF8C00'], ], 'confirmed' => [ 'label' => 'Confirmed', 'color' => ['bg' => '#3B82F6', 'border' => '#2563EB'], ], // Add more statuses... ],
Localization
'calendar' => [ 'locale' => 'bg', // Bulgarian 'timezone' => 'Europe/Sofia', 'button_text' => [ 'today' => 'Днес', 'month' => 'Месец', 'week' => 'Седмица', 'day' => 'Ден', 'list_week' => 'Списък седмица', 'list_day' => 'Списък ден', ], ],
Business Hours
'calendar' => [ 'business_hours' => [ 'start' => '09:00:00', 'end' => '18:00:00', ], ],
Phone Number Formatting
'form' => [ 'enable_phone_formatting' => true, 'phone_country_code' => '+359', // Bulgaria ],
This will automatically convert phone numbers starting with "0" to "+359xxx".
Advanced Usage
Extending the Widget
For domain-specific customizations (like pet grooming), extend the widget:
// app/Filament/Widgets/PetGroomingCalendar.php <?php namespace App\Filament\Widgets; use Edissavov\FilamentBookingCalendar\Widgets\BookingCalendarWidget; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Select; use Filament\Forms\Components\Fieldset; class PetGroomingCalendar extends BookingCalendarWidget { protected function getFormSchema(): array { $baseSchema = parent::getFormSchema(); // Add pet-specific fields $petFields = Fieldset::make('Pet Information') ->schema([ TextInput::make('metadata.pet_name') ->label('Pet Name') ->required(), TextInput::make('metadata.breed') ->label('Breed'), Select::make('metadata.weight') ->label('Weight') ->options([ 'Small (< 5kg)' => 'Small (< 5kg)', 'Medium (5-15kg)' => 'Medium (5-15kg)', 'Large (15-30kg)' => 'Large (15-30kg)', ]), ]) ->columns(3); // Insert after customer information array_splice($baseSchema, 1, 0, [$petFields]); return $baseSchema; } protected function getEventTitle($booking): string { $petName = $booking->metadata['pet_name'] ?? null; return $booking->name . ($petName ? " ($petName)" : ''); } }
Then configure the title suffix:
'fields' => [ 'title' => 'name', 'title_suffix' => 'metadata.pet_name', // Shows "Owner (Pet Name)" ],
Using Service Providers
If your bookings are assigned to specific staff members:
'models' => [ 'booking' => \App\Models\Booking::class, 'service_provider' => \App\Models\User::class, // Your staff model ],
The widget will automatically add a "Service Provider" select field.
Custom Event Colors
Override the color logic for advanced scenarios:
protected function getEventColors(string $status): array { // Custom logic, e.g., color by service provider if ($this->record->service_provider_id === 1) { return ['bg' => '#FF6B6B', 'border' => '#EE5555']; } return parent::getEventColors($status); }
Migration Guide
From Pet Grooming App
If you're migrating from a pet-specific implementation:
- Migrate pet fields to metadata:
DB::table('bookings')->get()->each(function ($booking) { DB::table('bookings') ->where('id', $booking->id) ->update([ 'metadata' => json_encode([ 'pet_name' => $booking->pet_name, 'breed' => $booking->breed, 'weight' => $booking->weight, ]) ]); });
- Configure for Bulgarian locale:
'calendar' => [ 'locale' => 'bg', 'timezone' => 'Europe/Sofia', ], 'statuses' => [ 'непотвърдена' => ['label' => 'Непотвърдена', 'color' => ['bg' => '#EAB308', 'border' => '#CA8A04']], 'потвърдена' => ['label' => 'Потвърдена', 'color' => ['bg' => '#3B82F6', 'border' => '#2563EB']], 'успешна' => ['label' => 'Успешна', 'color' => ['bg' => '#10B981', 'border' => '#059669']], 'отказана' => ['label' => 'Отказана', 'color' => ['bg' => '#EF4444', 'border' => '#DC2626']], ],
API Reference
BookingCalendarWidget Methods
Overridable Methods:
getEventTitle($booking): string- Customize event title displaygetEventColors(string $status): array- Customize event colorsgetEventExtendedProps($booking): array- Add custom tooltip dataformatPhoneNumber(?string $phone): ?string- Custom phone formattinggetFormSchema(): array- Customize the booking form
Model Scopes:
Booking::byStatus('confirmed')->get(); Booking::betweenDates('2024-01-01', '2024-01-31')->get(); Booking::upcoming()->get(); Booking::past()->get();
Examples
Salon Booking System
'models' => [ 'booking' => \App\Models\Appointment::class, 'service_provider' => \App\Models\Stylist::class, ], 'statuses' => [ 'scheduled' => ['label' => 'Scheduled', 'color' => ['bg' => '#3B82F6', 'border' => '#2563EB']], 'completed' => ['label' => 'Completed', 'color' => ['bg' => '#10B981', 'border' => '#059669']], 'no_show' => ['label' => 'No Show', 'color' => ['bg' => '#EF4444', 'border' => '#DC2626']], ],
Room Reservations
'models' => [ 'booking' => \App\Models\Reservation::class, 'resource' => \App\Models\Room::class, ], 'fields' => [ 'title' => 'name', 'title_suffix' => 'resource.name', // Shows "Guest (Room 101)" ],
Troubleshooting
Migration Conflicts
If you already have a bookings table, the migration will automatically skip. Configure your own model:
'models' => [ 'booking' => \App\Models\Booking::class, ],
Relationship Errors
If you get "Model not configured" errors, make sure to set the relationship models in config:
'models' => [ 'service_provider' => \App\Models\User::class, // Required if using this relationship ],
Events Not Showing
- Check that your booking model has the required fields
- Verify the model is set correctly in config
- Check that bookings exist in the database
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
The MIT License (MIT). Please see License File for more information.
Credits
- Built on saade/filament-fullcalendar
- Developed for Filament v3