article

Wednesday, May 28, 2025

Laravel 12 Schedule Calendar | Fullcalendar

Laravel 12 Schedule Calendar | Fullcalendar

Download Laravel App

https://laravel.com/docs/12.x/installation

Connecting our Database

open .env file root directory.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=8889
DB_DATABASE=laravel12dev
DB_USERNAME=root
DB_PASSWORD=root

Database Migration
php artisan migrate

myapp>php artisan migrate
Migration table created successfully.
check database table

Create tables Schedule Model php artisan make:model Schedule -m myapp>php artisan make:model Schedule -m Open new Schedule migrations yourproject/database/migrations laravelproject\database\migrations\_create_schedule_table.php
//laravelproject\database\migrations\_create_schedule_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('schedules', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->dateTime('start');
            $table->dateTime('end');
            $table->string('color')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('schedules');
    }
};
run
myapp>php artisan migrate
update Schedule Model
app/models/Schedule.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Schedule extends Model
{
    use HasFactory;

    protected $fillable = [
        'title',
        'start', 
        'end',
        'color',
    ];
}
Create ScheduleController
php artisan make:controller ScheduleController
change it with the following codes:
app\Http\Controllers\ScheduleController.php

//app\Http\Controllers\ScheduleController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Schedule;
use Carbon\Carbon;

class ScheduleController extends Controller
{
    public function index()
    {
        return view('schedule.index');
    }

    public function store(Request $request)
    {
        $item = new Schedule();
        $item->title = $request->title;
        $item->start = $request->start;
        $item->end = $request->end;
        $item->color = $request->color;
        $item->save();

        return redirect()->route("schedule.index");
    }

    public function getEvents()
    {
        $schedules = Schedule::all();
        return response()->json($schedules);
    }

    public function update(Request $request, $id)
    {
        $schedule = Schedule::findOrFail($id);

        $schedule->update([
            'start' => Carbon::parse($request->input('start_date'))->setTimezone('UTC'),
            'end' => Carbon::parse($request->input('end_date'))->setTimezone('UTC'),
        ]);

        return response()->json(['message' => 'Event moved successfully']);
    }

    public function deleteEvent($id)
    {
        $schedule = Schedule::findOrFail($id);
        $schedule->delete();

        return response()->json(['message' => 'Event deleted successfully']);
    }

    public function search(Request $request)
    {
        $searchKeywords = $request->input('title');
        $matchingEvents = Schedule::where('title', 'like', '%' . $searchKeywords . '%')->get();

        return response()->json($matchingEvents);
    }
}
Create AuthController
php artisan make:controller AuthController
change it with the following codes:
app\Http\Controllers\AuthController.php

//app\Http\Controllers\AuthController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
    public function login()
    {
        $pass = Hash::make("123456789");
        return view("login")->with('password', $pass);
    }

    public function loginAction(Request $request)
    {
        $validated = $request->validate([
            'email' => 'required|email',
            'password' => 'required'
        ]);

        if (!Auth::attempt($request->only('email', 'password'), $request->boolean('remember'))) {
            throw ValidationException::withMessages([
                'email' => trans('auth.failed')
            ]);
        }

        $request->session()->regenerate();
        return redirect()->route("products.index")->with("success", "Login successfully");
    }

    public function logout(Request $request)
    {
        Auth::guard('web')->logout();

        $request->session()->invalidate();

        return redirect('/login');
    }
}
Create View File resources/views/layouts/app.blade.php
//resources/views/layouts/app.blade.php
<!DOCTYPE html>
<html>

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
    <title>Schedule Fullcalendar</title>
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4Q6Gf2aSP4eDXB8Miphtr37CMZZQ5oXLH2yaXMJ2w8e2ZtHTl7GptT4jmndRuHDT" crossorigin="anonymous">
</head>

<body>
    <div class="layout-wrapper layout-content-navbar">
        <div class="layout-container">
            <div class="layout-page">
                <div class="content-wrapper">
                    @yield('content')
                </div>
            </div>
        </div>
    </div>
</body>

</html>
Home resources/views/schedule/index.blade.php
//resources/views/schedule/index.blade.php
@extends('layouts.app')
@section('content')
<div class="container mt-5">
    <div class="row">
        <h1>Laravel 12 Schedule Calendar | Fullcalendar</h1>
        <div class="col-md-6">
            <div class="input-group mb-3">
                <input type="text" id="searchInput" class="form-control" placeholder="Search events">
                <div class="input-group-append">
                    <button id="searchButton" class="btn btn-primary">Search</button>
                </div>
            </div>
        </div>
        <div class="col-md-6">
            Color : <input type="color" id="myColor" class='form-control' name="colorpicker" onchange="myFunction()" />
            <p id="demo"></p>
        </div>
    </div>

    @if (Session::has('success'))
    <span class="alert alert-success p-2">{{ Session::get('success')}}</span>
    @endif
    @if (Session::has('error'))
    <span>{{ Session::get('error')}}</span>
    @endif

    <div class="card">
        <div class="card-body">
            <div id="calendar" style="width: 100%;height:100vh"></div>
        </div>
    </div>
</div>
<script
    src="https://code.jquery.com/jquery-3.7.1.js"
    integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4="
    crossorigin="anonymous"></script>
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@6.1.17/index.global.min.js'></script> <!--fullcalendar.io/docs/initialize-globals-->

