Inventory Management System in Laravel 12 React Starter Kit Using Open Code AI
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=laravel12DB
DB_USERNAME=root
DB_PASSWORD=root
Database Migration
php artisan migrate
myapp>php artisan migrate
Migration table created successfully.
check database table
Run php artisan serve and npm run dev myapp>composer run dev
Starting Laravel development server: http://127.0.0.1:8000
article
Saturday, March 14, 2026
Wednesday, September 10, 2025
Laravel 12 Quiz React | React Starter Kit
Laravel 12 Quiz React | React Starter Kit
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=laravel12DB
DB_USERNAME=root
DB_PASSWORD=root
Database Migration
php artisan migrate
myapp>php artisan migrate
Migration table created successfully.
check database table
php artisan make:controller HomeController change it with the following codes:
app\Http\Controllers\HomeController.php
php artisan make:model Question -m myapp>php artisan make:model Question -m
Open new Questions migrations yourproject/database/migrations laravelproject\database\migrations\_create_questions_table.php
Migration table created successfully.
check database table
update Question Model
app/models/Question.php
File: pages\quiz.tsx
reactjs\resources\js\pages\quiz.tsx
reactjs\resources\js\components\QuestionCard.tsx
Starting Laravel development server: http://127.0.0.1:8000
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=laravel12DB
DB_USERNAME=root
DB_PASSWORD=root
Database Migration
php artisan migrate
myapp>php artisan migrate
Migration table created successfully.
check database table
php artisan make:controller HomeController change it with the following codes:
app\Http\Controllers\HomeController.php
//app\Http\Controllers\HomeController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Inertia\Inertia;
use App\Models\Question;
class HomeController extends Controller
{
public function get_home_data()
{
//$question = Question::latest()->get();
$question = Question::where('category', "Programming")->latest()->get();
return Inertia::render('quiz', [
'questionsitems' => $question,
]);
#return Inertia::render('quiz');
}
}
Create tables Question Model php artisan make:model Question -m myapp>php artisan make:model Question -m
Open new Questions migrations yourproject/database/migrations laravelproject\database\migrations\_create_questions_table.php
//laravelproject\database\migrations\_create_questions_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('questions', function (Blueprint $table) {
$table->id();
$table->string('question');
$table->json('options');
$table->string('answer');
$table->string('category');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('questions');
}
};
myapp>php artisan migrate Migration table created successfully.
check database table
update Question Model
app/models/Question.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Question extends Model
{
protected $fillable = [
'question',
'options',
'answer',
'category',
];
protected $casts = [
'options' => 'array', // Automatically casts to/from array/JSON
];
}
Frontend with React and InertiaJS File: pages\quiz.tsx
reactjs\resources\js\pages\quiz.tsx
//reactjs\resources\js\pages\quiz.tsx
'use client';
import { Head } from '@inertiajs/react';
import { useState } from 'react';
import QuestionCard from "@/components/QuestionCard"
import Confetti from "react-confetti";
interface QuestionItem {
id: number;
question: string;
options: string;
answer: string;
category: string;
}
interface Props {
questionsitems: QuestionItem[];
}
export default function quiz({ questionsitems }: Props) {
//console.log(questionsitems)
const [currentQuestion, setCurrentQuestion] = useState(0);
const [selectedAnswer, setSelectedAnswer] = useState(null);
const [score, setScore] = useState(0);
const [isFinished, setIsFinished] = useState(false);
const [showFeedback, setShowFeedback] = useState(false);
const handleAnswer = (option) => {
if (showFeedback) return;
setSelectedAnswer(option);
setShowFeedback(true);
if (option === questionsitems[currentQuestion].answer) {
setScore(score + 1);
}
};
const goToNext = () => {
if (currentQuestion + 1 < questionsitems.length) {
setCurrentQuestion(currentQuestion + 1);
setSelectedAnswer(null);
setShowFeedback(false);
} else {
setIsFinished(true);
}
};
const restartQuiz = () => {
setCurrentQuestion(0);
setScore(0);
setSelectedAnswer(null);
setShowFeedback(false);
setIsFinished(false);
};
const calculateProgress = () => {
if (isFinished) return 100;
const baseProgress = (currentQuestion / questionsitems.length) * 100;
const questionProgress = selectedAnswer ? (1 / questionsitems.length) * 100 : 0;
return baseProgress + questionProgress;
};
const percentage = (score / questionsitems.length) * 100;
const showConfetti = isFinished && percentage > 50;
return (
<div className="min-h-screen">
<Head title="Quiz"></Head>
<div className="min-h-screen bg-gray-900 text-white flex flex-col items-center justify-center p-4 ">
{showConfetti && <Confetti />}
<div className="text-center mb-8">
<h1 className="text-4xl font-bold text-purple-600 mb-2">Laravel 12 Quiz React | React Starter Kit</h1>
<p className="text-gray-400">Test your knowledge</p>
</div>
<div className="w-full max-w-xl mb-6">
<div className="bg-gray-700 h-3 rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-indigo-500 to-purple-600 duration-500 ease-out transition-all"
style={{ width: `${calculateProgress()}%` }}
></div>
</div>
</div>
{!isFinished ? (
<>
<QuestionCard
showFeedback={showFeedback}
onAnswer={handleAnswer}
data={questionsitems[currentQuestion]}
current={currentQuestion}
total={questionsitems.length}
selected={selectedAnswer}
/>
<div className="mt-6 min-h-[60px]">
{showFeedback && (
<button
className="bg-gradient-to-r from-indigo-600 to-purple-600 py-3 px-6 rounded-lg font-medium shadow-lg cursor-pointer"
onClick={goToNext}
>
{currentQuestion + 1 < questionsitems.length
? "Continue"
: "See Results"}
</button>
)}
</div>
</>
) : (
<div className="text-center">
<h2 className="text-3xl font-bold mb-4">Quiz Completed!</h2>
<p className="text-xl mb-6">
You scored <span>{score}</span> out of{" "}
<span className="font-bold">{questionsitems.length}</span> and it is{" "}
{Math.round((score / questionsitems.length) * 100)}%
</p>
<button
className="bg-gradient-to-r from-indigo-600 to-purple-600 py-3 px-6 rounded-lg font-medium shadow-lg cursor-pointer"
onClick={restartQuiz}
>
Restart Quiz
</button>
</div>
)}
</div>
</div>
);
}
File: js\components\QuestionCard.tsx reactjs\resources\js\components\QuestionCard.tsx
//reactjs\resources\js\components\QuestionCard.tsx
const QuestionCard = ({
data,
onAnswer,
showFeedback,
selected,
current,
total,
}) => {
console.log(data)
const { question, options, answer } = data;
const getButtonStyle = (option) => {
if (!showFeedback) {
return "bg-indigo-700 hover:bg-indigo-600 hover:scale-[1.01]";
}
if (option === answer) return "bg-emerald-600";
if (option === selected) return "bg-rose-600";
return "bg-gray-600";
};
return (
<div className="bg-gray-800 p-6 rounded-2xl shadow-lg w-full max-w-xl border border-gray-700">
<div className="flex justify-between items-center mb-4">
<h2 className="text-lg font-medium text-gray-300">
Question {current + 1} of {total}
</h2>
<span className="text-sm bg-gray-700 px-3 py-1 rounded-full">
{selected
? Math.round(((current + 1) / total) * 100) + "% complete"
: Math.round((current / total) * 100) + "% complete"}
</span>
</div>
<p className="text-xl font-medium mb-6">{question}</p>
<div className="grid gap-3">
{options.map((option, index) => (
<button
className={`${getButtonStyle(
option
)} text-left px-4 py-3 cursor-pointer rounded-lg text-white `}
key={index}
onClick={() => onAnswer(option)}
disabled={showFeedback}
>
{option}
</button>
))}
</div>
</div>
);
};
export default QuestionCard;
//routes/web.php
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use App\Http\Controllers\HomeController;
Route::get('/', function () {
return Inertia::render('welcome');
})->name('home');
Route::get('/quiz', [HomeController::class, 'get_home_data'])->name('quiz');
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('dashboard', function () {
return Inertia::render('dashboard');
})->name('dashboard');
});
Run php artisan serve and npm run dev myapp>composer run dev Starting Laravel development server: http://127.0.0.1:8000
Monday, September 8, 2025
Laravel 12 Multiple Upload Fle React | React Starter Kit
Laravel 12 Multiple Upload Fle React | React Starter Kit
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=laravel12DB
DB_USERNAME=root
DB_PASSWORD=root
Database Migration
php artisan migrate
myapp>php artisan migrate
Migration table created successfully.
check database table
php artisan make:controller ProductController change it with the following codes:
app\Http\Controllers\ProductController.php
php artisan make:model Product -m myapp>php artisan make:model Product -m
Open new Products migrations yourproject/database/migrations laravelproject\database\migrations\_create_products_table.php
Migration table created successfully.
check database table
update Product Model
app/models/Product.php
Add sidebar menu product mainNavItems from reactjs\rescourses\js\components\app-sidebar.tsx
File: pages\admin\products\create.tsx
reactjs\resources\js\pages\users\create.tsx
reactjs\resources\js\components\ImageUploadInput.tsx
reactjs\resources\js\components\ui\textarea.tsx
reactjs\resources\js\lib\utils.ts
reactjs\resources\js\types\products.ts
Starting Laravel development server: http://127.0.0.1:8000
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=laravel12DB
DB_USERNAME=root
DB_PASSWORD=root
Database Migration
php artisan migrate
myapp>php artisan migrate
Migration table created successfully.
check database table
php artisan make:controller ProductController change it with the following codes:
app\Http\Controllers\ProductController.php
//app\Http\Controllers\ProductController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Inertia\Inertia;
use App\Models\Product;
use Illuminate\Support\Str;
class ProductController extends Controller
{
public function create()
{
return Inertia::render('admin/products/create');
}
public function store(Request $request)
{
$request->validate([
'name' => 'string|required|max:255',
'description' => 'string|nullable',
'images' => 'nullable|array',
'images.*' => 'image|max:2048',
]);
// Slug
$slug = Str::slug($request->name);
// Image
$images = [];
if ($request->hasFile('images')) {
foreach ($request->file('images') as $image) {
$images[] = $image->store('products/images', 'public');
}
}
$new_product = [
'name' => $request->name,
'slug' => $slug,
'description' => $request->description,
'price' => $request->price,
'images' => $images,
];
$prod = Product::create($new_product);
//dd($prod);
return redirect()->route('dashboard.products.index')->with('success', 'Product created successfully!');
}
}
Create tables Product Model php artisan make:model Product -m myapp>php artisan make:model Product -m
Open new Products migrations yourproject/database/migrations laravelproject\database\migrations\_create_products_table.php
//laravelproject\database\migrations\_create_products_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('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('slug')->unique();
$table->decimal('price', 10, 2)->default(0);
$table->text('description')->nullable();
$table->json('images')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};
myapp>php artisan migrate Migration table created successfully.
check database table
update Product Model
app/models/Product.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $fillable = [
'name',
'slug',
'price',
'description',
'images',
];
protected $casts = [
'images' => 'array',
'price' => 'decimal:2',
];
}
Frontend with React and InertiaJS Add sidebar menu product mainNavItems from reactjs\rescourses\js\components\app-sidebar.tsx
File: pages\admin\products\create.tsx
reactjs\resources\js\pages\users\create.tsx
//reactjs\resources\js\pages\admin\products\create.tsx
import AppLayout from '@/layouts/app-layout';
import { type BreadcrumbItem } from '@/types';
import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Textarea } from "@/components/ui/textarea"
import { Head, router, useForm } from '@inertiajs/react';
import { CompactFileInput } from '@/components/ImageUploadInput';
import { useState } from 'react';
import { LoaderCircle } from 'lucide-react';
import InputError from '@/components/input-error';
import { CreateProductItem } from '@/types/products';
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Create Product',
href: '/dashboard/products/create',
},
];
export default function Dashboard() {
const [images, setImages] = useState<File[]>([]);
const { data, setData, processing, errors, reset } = useForm<Required<CreateProductItem>>({
name: '',
slug: '',
image: null,
description: '',
price: 0,
images: null,
});
const handleSubmit: React.FormEventHandler = (e) => {
e.preventDefault();
data.images = images;
console.log(data.images);
router.post('/dashboard/products', data, {
onFinish: () => {
reset();
console.log("success");
},
});
};
return (
<AppLayout breadcrumbs={breadcrumbs}>
<Head title="Create Product" />
<div className="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
<div className="flex justify-end">Create New Product</div>
<div className="p-10 border-sidebar-border/70 dark:border-sidebar-border relative min-h-[100vh] flex-1 overflow-hidden rounded-xl border md:min-h-min">
<form onSubmit={handleSubmit} className="space-y-4">
<div className="grid gap-6">
<div className="grid gap-2">
<Label htmlFor="title">Product Name</Label>
<Input id="name" value={data.name} onChange={(e) => setData('name', e.target.value)} />
<InputError message={errors.name} className="mt-2" />
</div>
</div>
<div className="grid gap-6">
<div className="grid gap-2">
<Label htmlFor="price">Price</Label>
<Input id="price" value={data.price} onChange={(e) => setData('price', Number(e.target.value))} />
<InputError message={errors.price} className="mt-2" />
</div>
</div>
<div className="grid gap-2">
<div className="flex items-center">
<Label htmlFor="message">Product Description</Label>
</div>
<Textarea
value={data.description}
onChange={(e) => setData('description', e.target.value)}
placeholder="Type your description here."
id="message"
/>
<InputError message={errors.description} />
</div>
<div className="grid gap-2">
<h2 className="mb-3 text-lg font-semibold">Upload product Images</h2>
<div className="rounded border p-4">
<CompactFileInput multiple={true} maxSizeMB={1} onChange={setImages} />
</div>
</div>
<Button type="submit" className="mt-4 w-full" disabled={processing}>
{processing && <LoaderCircle className="h-4 w-4 animate-spin" />}
Add Product
</Button>
</form>
</div>
</div>
</AppLayout>
);
}
File: js\components\ImageUploadInput.tsx reactjs\resources\js\components\ImageUploadInput.tsx
//reactjs\resources\js\components\ImageUploadInput.tsx
'use client';
import React, { useState } from 'react';
// Shared types
type ImageFile = {
id: string;
file: File;
preview: string;
};
type FileInputProps = {
multiple?: boolean;
maxSizeMB?: number;
onChange?: (files: File[]) => void;
acceptedFileTypes?: string;
};
// Compact File Input Component
export const CompactFileInput: React.FC<FileInputProps> = ({ multiple = false, maxSizeMB = 1, onChange, acceptedFileTypes = 'image/*' }) => {
const [images, setImages] = useState<ImageFile[]>([]);
const [error, setError] = useState<string | null>(null);
const fileInputRef = React.useRef<HTMLInputElement>(null);
const maxSizeBytes = maxSizeMB * 1024 * 1024; // Convert MB to bytes
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const selectedFiles = Array.from(e.target.files || []);
console.log(selectedFiles);
// Reset error
setError(null);
// Validate file size
const oversizedFiles = selectedFiles.filter((file) => file.size > maxSizeBytes);
if (oversizedFiles.length > 0) {
setError(`File(s) exceed the ${maxSizeMB}MB limit`);
return;
}
// Handle single file mode
if (!multiple && selectedFiles.length > 0) {
// Remove previous image and URL
images.forEach((img) => URL.revokeObjectURL(img.preview));
const file = selectedFiles[0];
const newImage = {
id: Math.random().toString(36).substr(2, 9),
file,
preview: URL.createObjectURL(file),
};
setImages([newImage]);
onChange?.([file]);
return;
}
// Handle multiple files
const newImages = selectedFiles.map((file) => ({
id: Math.random().toString(36).substr(2, 9),
file,
preview: URL.createObjectURL(file),
}));
setImages((prev) => [...prev, ...newImages]);
onChange?.(selectedFiles);
};
const removeImage = (id: string) => {
setImages((prev) => {
const updatedImages = prev.filter((img) => {
if (img.id === id) {
URL.revokeObjectURL(img.preview);
return false;
}
return true;
});
// Notify parent component
onChange?.(updatedImages.map((img) => img.file));
return updatedImages;
});
};
const handleBrowseClick = () => {
fileInputRef.current?.click();
};
return (
<div className="compact-file-input">
<div className="input-container flex items-center gap-2 rounded border border-gray-300 p-2">
<button type="button" onClick={handleBrowseClick} className="rounded bg-blue-500 px-3 py-1 text-sm text-white hover:bg-blue-600">
Browse
</button>
<span className="text-sm text-gray-500">{multiple ? 'Choose images' : 'Choose an image'}</span>
<input ref={fileInputRef} type="file" accept={acceptedFileTypes} multiple={multiple} onChange={handleFileChange} className="hidden" />
</div>
{error && <div className="mt-1 text-xs text-red-500">{error}</div>}
{images.length > 0 && (
<div className="image-previews mt-2 flex flex-wrap gap-2">
{images.map((img) => (
<div key={img.id} className="preview-container relative h-16 w-16 overflow-hidden rounded border">
<img src={img.preview} alt="Preview" className="h-full w-full object-cover" />
<button
type="button"
onClick={() => removeImage(img.id)}
className="absolute top-0 right-0 flex h-5 w-5 items-center justify-center rounded-full bg-red-500 text-xs text-white"
>
×
</button>
</div>
))}
</div>
)}
</div>
);
};
File: js\components\ui\textarea.tsx reactjs\resources\js\components\ui\textarea.tsx
//reactjs\resources\js\components\ui\textarea.tsx
import * as React from "react"
import { cn } from "@/lib/utils"
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
return (
<textarea
data-slot="textarea"
className={cn(
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
)}
{...props}
/>
)
}
export { Textarea }
File: js\lib\utils.ts reactjs\resources\js\lib\utils.ts
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
File: js\types\products.ts reactjs\resources\js\types\products.ts
export interface ProductItem {
id: number;
name: string;
slug: string;
price: number;
description: string;
images: string | null;
}
//routes/web.php
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use App\Http\Controllers\ProductController;
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('/dashboard/products/create', [ProductController::class, 'create'])->name('dashboard.products.create');
Route::post('/dashboard/products', [ProductController::class, 'store'])->name('dashboard.products.store');
});
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
Tuesday, August 5, 2025
React + Vite How to Create Portfolios No coding using Lovable AI
React + Vite How to Create Portfolios No coding using Lovable AI
Create react project
Run the following command in your terminal: vite dev/guide/
npm create vite@latest
Update to latest tailwindcss
npm install tailwindcss@latest
Create react project
Run the following command in your terminal: vite dev/guide/
npm create vite@latest
Update to latest tailwindcss
npm install tailwindcss@latest
Sunday, August 3, 2025
React Vite How to Setup Path Aliases | from @/components/Navigation
React Vite How to Setup Path Aliases |
from @/components/Navigation
Create react project
Run the following command in your terminal: vite dev/guide/
npm create vite@latest
Install react-router-dom
my-app\src\App.tsx my-app\src\App.tsx
my-app\vite.config.ts
my-app\tsconfig.json
myapp\my-app> npm run dev
Create react project
Run the following command in your terminal: vite dev/guide/
npm create vite@latest
Install react-router-dom
my-app\src\App.tsx my-app\src\App.tsx
//src\App.tsx
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Index from "./pages/Index";
import NotFound from "./pages/NotFound";
const App = () => (
<BrowserRouter>
<Routes>
<Route path="/" element={<Index />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
export default App;
my-app\src\pages\Index.tsx
//pages\Index.tsx
import { Navigation } from "@/components/Navigation";
const Index = () => {
return (
<div className="min-h-screen">
<Navigation />
<main>
<div id="home">
Heror
</div>
<h1>About</h1>
<h1>Skills</h1>
<h1>Projects</h1>
<h1>Contact</h1>
</main>
Footer
</div>
);
};
export default NotFound;
my-app\src\pages\NotFound.tsx
//pages\NotFound.tsx
import { useLocation } from "react-router-dom";
import { useEffect } from "react";
const NotFound = () => {
const location = useLocation();
useEffect(() => {
console.error(
"404 Error: User attempted to access non-existent route:",
location.pathname
);
}, [location.pathname]);
return (
<div className="min-h-screen flex items-center justify-center bg-gray-100">
<div className="text-center">
<h1 className="text-4xl font-bold mb-4">404</h1>
<p className="text-xl text-gray-600 mb-4">Oops! Page not found</p>
<a href="/" className="text-blue-500 hover:text-blue-700 underline">
Return to Home
</a>
</div>
</div>
);
};
export default Navigation;
my-app\src\pages\Navigation.tsx
//pages\Navigation.tsx
import { useState, useEffect } from "react";
import logo from "@/assets/react.svg";
const navLinks = [
{ label: "Home", href: "#home" },
{ label: "About", href: "#about" },
{ label: "Skills", href: "#skills" },
{ label: "Portfolios", href: "#portfolios" },
{ label: "Contact", href: "#contact" },
];
export function Navigation() {
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 50);
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
const scrollToSection = (href: string) => {
console.log(`Navigating to ${href}`);
};
return (
<nav className={`fixed top-0 left-0 right-0 z-50 transition-smooth ${
scrolled ? "bg-background/90 backdrop-blur-md shadow-card" : "bg-transparent"
}`}>
<div className="container mx-auto max-w-6xl px-4">
<div className="flex items-center justify-between h-16">
{/* Logo */}
<div className="text-2xl font-bold">
<img
src={logo}
alt="logo"
className="h-[50px]"
/>
</div>
{/* Desktop Navigation */}
<div className="hidden md:flex items-center space-x-8">
{navLinks.map((link) => (
<button
key={link.label}
onClick={() => scrollToSection(link.href)}
className="text-muted-foreground hover:text-primary transition-smooth font-medium"
>
{link.label}
</button>
))}
<button>
Hire Me
</button>
</div>
</div>
</div>
</nav>
);
}
Update vite.config.ts my-app\vite.config.ts
//vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@/components': '/src/components',
'@/assets': '/src/assets',
'@/lib': '/src/lib',
},
},
});
Update tsconfig.json my-app\tsconfig.json
//tsconfig.json
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@components/*": ["src/components/*"],
"@assets/*": ["src/assets/*"],
"@lib/*": ["src/lib/*"]
}
}
}
Run myapp\my-app> npm run dev
Monday, July 28, 2025
python tkinter chatbot google API Gemini
python tkinter chatbot google API Gemini
chatbot.py
import tkinter as tk
from tkinter import scrolledtext, Entry, Button
import google.generativeai as genai
class SimpleChatbot:
def __init__(self, root):
self.root = root
self.root.geometry("700x480") #Initial size and position
self.root.title("Generative AI Chatbot")
# Configure the Generative AI API with your API key
genai.configure(api_key='AIzaSyA8ZbJrTvnMnnDOlN3HDT3cnwsZ906321654654WhQY') # Replace with your actual API key
# Create a model instance (adjust parameters as per documentation)
self.model = genai.GenerativeModel(model_name="gemini-2.0-flash") # Example model name
# Create a scrolled text area for displaying the conversation
self.conversation_area = scrolledtext.ScrolledText(root, wrap=tk.WORD, width=90, height=30)
self.conversation_area.grid(column=0, row=0, padx=10, pady=10, columnspan=2)
self.conversation_area.insert(tk.INSERT, "Chatbot: Hello! How can I help you today?\n")
# Create an entry widget for the user to type their message
self.user_input = Entry(root, width=60)
self.user_input.grid(column=0, row=1, padx=10, pady=10)
# Create a button to send the message
self.send_button = Button(root, text="Send", command=self.send_message)
self.send_button.grid(column=1, row=1, padx=10, pady=10)
def send_message(self):
user_message = self.user_input.get()
self.conversation_area.insert(tk.INSERT, f"You: {user_message}\n")
self.user_input.delete(0, tk.END)
# Call the Generative AI API to get a response
response = self.model.generate_content(user_message) # Hypothetical method
bot_response = f"Chatbot: {response.text}\n"
self.conversation_area.insert(tk.INSERT, bot_response)
if __name__ == "__main__":
root = tk.Tk()
chatbot = SimpleChatbot(root)
root.mainloop()
Wednesday, June 4, 2025
Laravel 12 Simple Inertia React Pagination Components | React Starter Kit
Laravel 12 Simple Inertia React Pagination Components | React Starter Kit
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
php artisan make:controller UsersController change it with the following codes:
app\Http\Controllers\UsersController.php
Add sidebar menu product mainNavItems from reactjs\rescourses\js\components\app-sidebar.tsx
File: pages\users\index.tsx
reactjs\resources\js\pages\users\index.tsx
reactjs\resources\js\components\Pagination.tsx
User::factory()->count(1000)->create()
Routes
routes/web.php
Starting Laravel development server: http://127.0.0.1:8000
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
php artisan make:controller UsersController change it with the following codes:
app\Http\Controllers\UsersController.php
//app\Http\Controllers\UsersController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Inertia\Inertia;
use App\Models\User;
class UsersController extends Controller
{
public function home()
{
$query = User::select('id', 'name', 'email', 'created_at')->latest();
// Handle search
if (request()->has('search')) {
$search = request('search');
$query->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('email', 'like', "%{$search}%");
});
}
$users = $query->paginate(10);
return Inertia::render('users/index', [
'users' => $users,
'filters' => [
'search' => request('search', ''),
]
]);
}
}
Frontend with React and InertiaJS Add sidebar menu product mainNavItems from reactjs\rescourses\js\components\app-sidebar.tsx
File: pages\users\index.tsx
reactjs\resources\js\pages\users\index.tsx
//reactjs\resources\js\pages\users\index.tsx
import AppLayout from '@/layouts/app-layout';
import { type BreadcrumbItem } from '@/types';
import { Head, router } from '@inertiajs/react';
import { Search } from 'lucide-react';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import Pagination from '@/components/Pagination';
import { useState } from 'react';
interface User {
id: number;
name: string;
email: string;
created_at: string;
}
interface Props {
users: {
data: User[];
current_page: number;
last_page: number;
per_page: number;
total: number;
from: number;
to: number;
};
filters: {
search: string;
filter: string;
};
}
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Laravel 12 Simple Inertia React Pagination Components | React Starter Kit',
href: '/admin/users',
},
];
export default function UsersIndex({ users, filters }: Props) {
//console.log(users);
const [searchTerm, setSearchTerm] = useState(filters.search);
const handleSearch = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
router.get(route('users.home'), {
search: searchTerm,
}, {
preserveState: true,
preserveScroll: true,
});
};
return (
<AppLayout breadcrumbs={breadcrumbs}>
<Head title="Users" />
<div className="flex h-full flex-1 flex-col gap-6 rounded-xl p-6 bg-gradient-to-br from-background to-muted/20">
<div className="flex gap-4 mb-4">
<form onSubmit={handleSearch} className="relative flex-1">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input placeholder="Search name or email..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10 bg-gray-200 text-black"
/>
</form>
</div>
<div className="rounded-md border">
<div className="relative w-full overflow-auto">
<table className="w-full caption-bottom text-sm bg-white rounded-lg">
<thead>
<tr className="bg-gray-200 text-black">
<th className="py-2 px-4 text-left border-b">ID</th>
<th className="py-2 px-4 text-left border-b">Name</th>
<th className="py-2 px-4 text-left border-b">Email</th>
<th className="py-2 px-4 text-left border-b">Created At</th>
<th className="py-2 px-4 text-right border-b">Actions</th>
</tr>
</thead>
<tbody>
{users.data.map((user) => (
<tr key={user.id} className="hover:bg-gray-50 text-black">
<td className="p-4 align-middle font-medium border-b">{user.id}</td>
<td className="p-4 align-middle font-medium border-b">{user.name}</td>
<td className="p-4 align-middle font-medium border-b">{user.email}</td>
<td className="p-4 align-middle font-medium border-b">{new Date(user.created_at).toLocaleDateString()}</td>
<td className="p-4 align-middle text-right border-b">
<div className="flex justify-end gap-2">
<Button variant="ghost"
className="w-full sm:w-auto bg-blue-600 text-white rounded-lg px-4 py-2 hover:bg-blue-700"
>
Edit
</Button>
<Button variant="ghost"
className="w-full sm:w-auto bg-red-600 text-white rounded-lg px-4 py-2 hover:bg-red-700 transition transition ml-2"
>
Delete
</Button>
</div>
</td>
</tr>
))}
{users.total === 0 && (
<tr>
<td colSpan={6} className="p-4 text-center text-muted-foreground">
No users Found
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
{/* Pagination */}
<div className="flex items-center justify-between px-2">
<div className="text-sm text-muted-foreground">
Showing {users.from} to {users.to} of {users.total} results
</div>
<div className="flex items-center space-x-2">
<Pagination links={users.links}/>
</div>
</div>
</div>
</AppLayout>
);
}
File: js\components\Pagination.tsx reactjs\resources\js\components\Pagination.tsx
//reactjs\resources\js\components\Pagination.tsx
import { Link } from '@inertiajs/react'
export default function Pagination({ links }) {
console.log(links);
return (
<div className="flex flex-wrap items-center space-x-1 mt-4">
{links.map((link, index) => (
<Link
key={index}
href={link.url ?? '#'}
dangerouslySetInnerHTML={{ __html: link.label}}
className={`text-lg rounded-lg px-4 py-2 border gap-2
${link.active ? 'border-t-blue-600 text-white bg-blue-600' : 'bg-white text-gray-700'}
${!link.url ? 'opacity-50 pointer-events-none' : 'hover:bg-gray-100'}`}
/>
))}
</div>
)
}
php artisan tinker User::factory()->count(1000)->create()
Routes
routes/web.php
//routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use App\Http\Controllers\UsersController;
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/users-pagination-search', [UsersController::class, 'home'])->name('users.home');
});
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
Friday, May 30, 2025
Laravel 12 React Starter kit Schedule Calendar | Fullcalendar CRUD
Laravel 12 React Starter kit Schedule Calendar | Fullcalendar CRUD
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
myapp>php artisan migrate
update Schedule Model
app/models/Schedule.php
php artisan make:controller ScheduleController
change it with the following codes:
app\Http\Controllers\ScheduleController.php
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
routes/web.php
Starting Laravel development server: http://127.0.0.1:8000
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
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
myapp>php artisan migrate
update Schedule Model
app/models/Schedule.php
php artisan make:controller ScheduleController
change it with the following codes:
app\Http\Controllers\ScheduleController.php
php artisan make:controller AuthController
change it with the following codes:
app\Http\Controllers\AuthController.php
routes/web.php
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');
});
Wednesday, May 14, 2025
Laravel 12 React Pagination and Search | React Starter kit
Laravel 12 React Pagination and Search | React Starter kit
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
php artisan make:controller UsersController change it with the following codes:
app\Http\Controllers\UsersController.php
Add sidebar menu product mainNavItems from reactjs\rescourses\js\components\app-sidebar.tsx
File: pages\users\index.tsx
reactjs\resources\js\pages\users\index.tsx
routes/web.php
Starting Laravel development server: http://127.0.0.1:8000
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
php artisan make:controller UsersController change it with the following codes:
app\Http\Controllers\UsersController.php
//app\Http\Controllers\UsersController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Inertia\Inertia;
use App\Models\User;
class UsersController extends Controller
{
public function home()
{
$query = User::select('id', 'name', 'email', 'created_at')->latest();
// Handle search
if (request()->has('search')) {
$search = request('search');
$query->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('email', 'like', "%{$search}%");
});
}
$users = $query->paginate(10);
return Inertia::render('users/index', [
'users' => $users,
'filters' => [
'search' => request('search', ''),
]
]);
}
}
Frontend with React and InertiaJS Add sidebar menu product mainNavItems from reactjs\rescourses\js\components\app-sidebar.tsx
File: pages\users\index.tsx
reactjs\resources\js\pages\users\index.tsx
//reactjs\resources\js\pages\users\index.tsx
import AppLayout from '@/layouts/app-layout';
import { type BreadcrumbItem } from '@/types';
import { Head, router } from '@inertiajs/react';
import { Button } from '@/components/ui/button';
import { Search, ChevronLeft, ChevronRight } from 'lucide-react';
import { Input } from '@/components/ui/input';
import { useState } from 'react';
interface User {
id: number;
name: string;
email: string;
created_at: string;
}
interface Props {
users: {
data: User[];
current_page: number;
last_page: number;
per_page: number;
total: number;
from: number;
to: number;
};
filters: {
search: string;
filter: string;
};
}
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Users',
href: '/admin/users',
},
];
export const generatePaginationnumber = (currentPage, totalPages) => {
if (totalPages <= 7) {
return Array.from({ length: totalPages }, (_, i) => i + 1);
}
if (currentPage <= 3) {
return [1, 2, 3 , "...", totalPages - 1, totalPages];
}
if (currentPage >= totalPages - 3) {
console.log("2");
return [1, 2, 3, "...", totalPages - 2, totalPages - 1, totalPages];
}
return [
1,
"...",
currentPage - 1,
currentPage,
currentPage + 1,
"...",
totalPages,
];
};
export default function UsersIndex({ users, filters }: Props) {
//console.log(users);
const params = new URLSearchParams(window.location.search);
const currentPage = Number(params.get("page")) || 1;
//console.log(currentPage);
const totalPages = Math.ceil(Number(users.total) / Number(users.per_page));
//const totalPages = users.total;
console.log(totalPages);
const allPages = generatePaginationnumber(currentPage, totalPages);
const [searchTerm, setSearchTerm] = useState(filters.search);
const handleSearch = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
router.get(route('users.home'), {
search: searchTerm,
}, {
preserveState: true,
preserveScroll: true,
});
};
const handlePageChange = (page: number) => {
router.get(route('users.home'), {
page,
}, {
preserveState: true,
preserveScroll: true,
});
};
return (
<AppLayout breadcrumbs={breadcrumbs}>
<Head title="Users" />
<div className="flex h-full flex-1 flex-col gap-6 rounded-xl p-6 bg-gradient-to-br from-background to-muted/20">
<div className="flex gap-4 mb-4">
<form onSubmit={handleSearch} className="relative flex-1">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input placeholder="Search name or email..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10 bg-gray-200 text-black"
/>
</form>
</div>
<div className="rounded-md border">
<div className="relative w-full overflow-auto">
<table className="w-full caption-bottom text-sm bg-white rounded-lg">
<thead>
<tr className="bg-gray-200 text-black">
<th className="py-2 px-4 text-left border-b">ID</th>
<th className="py-2 px-4 text-left border-b">Name</th>
<th className="py-2 px-4 text-left border-b">Email</th>
<th className="py-2 px-4 text-left border-b">Created At</th>
<th className="py-2 px-4 text-right border-b">Actions</th>
</tr>
</thead>
<tbody>
{users.data.map((user) => (
<tr key={user.id} className="hover:bg-gray-50 text-black">
<td className="p-4 align-middle font-medium border-b">{user.id}</td>
<td className="p-4 align-middle font-medium border-b">{user.name}</td>
<td className="p-4 align-middle font-medium border-b">{user.email}</td>
<td className="p-4 align-middle font-medium border-b">{new Date(user.created_at).toLocaleDateString()}</td>
<td className="p-4 align-middle text-right border-b">
<div className="flex justify-end gap-2">
<Button variant="ghost"
className="w-full sm:w-auto bg-blue-600 text-white rounded-lg px-4 py-2 hover:bg-blue-700"
>
Edit
</Button>
<Button variant="ghost"
className="w-full sm:w-auto bg-red-600 text-white rounded-lg px-4 py-2 hover:bg-red-700 transition transition ml-2"
>
Delete
</Button>
</div>
</td>
</tr>
))}
{users.total === 0 && (
<tr>
<td colSpan={6} className="p-4 text-center text-muted-foreground">
No users Found
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
{/* Pagination */}
<div className="flex items-center justify-between px-2">
<div className="text-sm text-muted-foreground">
Showing {users.from} to {users.to} of {users.total} results
</div>
<div className="flex items-center space-x-2">
<Button variant="outline"
size="icon"
onClick={() => handlePageChange(users.current_page - 1)}
disabled={users.current_page === 1}
>
<ChevronLeft className="h-4 w-4" />
</Button>
<div className="flex items-center space-x-1">
{allPages.map((page, index) => (
<Button key={index}
variant={page === users.current_page ? "default" : "outline"}
size="icon"
onClick={() => handlePageChange(page)}
>
{page}
</Button>
))}
</div>
<Button variant="outline"
size="icon"
onClick={() => handlePageChange(users.current_page + 1)}
disabled={users.current_page === users.last_page}
>
<ChevronRight className="h-4 w-4" />
</Button>
</div>
</div>
</div>
</AppLayout>
);
}
Routes routes/web.php
//routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use App\Http\Controllers\UsersController;
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/users-pagination-search', [UsersController::class, 'home'])->name('users.home');
});
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
Sunday, May 11, 2025
Laravel 12 CRUD Image Upload, Search, Soft Deletes Bootstrap and Vite
Laravel 12 CRUD Image Upload, Search, Soft Deletes Bootstrap and Vite e
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 Product Model php artisan make:model Product -m myapp>php artisan make:model Product -m Open new Products migrations yourproject/database/migrations laravelproject\database\migrations\_create_products_table.php
myapp>php artisan migrate
update Product Model
app/models/Product.php
php artisan make:controller PostController
change it with the following codes:
app\Http\Controllers\PostController.php
php artisan make:controller AuthController
change it with the following codes:
app\Http\Controllers\AuthController.php
routes/web.php
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 Product Model php artisan make:model Product -m myapp>php artisan make:model Product -m Open new Products migrations yourproject/database/migrations laravelproject\database\migrations\_create_products_table.php
//laravelproject\database\migrations\_create_products_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('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('description')->nullable();
$table->integer('quantity');
$table->float('price');
$table->string('image')->nullable();
$table->enum('status', ['active', 'in-active'])->default('active');
$table->softDeletes();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};
run myapp>php artisan migrate
update Product Model
app/models/Product.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
class Product extends Model
{
use SoftDeletes, HasFactory;
protected $fillable = [
"name",
"description",
"quantity",
"price",
"status",
"image",
];
}
Create PostController php artisan make:controller PostController
change it with the following codes:
app\Http\Controllers\PostController.php
//app\Http\Controllers\ProductController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Product;
use Illuminate\Support\Facades\Storage;
class ProductController extends Controller
{
public function index(Request $request)
{
// $products = Product::all();
$query = Product::query();
if (request()->has("search") && $request->search) {
$query = $query->where("name", "like", "%" . $request->search . "%")
->orWhere('description', 'like', "%" . $request->search . "%");
}
$products = $query->latest()->paginate(3);
return view("product.index", compact("products"));
}
public function create()
{
return view("product.create");
}
public function store(Request $request)
{
$validated = $request->validate([
"name" => "required|string",
"description" => "nullable|string",
"price" => "required|numeric",
"quantity" => "required|numeric",
"status" => "required",
"image" => "nullable|image|mimes:jpg,png",
]);
if ($request->hasFile("image")) { //php artisan storage:link
$validated["image"] = $request->file("image")->store("products", "public");
}
Product::create($validated);
return redirect()->route("products.index")->with("success", "product added successfully");
}
public function show($id)
{
$product = Product::find($id);
return view("product.show", compact("product"));
}
public function edit($id)
{
$product = Product::find($id);
return view("product.edit", compact("product"));
}
public function update(Request $request, $id)
{
$validated = $request->validate([
"name" => "required|string",
"description" => "nullable|string",
"price" => "required|numeric",
"quantity" => "required|numeric",
"status" => "required",
"image" => "nullable|image|mimes:jpg,png",
]);
if ($request->hasFile("image")) {
if ($request->image && Storage::disk("public")->exists($request->image)) {
Storage::disk("public")->delete($request->image);
}
$validated["image"] = $request->file("image")->store("products", "public");
}
Product::find($id)->update($validated);
return redirect()->route("products.index")->with("success", "product updated successfully!");
}
public function destroy($id)
{
Product::find($id)->delete();
return redirect()->route("products.index")->with("success", "product deleted successfully!");
}
public function trashedProducts(Request $request)
{
$query = Product::query()->onlyTrashed();
$products = $query->paginate(3);
return view("product.deleted-products", compact("products"));
}
public function showTrashed($id)
{
$product = Product::onlyTrashed()->findOrFail($id);
return view("product.show", compact("product"));
}
public function restoreProduct($id)
{
$product = Product::onlyTrashed()->findOrFail($id);
$product->restore();
return redirect()->route("products.index")->with("success", "product restored successfully");
}
public function destroyProduct($id)
{
$product = Product::onlyTrashed()->findOrFail($id);
if ($product->image && Storage::exists($product->image)) {
Storage::delete($product->image);
}
$product->forceDelete();
return redirect()->route("products.index")->with("success", "product was force deleted successfully!");
}
}
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 lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel 12 CRUD</title>
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
</head>
<body>
<nav class="py-2 bg-body-tertiary border-bottom">
<div class="container d-flex flex-wrap">
<ul class="nav me-auto">
<li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2 active" aria-current="page">Home</a></li>
<li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">Features</a></li>
<li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">Pricing</a></li>
<li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">FAQs</a></li>
<li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">About</a></li>
</ul>
<ul class="nav">
<li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">Login</a></li>
<li class="nav-item"><a href="#" class="nav-link link-body-emphasis px-2">Sign up</a></li>
</ul>
</div>
</nav>
<header class="py-3 mb-4 border-bottom">
<div class="container d-flex flex-wrap justify-content-center"> <a href="/" class="d-flex align-items-center mb-3 mb-lg-0 me-lg-auto link-body-emphasis text-decoration-none">
<svg class="bi me-2" width="40" height="32" aria-hidden="true">
<use xlink:href="#bootstrap"></use>
</svg> <span class="fs-4">Cairocoders</span> </a>
</div>
</header>
@yield('content')
</body>
</html>
Home
resources/views/product/index.blade.php
//resources/views/product/index.blade.php
@extends('layouts.layout')
@section('content')
<div class="container">
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h2>Product List</h2>
</div>
<div class="col">
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="col">
<div><a href="{{ route('products.trashed')}}" class="float-end btn btn-danger" style="margin-left:10px;">Deleted</a></div>
<div><a href="{{ route('products.create')}}" class="float-end btn btn-primary">Add New</a></div>
</div>
</div>
</div>
<div class="col-md-12" style="padding-top:20px;">
<form class="d-flex" role="search" action="{{ route('products.index')}}" method="GET">
@csrf
<input class="form-control me-2" name="search" type="search" placeholder="Search"
aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</div>
</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-body">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Photo</th>
<th scope="col">Product Name</th>
<th scope="col">Quantity</th>
<th scope="col">Price</th>
<th scope="col">Status</th>
<th scope="col">Description</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
@if (count($products) > 0)
@foreach ($products as $product)
<tr>
<th scope="row">{{ $loop->iteration }}</th>
<td><img src="{{ asset('storage/' . $product->image) }}" width="100"></td>
<td>{{ str($product->name)->words(2)}}</td>
<td>{{ $product->quantity}}</td>
<td>{{ $product->price}}</td>
<td>{{ $product->status}}</td>
<td>{{ str($product->description)->words(5)}}</td>
<td>
<a href="{{ route('products.show', $product->id) }} " class="btn btn-success btn">show</a>
<a href="{{ route('products.edit', $product->id) }} " class="btn btn-primary btn">edit</a>
<form action="{{ route('products.destroy', $product->id) }}" method="POST"
style="display:inline-block">
@csrf @method('DELETE')
<button onclick="return confirm('Are you sure?')"
class="btn btn btn-danger">Delete</button>
</form>
</td>
</tr>
@endforeach
@else
<tr>
<td colspan="8" class="text-center">No Data Found!</td>
</tr>
@endif
</tbody>
</table>
{{ $products->links('pagination::bootstrap-5') }}
</div>
</div>
</div>
@endsection
resources/views/product/create.blade.php
//resources/views/product/create.blade.php
@extends('layouts.layout')
@section('content')
<div class="container">
<div class="card">
<div class="card-header">
Add New Product
</div>
<div class="card-body">
<form action="{{ route('products.store')}}" method="post" enctype="multipart/form-data">
@csrf
@include('product.form')
<button type="submit" class="btn btn-primary">Save</button>
<a href="{{ route('products.index')}}" class="btn btn-secondary">Cancel</a>
</form>
</div>
</div>
</div>
@endsection
resources/views/product/form.blade.php
//resources/views/product/form.blade.php
<div class="mb-3">
<label class="form-label">Product Name *</label>
<input type="text" name="name" class="form-control" value="{{ old('name', $product->name ?? '') }}">
@error('name')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="mb-3">
<label class="form-label">Description</label>
<textarea name="description" class="form-control">{{ old('description', $product->description ?? '') }}</textarea>
@error('description')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="mb-3">
<label class="form-label">Price *</label>
<input type="number" name="price" step="0.01" class="form-control"
value="{{ old('price', $product->price ?? '') }}">
@error('price')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="mb-3">
<label class="form-label">Quantity *</label>
<input type="number" name="quantity" class="form-control" value="{{ old('quantity', $product->quantity ?? '') }}">
@error('quantity')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="mb-3">
<label class="form-label">Status *</label>
<select name="status" class="form-select">
<option value="active" {{ (old('status', $product->status ?? '') == 'active') ? 'selected' : '' }}>Active</option>
<option value="in-active" {{ (old('status', $product->status ?? '') == 'in-active') ? 'selected' : '' }}>Inactive
</option>
</select>
@error('status')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="mb-3">
<label class="form-label">Product Image</label>
<input type="file" name="image" class="form-control">
@error('image')
<span class="text-danger">{{ $message }}</span>
@enderror
@if (!empty($product->image))
<img src="{{ asset('storage/' . $product->image) }}" class="mt-2" width="300">
@endif
</div>
resources/views/product/edit.blade.php
//resources/views/product/edit.blade.php
@extends('layouts.layout')
@section('content')
<div class="container">
<div class="card">
<div class="card-header">
Edit Product
</div>
<div class="card-body">
<form action="{{ route('products.update', $product->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
@include('product.form')
<button type="submit" class="btn btn-primary">Update</button>
<a href="{{ route('products.index')}}" class="btn btn-secondary">Cancel</a>
</form>
</div>
</div>
</div>
@endsection
resources/views/product/show.blade.php
//resources/views/product/show.blade.php
@extends('layouts.layout')
@section('content')
<div class="container">
<h2>Product Details</h2>
<div class="card">
<div class="card-body">
@if($product->image)
<img src="{{ asset('storage/' . $product->image) }}" width="250" class="mb-3">
@endif
<p><strong>Name:</strong> {{ $product->name }}</p>
<p><strong>Description:</strong> {{ $product->description }}</p>
<p><strong>Price:</strong> ${{ number_format($product->price, 2) }}</p>
<p><strong>Quantity:</strong> {{ $product->quantity }}</p>
<p><strong>Status:</strong>
<span class="badge bg-{{ $product->status === 'active' ? 'success' : 'secondary' }}">
{{ ucfirst($product->status) }}
</span>
</p>
<a href="{{ route('products.edit', $product->id) }}" class="btn btn-warning">Edit</a>
<a href="{{ route('products.index') }}" class="btn btn-secondary">Back</a>
</div>
</div>
</div>
@endsection
resources/views/product/deleted-products.blade.php
//resources/views/product/deleted-products.blade.php
@extends('layouts.layout')
@section('content')
<div class="container">
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h2>Product List</h2>
</div>
<div class="col">
<div class="row">
<div class="col-md-12">
<a href="{{ route('products.index')}}" class="float-end btn btn-warning">View All
Products</a>
</div>
<div class="col-md-12" style="padding-top:20px;">
<form class="d-flex" role="search" action="{{ route('products.trashed')}}" method="GET">
@csrf
<input class="form-control me-2" name="search" type="search" placeholder="Search"
aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</div>
</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-body">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Photo</th>
<th scope="col">Product Name</th>
<th scope="col">Quantity</th>
<th scope="col">Price</th>
<th scope="col">Status</th>
<th scope="col">Description</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
@if (count($products) > 0)
@foreach ($products as $product)
<tr>
<th scope="row">{{ $loop->iteration }}</th>
<td><img src="{{ asset('storage/' . $product->image) }}" width="100"></td>
<td>{{ $product->name}}</td>
<td>{{ $product->quantity}}</td>
<td>{{ $product->price}}</td>
<td>{{ $product->status}}</td>
<td>{{ $product->description}}</td>
<td>
<a href="{{ route('trashed.show', $product->id) }}" class="btn btn-success btn">show</a>
<form action="{{ route('trashed.restore', $product->id) }}" method="POST"
style="display:inline-block">
@csrf
@method('PUT')
<button onclick="return confirm('Are you sure?')"
class="btn btn btn-info">Restore</button>
</form>
<form action="{{ route('trashed.delete', $product->id) }}" method="POST"
style="display:inline-block">
@csrf
@method('DELETE')
<button onclick="return confirm('Are you sure?')"
class="btn btn btn-danger">Delete</button>
</form>
</td>
</tr>
@endforeach
@else
<tr>
<td colspan="8" class="text-center">No Data Found!</td>
</tr>
@endif
</tbody>
</table>
{{ $products->links() }}
</div>
</div>
</div>
@endsection
resources/views/login.blade.php
//resources/views/login.blade.php
@extends('layouts.layout')
@section('content')
<div class="container">
<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\ProductController;
use App\Http\Controllers\AuthController;
Route::get('/', function () {
return view('welcome');
});
Route::middleware('auth')->group(function () {
//Route::get('dashboard', function () {
// return view('dashboard');
//})->name('dashboard');
Route::controller(ProductController::class)->group(function () {
Route::get('/admin/products', 'index')->name('products.index');
Route::get('/admin/products/create', 'create')->name('products.create');
Route::post('/admin/products', 'store')->name('products.store');
Route::get('/admin/products/show/{product}', 'show')->name('products.show');
Route::get('/admin/products/{product}/edit', 'edit')->name('products.edit');
Route::put('/admin/products/{product}', 'update')->name('products.update');
Route::delete('/admin/products/{product}', 'destroy')->name('products.destroy');
Route::get('/admin/deleted-products', 'trashedProducts')->name('products.trashed');
Route::get('/admin/show-trashed-product/{id}', 'showTrashed')->name('trashed.show');
Route::put('/admin/restore-product/{id}', 'restoreProduct')->name('trashed.restore');
Route::delete('/admin/delete-product/{id}', 'destroyProduct')->name('trashed.delete');
});
});
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');
});
Subscribe to:
Comments (Atom)










