Criando um Calendário com persistência, AJAX e com Laravel
Olá, mundo!
Tudo bem?
Hoje venho trazer um outro exemplo com a simplicidade de integração com componentes de bibliotecas Javascript com Laravel.
Vamos ao trabalho//
Vamos criar um novo projeto com Laravel. Estou usando a Versão 8.1 do PHP e o Laravel 9, no entanto funciona com a versão 7.4 do PHP e o Laravel 8.
composer create-project laravel/laravel laravel_cal

Com o projeto criado, vamos a configuração inicial de nosso arquivo .env na pasta raiz do projeto:
.env
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_cal DB_USERNAME=<usuário> DB_PASSWORD=<senha>
Agora vamos criar na pasta de nosso projeto, nossa migration:
php artisan make:migration create_eventos_table

database/migrations/2022_12_05_132037_create_eventos_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.
*
* @return void
*/
public function up()
{
Schema::create('eventos', function (Blueprint $table) {
$table->id();
$table->string('titulo');
$table->date('inicio');
$table->date('fim');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('eventos');
}
};
Vamos criar nosso banco de dados:
create database laravel_cal;

Pronto, agora vamos rodar nossa migration:
php artisan migrate

criaremos nossa classe model:
php artisan make:model Evento
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Evento extends Model
{
use HasFactory;
protected $fillable = [
'titulo', 'inicio', 'fim'
];
}
Agora criaremos nosso controller, que terá dois métodos: um que pegará as informações persistentes no banco, e outro que fará requisições assíncronas, utilizando JQuery e o FullCalendar, para que realize inserção, alteração e exclusão de maneira reativa:
php artisan make:controller CalendarioController
CalendarioController.php
<?php
namespace App\Http\Controllers;
use App\Models\Evento;
use Illuminate\Http\Request;
class CalendarioController extends Controller
{
public function index(Request $request)
{
if($request->ajax()) {
$data = Evento::whereDate('inicio', '>=', $request->inicio)
->whereDate('fim', '<=', $request->fim)
->get(['id', 'titulo', 'inicio', 'fim']);
return response()->json($data);
}
return view('calendario');
}
/**
* Write code on Method
*
* @return response()
*/
public function ajax(Request $request)
{
switch ($request->type) {
case 'add':
$evento = Evento::create([
'titulo' => $request->titulo,
'inicio' => $request->inicio,
'fim' => $request->fim,
]);
return response()->json($evento);
break;
case 'update':
$evento = Evento::find($request->id)->update([
'titulo' => $request->titulo,
'inicio' => $request->inicio,
'fim' => $request->fim,
]);
return response()->json($evento);
break;
case 'delete':
$evento = Evento::find($request->id)->delete();
return response()->json($evento);
break;
default:
#
break;
}
}
}
Como podemos observar nosso Controller, no método index() que já faz requisições ajax, através da injeção de dependência Request do Laravel, já no método ajax() temos a condição de cada função de adição, remoção, atualização que faremos a chamada em nossa view, através do JQuery.
Criaremos agora nossa view, resources/view/calendario.blade.php
<!DOCTYPE html>
<html>
<head>
<title>Calendário com Laravel</title>
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/fullcalendar.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/fullcalendar.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/locale/pt-br.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" />
</head>
<body>
<div class="container">
<h1>Calendário com Laravel e JQuery</h1>
<div id='calendar'></div>
</div>
<script>
$(document).ready(function () {
var SITEURL = "{{ url('/') }}";
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
var calendar = $('#calendar').fullCalendar({
editable: true,
events: SITEURL + "/calendario",
displayEventTime: false,
editable: true,
eventRender: function (event, element, view) {
if (event.allDay === 'true') {
event.allDay = true;
} else {
event.allDay = false;
}
},
selectable: true,
selectHelper: true,
select: function (start, end, allDay) {
var title = prompt('Título do Evento:');
if (title) {
var start = $.fullCalendar.formatDate(start, "Y-MM-DD");
var end = $.fullCalendar.formatDate(end, "Y-MM-DD");
$.ajax({
url: SITEURL + "/calendarioAjax",
data: {
title: title,
start: start,
end: end,
type: 'add'
},
type: "POST",
success: function (data) {
displayMessage("Evento criado com Sucesso");
calendar.fullCalendar('renderEvent',
{
id: data.id,
title: title,
start: start,
end: end,
allDay: allDay
},true);
calendar.fullCalendar('unselect');
}
});
}
},
eventDrop: function (event, delta) {
var start = $.fullCalendar.formatDate(event.start, "Y-MM-DD");
var end = $.fullCalendar.formatDate(event.end, "Y-MM-DD");
$.ajax({
url: SITEURL + '/calendarioAjax',
data: {
title: event.title,
start: start,
end: end,
id: event.id,
type: 'update'
},
type: "POST",
success: function (response) {
displayMessage("Evento Atualizado com Sucesso!");
}
});
},
eventClick: function (event) {
var deleteMsg = confirm("Você deseja apagar este evento?");
if (deleteMsg) {
$.ajax({
type: "POST",
url: SITEURL + '/calendarioAjax',
data: {
id: event.id,
type: 'delete'
},
success: function (response) {
calendar.fullCalendar('removeEvents', event.id);
displayMessage("Evento Apagado com Sucesso");
}
});
}
}
});
});
function displayMessage(message) {
toastr.success(message, 'Evento');
}
</script>
</body>
</html>
routes/web.php
Route::get('calendario', [CalendarioController::class, 'index']);
Route::post('calendarioAjax', [CalendarioController::class, 'ajax']);
agora vamos rodar a aplicação:
php artisan serve
A biblioteca Fullcalendar tem uma ampla documentação para se customizar conforme a necessidade de seu negócio.
Código fonte no Github.
Estudem seus homens com tanto cuidado quanto um cirurgião
estuda um caso difícil. E, quando tiverem certeza do diagnóstico,
apliquem o remédio. Lembrem-se de que vocês aplicam o remédio
para efetuar uma cura, não para ver a vítima contorcer-se. Pode ser
necessário cortar fundo, mas, quando estiverem satisfeitos com o
diagnóstico, não se desviem do objetivo por alguma falsa simpatia
pelo paciente. – O Manuscrito Original – Napoleon Hill