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