<script type="text/javascript">
    $.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });

    var calendarEl = document.getElementById('calendar');
    var events = [];
    var calendar = new FullCalendar.Calendar(calendarEl, {
        headerToolbar: {
            left: 'prev,next today',
            center: 'title',
            right: 'dayGridMonth,timeGridWeek,timeGridDay'
        },
        initialView: 'dayGridMonth',
        events: '/events',
        editable: true,
        selectable: true,
        select: function(info) {
            var title = prompt('Event Title:');
            var color = prompt("Color", "#0d6efd");
            if (title && color) {
                //alert('selected ' + info.startStr + ' to ' + info.endStr);
                $.ajax({
                    url: "/create-schedule",
                    data: 'title=' + title + '&start=' + info.startStr + '&end=' + info.endStr + '&color=' + color + '&_token=' + "{{ csrf_token() }}",
                    type: "post",
                    success: function(data) {
                        alert("Added Successfully");
                        calendar.refetchEvents(); // Refresh events
                    }
                });

            }
        },
        // Drag And Drop
        eventDrop: function(info) {
            var eventId = info.event.id;
            var newStartDate = info.event.start;
            var newEndDate = info.event.end || newStartDate;
            var newStartDateUTC = newStartDate.toISOString().slice(0, 10);
            var newEndDateUTC = newEndDate.toISOString().slice(0, 10);

            $.ajax({
                method: 'post',
                url: `/schedule/${eventId}`,
                data: {
                    '_token': "{{ csrf_token() }}",
                    start_date: newStartDateUTC,
                    end_date: newEndDateUTC,
                },
                success: function(response) {
                    alert(response.message);
                    console.log('Event moved successfully.');
                },
                error: function(error) {
                    console.error('Error moving event:', error);
                }
            });
        },
        // Deleting The Event
        eventContent: function(info) {
            var eventTitle = info.event.title;
            var eventElement = document.createElement('div');
            eventElement.innerHTML = '<span style="cursor: pointer;">❌</span> ' + eventTitle;

            eventElement.querySelector('span').addEventListener('click', function() {
                if (confirm("Are you sure you want to delete this event?")) {
                    var eventId = info.event.id;
                    $.ajax({
                        method: 'get',
                        url: '/schedule/delete/' + eventId,
                        headers: {
                            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                        },
                        success: function(response) {
                            alert(response.message);
                            console.log('Event deleted successfully.');
                            calendar.refetchEvents(); // Refresh events after deletion
                        },
                        error: function(error) {
                            console.error('Error deleting event:', error);
                        }
                    });
                }
            });
            return {
                domNodes: [eventElement]
            };
        },
    });
    calendar.render();

    document.getElementById('searchButton').addEventListener('click', function() {
        var searchKeywords = document.getElementById('searchInput').value.toLowerCase();
        filterAndDisplayEvents(searchKeywords);
    });

    function filterAndDisplayEvents(searchKeywords) {
        $.ajax({
            method: 'GET',
            url: `/events/search?title=${searchKeywords}`,
            success: function(response) {
                calendar.removeAllEvents();
                calendar.addEventSource(response);
            },
            error: function(error) {
                console.error('Error searching events:', error);
            }
        });
    }

    function myFunction() {
        var x = document.getElementById("myColor").value;
        document.getElementById("demo").innerHTML = x;
    }
</script>
@endsection
resources/views/login.blade.php
//resources/views/login.blade.php
@extends('layouts.app')
@section('content')
<div class="container mt-5">
    <div class="card">
        <div class="card-header">
            Login
        </div>
        <div class="card-body">
            <form action="{{ route('login.action') }}" method="POST" class="user">
                @csrf
                @if ($errors->any())
                <div class="alert alert-danger">
                    <ul>
                        @foreach ($errors->all() as $error)
                        <li>{{ $error }}</li>
                        @endforeach
                    </ul>
                </div>
                @endif
                <div class="mb-3">
                    <label class="form-label">Email</label>
                    <input name="email" type="email" class="form-control form-control-user" id="exampleInputEmail" aria-describedby="emailHelp" placeholder="Enter Email Address...">
                </div>
                <div class="mb-3">
                    <label class="form-label">Password</label>
                    <input name="password" type="password" class="form-control form-control-user" id="exampleInputPassword" placeholder="Password">
                    {{ $password }}
                </div>
                <div class="mb-3">
                    <div class="custom-control custom-checkbox small">
                        <input name="remember" type="checkbox" class="custom-control-input" id="customCheck">
                        <label class="custom-control-label" for="customCheck">Remember
                            Me</label>
                    </div>
                </div>
                <button type="submit" class="btn btn-primary btn-block btn-user">Login</button>
            </form>
        </div>
    </div>

</div>

@endsection
Routes
routes/web.php
//routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ScheduleController; //php artisan make:controller ScheduleController
use App\Http\Controllers\AuthController;

Route::get('/', function () {
    return view('welcome');
});

Route::middleware('auth')->group(function () {
    Route::controller(ScheduleController::class)->group(function () {
        Route::get('/fullcalender', 'index')->name('schedule.index');
        Route::post('/create-schedule', 'store')->name('schedule.store');
        Route::get('/events', 'getEvents')->name('schedule.events');
        Route::post('/schedule/{id}', 'update')->name('schedule.update');
        Route::get('/schedule/delete/{id}', 'deleteEvent')->name('schedule.deleteEvent');
        Route::get('/events/search', 'search')->name('schedule.search');
    });
});

Route::controller(AuthController::class)->group(function () {
    Route::get('login', 'login')->name('login');
    Route::post('login', 'loginAction')->name('login.action');
    Route::get('logout', 'logout')->middleware('auth')->name('logout');
});

Related Post