Calendar Application
Calendar Application
Event management with FullCalendar integration, drag-and-drop functionality, and comprehensive scheduling features.
Route: /admin/apps/calendar
Overview
The Calendar application provides a complete event management system with multiple view options, drag-and-drop functionality, and comprehensive scheduling capabilities. It integrates with FullCalendar for a professional calendar experience.
Features
Core Calendar Features
- Multiple Views - Month, week, day, and list views
- Event Management - Create, edit, delete, and duplicate events
- Drag & Drop - Move events between dates and times
- Event Categories - Color-coded event types and categories
- Recurring Events - Set up repeating events with various patterns
- Event Details - Rich event information with descriptions and attendees
- Time Zones - Support for multiple time zones
- Event Search - Find events quickly with search functionality
- Event Filtering - Filter events by category, date, or other criteria
- Export/Import - Export calendar data and import from other sources
UI/UX Features
- Responsive Design - Works on all devices
- Dark/Light Mode - Automatic theme switching
- Smooth Animations - Fluid transitions and interactions
- Modern Interface - Clean, professional design
- Accessibility - WCAG compliant with proper ARIA labels
- Touch Support - Optimized for touch devices
Calendar Views
Month View
- Grid Layout - Traditional monthly calendar grid
- Event Display - Events shown as colored blocks
- Navigation - Previous/next month navigation
- Today Highlight - Current date highlighted
- Event Overflow - Show "+X more" for days with many events
Week View
- 7-Day Layout - Full week with time slots
- Time Grid - Hourly time slots for precise scheduling
- Event Positioning - Events positioned by time
- Week Navigation - Navigate between weeks
- Weekend Toggle - Show/hide weekends
Day View
- Single Day - Focus on one day's events
- Detailed Timeline - Hour-by-hour breakdown
- Event Details - Full event information visible
- Time Slots - Precise time management
- Day Navigation - Navigate between days
List View
- Event List - Chronological list of events
- Upcoming Events - Focus on future events
- Event Summary - Quick overview of all events
- Search & Filter - Find specific events quickly
- Bulk Actions - Manage multiple events at once
Event Management
Creating Events
- Quick Create - Click on calendar to create event
- Event Modal - Detailed event creation form
- Event Details - Title, description, location, attendees
- Time Selection - Start and end time pickers
- All-Day Events - Toggle for all-day events
- Recurring Options - Set up repeating events
Event Types
- Meetings - Business meetings and appointments
- Tasks - Personal tasks and to-dos
- Deadlines - Project deadlines and milestones
- Holidays - Company holidays and observances
- Personal - Personal events and reminders
- Custom - User-defined event types
Event Categories
- Color Coding - Visual categorization with colors
- Category Management - Create and manage categories
- Category Filtering - Show/hide specific categories
- Category Icons - Visual icons for categories
- Category Rules - Automatic categorization rules
Integration Examples
Backend Integration
// Calendar Controller
class CalendarController extends Controller
{
public function index()
{
$events = Event::where('user_id', auth()->id())
->orWhere('is_public', true)
->get();
return view('admin.apps.calendar', compact('events'));
}
public function getEvents(Request $request)
{
$start = $request->start;
$end = $request->end;
$events = Event::where('user_id', auth()->id())
->whereBetween('start', [$start, $end])
->get()
->map(function($event) {
return [
'id' => $event->id,
'title' => $event->title,
'start' => $event->start,
'end' => $event->end,
'color' => $event->color,
'allDay' => $event->all_day,
'extendedProps' => [
'description' => $event->description,
'location' => $event->location,
'attendees' => $event->attendees
]
];
});
return response()->json($events);
}
public function store(Request $request)
{
$request->validate([
'title' => 'required|string|max:255',
'start' => 'required|date',
'end' => 'nullable|date|after:start',
'color' => 'nullable|string',
'description' => 'nullable|string',
'location' => 'nullable|string',
'attendees' => 'nullable|array'
]);
$event = Event::create([
'user_id' => auth()->id(),
'title' => $request->title,
'start' => $request->start,
'end' => $request->end,
'color' => $request->color,
'description' => $request->description,
'location' => $request->location,
'attendees' => $request->attendees,
'all_day' => $request->boolean('all_day')
]);
return response()->json($event);
}
public function update(Request $request, Event $event)
{
$this->authorize('update', $event);
$request->validate([
'title' => 'required|string|max:255',
'start' => 'required|date',
'end' => 'nullable|date|after:start'
]);
$event->update($request->all());
return response()->json($event);
}
public function destroy(Event $event)
{
$this->authorize('delete', $event);
$event->delete();
return response()->json(['success' => true]);
}
}
Livewire Integration
// Calendar Livewire Component
class CalendarApp extends Component
{
public $events = [];
public $selectedEvent = null;
public $showEventModal = false;
public $eventTitle = '';
public $eventStart = '';
public $eventEnd = '';
public $eventColor = '#3788d8';
public $eventDescription = '';
public $eventLocation = '';
public function mount()
{
$this->loadEvents();
}
public function loadEvents()
{
$this->events = Event::where('user_id', auth()->id())
->get()
->map(function($event) {
return [
'id' => $event->id,
'title' => $event->title,
'start' => $event->start,
'end' => $event->end,
'color' => $event->color,
'allDay' => $event->all_day
];
})
->toArray();
}
public function selectDate($date)
{
$this->eventStart = $date;
$this->eventEnd = $date;
$this->showEventModal = true;
}
public function selectEvent($eventId)
{
$event = Event::find($eventId);
$this->selectedEvent = $event;
$this->eventTitle = $event->title;
$this->eventStart = $event->start;
$this->eventEnd = $event->end;
$this->eventColor = $event->color;
$this->eventDescription = $event->description;
$this->eventLocation = $event->location;
$this->showEventModal = true;
}
public function saveEvent()
{
$this->validate([
'eventTitle' => 'required|string|max:255',
'eventStart' => 'required|date',
'eventEnd' => 'nullable|date|after:eventStart'
]);
if ($this->selectedEvent) {
$this->selectedEvent->update([
'title' => $this->eventTitle,
'start' => $this->eventStart,
'end' => $this->eventEnd,
'color' => $this->eventColor,
'description' => $this->eventDescription,
'location' => $this->eventLocation
]);
} else {
Event::create([
'user_id' => auth()->id(),
'title' => $this->eventTitle,
'start' => $this->eventStart,
'end' => $this->eventEnd,
'color' => $this->eventColor,
'description' => $this->eventDescription,
'location' => $this->eventLocation
]);
}
$this->loadEvents();
$this->closeEventModal();
}
public function deleteEvent()
{
if ($this->selectedEvent) {
$this->selectedEvent->delete();
$this->loadEvents();
$this->closeEventModal();
}
}
public function closeEventModal()
{
$this->showEventModal = false;
$this->selectedEvent = null;
$this->reset(['eventTitle', 'eventStart', 'eventEnd', 'eventColor', 'eventDescription', 'eventLocation']);
}
public function render()
{
return view('livewire.calendar-app');
}
}
Google Calendar Integration
// Google Calendar Service
class GoogleCalendarService
{
protected $client;
public function __construct()
{
$this->client = new \Google_Client();
$this->client->setAuthConfig(config('services.google.client_secret'));
$this->client->addScope(\Google_Service_Calendar::CALENDAR);
}
public function syncEvents()
{
$service = new \Google_Service_Calendar($this->client);
$calendarId = 'primary';
$events = $service->events->listEvents($calendarId);
foreach ($events->getItems() as $event) {
Event::updateOrCreate([
'google_id' => $event->getId()
], [
'user_id' => auth()->id(),
'title' => $event->getSummary(),
'start' => $event->getStart()->getDateTime(),
'end' => $event->getEnd()->getDateTime(),
'description' => $event->getDescription(),
'location' => $event->getLocation(),
'color' => $this->getEventColor($event)
]);
}
}
public function createEvent($eventData)
{
$service = new \Google_Service_Calendar($this->client);
$calendarId = 'primary';
$event = new \Google_Service_Calendar_Event([
'summary' => $eventData['title'],
'description' => $eventData['description'],
'location' => $eventData['location'],
'start' => [
'dateTime' => $eventData['start'],
'timeZone' => 'America/New_York'
],
'end' => [
'dateTime' => $eventData['end'],
'timeZone' => 'America/New_York'
]
]);
return $service->events->insert($calendarId, $event);
}
}
Customization
Styling
// Custom calendar styles
.calendar-container {
.fc {
--fc-border-color: var(--border-color);
--fc-button-bg-color: var(--primary-color);
--fc-button-border-color: var(--primary-color);
--fc-button-hover-bg-color: var(--primary-hover);
--fc-button-hover-border-color: var(--primary-hover);
--fc-button-active-bg-color: var(--primary-active);
--fc-button-active-border-color: var(--primary-active);
--fc-today-bg-color: var(--bg-today);
--fc-event-bg-color: var(--event-bg);
--fc-event-border-color: var(--event-border);
}
.fc-toolbar {
margin-bottom: 1rem;
.fc-toolbar-title {
font-size: 1.5rem;
font-weight: 600;
color: var(--text-color);
}
}
.fc-event {
border-radius: 4px;
border: none;
padding: 2px 4px;
font-size: 0.875rem;
&:hover {
opacity: 0.8;
}
}
.fc-daygrid-event {
margin: 1px 0;
}
.fc-timegrid-event {
border-radius: 4px;
}
}
JavaScript Functionality
// Calendar functionality
class CalendarApp {
constructor() {
this.calendar = null;
this.initCalendar();
this.initEventHandlers();
}
initCalendar() {
const calendarEl = document.getElementById('calendar');
this.calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
editable: true,
selectable: true,
selectMirror: true,
dayMaxEvents: true,
events: this.loadEvents.bind(this),
select: this.handleDateSelect.bind(this),
eventClick: this.handleEventClick.bind(this),
eventDrop: this.handleEventDrop.bind(this),
eventResize: this.handleEventResize.bind(this)
});
this.calendar.render();
}
loadEvents(info) {
return fetch('/api/calendar/events', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
}
})
.then(response => response.json())
.then(events => {
return events.map(event => ({
id: event.id,
title: event.title,
start: event.start,
end: event.end,
color: event.color,
allDay: event.allDay
}));
});
}
handleDateSelect(selectInfo) {
const title = prompt('Enter event title:');
if (title) {
this.createEvent({
title: title,
start: selectInfo.startStr,
end: selectInfo.endStr,
allDay: selectInfo.allDay
});
}
this.calendar.unselect();
}
handleEventClick(clickInfo) {
const event = clickInfo.event;
this.editEvent(event);
}
handleEventDrop(dropInfo) {
this.updateEvent(dropInfo.event);
}
handleEventResize(resizeInfo) {
this.updateEvent(resizeInfo.event);
}
createEvent(eventData) {
fetch('/api/calendar/events', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify(eventData)
})
.then(response => response.json())
.then(event => {
this.calendar.addEvent(event);
});
}
updateEvent(event) {
const eventData = {
id: event.id,
title: event.title,
start: event.startStr,
end: event.endStr,
allDay: event.allDay
};
fetch(`/api/calendar/events/${event.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify(eventData)
});
}
}
Best Practices
- Performance: Implement event pagination and lazy loading
- Security: Validate all event data and implement proper authorization
- UX: Provide clear feedback for all user actions
- Mobile: Ensure touch-friendly interface on mobile devices
- Accessibility: Use proper ARIA labels and keyboard navigation
- Time Zones: Handle time zone conversions properly
- Recurring Events: Implement proper recurring event logic
Production Deployment
The Calendar application is ready for production use in both static HTML and Laravel Livewire editions. For production deployment:
- Database Setup - Create necessary tables for events and categories
- External Integrations - Set up Google Calendar, Outlook, or other calendar services
- File Storage - Configure attachment storage for event files
- Security - Implement proper authentication and authorization
- Performance - Set up caching for frequently accessed data
- Notifications - Configure email/SMS notifications for events