Laravel 13 React Complete Point Of Sale POS using AI opencodeLaravel 13 React Complete Point Of Sale POS using AI opencode
Source Code : https://github___com/cai-ro-coders/Laravel-13-React-Complete-Point-Of-Sale-POS-using-AI-opencode
Download and Install Opencode
Download Laravel App
https://laravel.com/docs/13.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
chatgpt prompt
Build a modern POS system for a retail store with inventory management, sales processing, reporting, and user roles.
Implement role-based access:
Admin
Cashier
Manager
Each role should have proper permissions.
Core Modules & Features
1. Authentication & Authorization
Role-based middleware
2. Dashboard
Sales summary (daily, weekly, monthly)
Top-selling products
Low stock alerts
3. Product Management
CRUD products
Categories & brands
Barcode generation
Product variants (size, color)
Stock tracking
4. Inventory Management
Stock in/out
Supplier management
Purchase orders
Inventory history logs
5. POS Interface (IMPORTANT)
Fast product search (barcode + name)
Add to cart
Quantity adjustment
Discounts & taxes
Real-time total calculation
Multiple payment methods
Print receipt (thermal format)
6. Sales Management
Store transactions
View sales history
Refund/returns handlingv
7. Reports
Sales reports
Inventory reports
Profit/loss
Export to CSV/PDF
8. Settings
Store info
Tax configuration
Receipt customization
Database Design
Generate migrations for:
users
roles & permissions
products
categories
brands
orders
order_items
payments
suppliers
inventory_logs
Include relationships and indexes.
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 28, 2026
Thursday, March 19, 2026
Create Ecommerce website design similar website using Laravel 13 React and Open Code
Create Ecommerce website design similar website using Laravel 13 React and Open Code
Download and Install Opencode
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
Download and Install Opencode
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
Tuesday, March 17, 2026
How to Install Claude Code and Ollama in VSCode and Use Claude Code FREE
How to Install Claude Code and Ollama in VSCode and Use Claude Code FREE
Install Claude Code code.claude. com/docs/en/quickstart = curl -fsSL https://claude.ai/install.sh | bash
Download Ollama and seach model ollama launch claude --model minimax-m2.5:cloud
Install Claude Code code.claude. com/docs/en/quickstart = curl -fsSL https://claude.ai/install.sh | bash
Download Ollama and seach model ollama launch claude --model minimax-m2.5:cloud
Saturday, March 14, 2026
Inventory Management System in Laravel 12 React Starter Kit Using Open Code AI
Inventory Management System in Laravel 12 React Starter Kit Using Open Code AI
opencode prompt
create inventory management system
This will include:
1. Authentication
- Register (Admin only can create stuff)
- Role-based middleware
2. Dashboard
- Total Products
- Total Categories
- Low Stock Products
- Total Suppliers
- Recent Transactions
3. Categories Modulev
- Create Category
- Edit Category
- Delete Category
- List Category
- Slug support
4. Products Module
- Product Name
- SKU (unique)
- Category (relationship)
- Supplier (relationship)
- Purchase Price
- Selling Price
- Stock Quantitiy
- Minimum Stock Alert
- Product Image Upload
- Pagination
- Flash message
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
opencode prompt
create inventory management system
This will include:
1. Authentication
- Register (Admin only can create stuff)
- Role-based middleware
2. Dashboard
- Total Products
- Total Categories
- Low Stock Products
- Total Suppliers
- Recent Transactions
3. Categories Modulev
- Create Category
- Edit Category
- Delete Category
- List Category
- Slug support
4. Products Module
- Product Name
- SKU (unique)
- Category (relationship)
- Supplier (relationship)
- Purchase Price
- Selling Price
- Stock Quantitiy
- Minimum Stock Alert
- Product Image Upload
- Pagination
- Flash message
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
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
Subscribe to:
Comments (Atom)












