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 Inertia\Inertia;
use App\Models\Schedule;
class ScheduleController extends Controller
{
public function index()
{
$query = Schedule::select('id', 'title', 'start', 'end', 'color', 'created_at')->get();
return Inertia::render('schedule/index', [
'schedules' => $query,
'flash' => [
'success' => session('success'),
'error' => session('error')
]
]);
}
public function store(Request $request)
{
Schedule::create([
'title' => $request->title,
'start' => $request->startdate,
'end' => $request->enddate,
'color' => $request->color,
]);
return redirect()->route('schedule.index')->with('success', 'Schedule created successfully!');
}
public function destroy($id)
{
Schedule::findOrFail($id)->delete();
return redirect()->route('schedule.index')->with('success', 'Schedule Deleted successfully!');
}
public function update(Request $request, $id)
{
$schedule = Schedule::findOrFail($id);
$schedule->update($request->only('start', 'end'));
return redirect()->route('schedule.index')->with('success', 'Schedule Updated successfully!');
}
}
Frontend with React and InertiaJS Add sidebar menu product mainNavItems from reactjs\rescourses\js\components\app-sidebar.tsx
Index.tsx File: pages\schedule\index.tsx
reactjs\resources\js\pages\schedule\index.tsx
//reactjs\resources\js\pages\schedule\index.tsx
import AppLayout from '@/layouts/app-layout';
import { type BreadcrumbItem } from '@/types';
import { Head, router } from '@inertiajs/react';
import FullCalendar from '@fullcalendar/react'
import dayGridPlugin from '@fullcalendar/daygrid' //npm install --save @fullcalendar/react @fullcalendar/core @fullcalendar/daygrid @fullcalendar/interaction
import interactionPlugin from "@fullcalendar/interaction"; // needed for dayClick
import {
DateSelectArg,
formatDate,
} from "@fullcalendar/core"; // npm install @fullcalendar/interaction https://fullcalendar.io/docs/react
import { useState, useEffect } from 'react';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { DialogDescription } from '@radix-ui/react-dialog';
import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { CheckCircle2, XCircle } from 'lucide-react';
interface Schedule {
id: number;
title: string;
start: Date;
end: Date;
color: string;
}
interface Props {
schedules: Schedule[];
flash?: {
success?: string;
error?: string;
};
}
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Schedule',
href: '/admin/schedule',
},
];
export default function Dashboard({ schedules, flash }: Props) {
//console.log(schedules);
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(false);
const [title, setTitle] = useState<string>("");
const [color, setColor] = useState<string>("#000000");
const [startdate, setStart] = useState<DateSelectArg | null>(null);
const [enddate, setEnd] = useState<DateSelectArg | null>(null);
const [toastMessage, setToastMessage] = useState('');
const [toastType, setToastType] = useState<'success' | 'error'>('success');
const [showToast, setShowToast] = useState(false);
//console.log(flash);
useEffect(() => {
if (flash?.success) {
setToastMessage(flash.success);
setToastType('success');
setShowToast(true);
} else if (flash?.error) {
setToastMessage(flash.error);
setToastType('error');
setShowToast(true);
}
}, [flash]);
useEffect(() => {
if (showToast) {
const timer = setTimeout(() => {
setShowToast(false);
}, 3000);
return () => clearTimeout(timer);
}
}, [showToast]);
const handleDateClick = (selected: DateSelectArg) => {
const start = selected.startStr
const end = selected.endStr
//console.log(start)
setStart(start)
setEnd(end)
setIsDialogOpen(true);
};
function handleSubmit(e: React.FormEvent) {
e.preventDefault();
//console.log(color);
router.post(route('schedule.store'), {
_method: 'post',
title,
startdate,
enddate,
color,
});
handleCloseDialog();
};
const handleCloseDialog = () => {
setIsDialogOpen(false);
};
function formatEvents() {
return schedules.map(schedule => {
const {id, title, start, end, color} = schedule
let startTime = new Date(start)
let endTime = new Date(end)
return {
id,
title,
start: startTime,
end: endTime,
color,
}
})
}
function handleEventDrop(info) {
if(window.confirm("Are you sure you want to change the event date?")){
//console.log('change confirmed')
//console.log(info.event.start)
const start = (new Date(info.event.start)).toISOString().slice(0, 10)
const end = (new Date(info.event.end)).toISOString().slice(0, 10)
router.put(`/admin/schedule/${info.event.id}`, {
_method: 'put',
start,
end,
});
} else {
console.log('change aborted')
}
}
function handleEventClick(data) {
console.log(data);
console.log(data.event.id);
if (confirm(`Are you sure you want to delete the event '${data.event.title}'`)) {
router.delete(`/admin/schedule/${data.event.id}`, {
onSuccess: () => {
router.reload();
},
onError: () => {
console.error("Failed to delete post.");
},
});
data.event.remove()
}
}
return (
<AppLayout breadcrumbs={breadcrumbs}>
<Head title="Schedule" />
<div className="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
{showToast && (
<div className={`fixed top-4 right-4 z-50 flex items-center gap-2 rounded-lg p-4 shadow-lg ${toastType === 'success' ? 'bg-green-500' : 'bg-red-500'
} text-white animate-in fade-in slide-in-from-top-5`}>
{toastType === 'success' ? (
<CheckCircle2 className="h-5 w-5" />
) : (
<XCircle className="h-5 w-5" />
)}
<span>{toastMessage}</span>
</div>)}
<h1>Laravel 12 React Starter kit Schedule Calendar | Fullcalendar</h1>
<FullCalendar
plugins={[dayGridPlugin, interactionPlugin]} // Initialize calendar with required plugins.
headerToolbar = {{
left: 'prev,next' ,
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
}}
initialView="dayGridMonth"
editable={true}
selectable={true} // Allow dates to be selectable.
selectMirror={true} // Mirror selections visually.
select={handleDateClick} // Handle date selection to create new events.
events={formatEvents()}
eventDrop={handleEventDrop}
eventClick={handleEventClick}
//events={[
// {title : 'Event 1', start: '2025-05-19', end: '2025-05-21'},
//]}
/>
</div>
<div className="flex justify-between items-center">
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Add New Event Details</DialogTitle>
<DialogDescription>
Make changes to your category here. Click update when you're done.
</DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="title">Title</Label>
<Input id="title"
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
</div>
<div className="space-y-2">
<Label htmlFor="color">Color</Label>
<Input type="color" id="color" name="color"
value={color}
onChange={(e) => setColor(e.target.value)}
/>
</div>
<Button type="submit">
Create
</Button>
</form>
</DialogContent>
</Dialog>
</div>
</AppLayout>
);
}
Routes routes/web.php
//routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use App\Http\Controllers\ScheduleController;
Route::get('/', function () {
return Inertia::render('welcome');
})->name('home');
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('dashboard', function () {
return Inertia::render('dashboard');
})->name('dashboard');
Route::get('/admin/schedule', [ScheduleController::class, 'index'])->name('schedule.index');
Route::post('/admin/schedule', [ScheduleController::class, 'store'])->name('schedule.store');
Route::delete('/admin/schedule/{id}', [ScheduleController::class, 'destroy'])->name('schedule.destroy');
Route::put('/admin/schedule/{id}', [ScheduleController::class, 'update'])->name('users.update');
});
require __DIR__.'/settings.php';
require __DIR__.'/auth.php';
Run php artisan serve and npm run dev myapp>composer run dev Starting Laravel development server: http://127.0.0.1:8000
