article

Thursday, April 18, 2024

Next.js 14 Python Flask Dynamic Select Country State City Mysql | TailwindCSS DaisyUI

Next.js 14 Python Flask Dynamic Select Country State City Mysql | TailwindCSS DaisyUI

https://python-guide-es.readthedocs.io/es/guide-es/dev/virtualenvs.html

Create an environment
ednalan@Cairocoders myapp % pip install virtualenv
ednalan@Cairocoders myapp % pip install virtualenv

Activate the environment
ednalan@Cairocoders myapp % source venv/bin/activate
(venv) ednalan@Cairocoders myapp %

Install Flask
https://pypi.org/project/Flask/
(venv) ednalan@Cairocoders myapp % pip install -U Flask
(venv) ednalan@Cairocoders myapp % flask run

Install requirements
pip install -U flask-cors
https://pypi.org/project/Flask-Cors/

Flask-SQLAlchemy
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy to your application.
https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/

(venv) PS C:\flask_dev\myapp>pip install -U Flask-SQLAlchemy

python3 -m pip install
https://pypi.org/project/pymysql/
app.py
//app.py
from flask import Flask, jsonify
from flask_cors import CORS #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors
from flask_marshmallow import Marshmallow #ModuleNotFoundError: No module named 'flask_marshmallow' = pip install flask-marshmallow https://pypi.org/project/flask-marshmallow/
   
from models import db, Countries, State, City
   
app = Flask(__name__)
CORS(app, supports_credentials=True)
   
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flaskdb.db'
# Databse configuration mysql                             Username:password@hostname/databasename
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:root@localhost:8889/nextjsdb'
   
db.init_app(app)
     
with app.app_context():
    db.create_all()
   
ma=Marshmallow(app)
    
class CountriesSchema(ma.Schema):
    class Meta:
        fields = ('ID','countryName')
 
class StateSchema(ma.Schema):
    class Meta:
        fields = ('id','name','country_id')
 
class CitySchema(ma.Schema):
    class Meta:
        fields = ('id','name','stateid')
 
countries_schema = CountriesSchema(many=True)
state_schema = StateSchema(many=True)
city_schema = CitySchema(many=True)
 
@app.route("/")
def hello_world():
    return "Hello, World!"
   
@app.route('/listall',methods =['GET'])
def listall():
    all_countries = Countries.query.all()
    results = countries_schema.dump(all_countries)
    return jsonify(results)
 
@app.route('/state/<get_state>',methods =['GET'])
def statebycountry(get_state):
    state = State.query.filter_by(country_id=get_state).all()
    results = state_schema.dump(state)
    return jsonify(results)
 
@app.route('/city/<get_city>',methods =['GET'])
def city(get_city):
    city_data = City.query.filter_by(stateid=get_city).all()
    results = city_schema.dump(city_data)
    return jsonify(results)

if __name__ == "__main__":
    app.run(debug=True)
models.py
//models.py
from flask_sqlalchemy import SQLAlchemy
      
db = SQLAlchemy()
      
class Countries(db.Model):
    __tablename__ = "countries"
    ID = db.Column(db.Integer, primary_key=True)
    countryName = db.Column(db.String(120), index=True, unique=True)
 
class State(db.Model):
    __tablename__ = "state"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(120), index=True, unique=True)
    country_id = db.Column(db.Integer)
 
class City(db.Model):
    __tablename__ = "city"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(120), index=True, unique=True)
    stateid = db.Column(db.Integer)
Country State and City : https://github.com/cairocodes/cairocoders/blob/main/country-state-city.sql

run (venv) C:\flask_dev\myapp>flask run

Next.js
Install requirements
npm install axios
https://www.npmjs.com/package/axios

app\page.tsx
//app\page.tsx
import Form from "@/components/form";

export default function Home() {
  return (
    <div className="w-screen py-20 flex justify-center flex-col items-center">
      <div className="flex items-center justify-between gap-1 mb-5">
        <h1 className="text-4xl font-bold">Next.js 14 Python Flask Dynamic Select Country State City Mysql | TailwindCSS DaisyUI</h1>
      </div>    
      <div className="overflow-x-auto">
          <Form/>
      </div>  
    </div>
  );
}
components\form.tsx
//components\form.tsx
"use client";
 
import React, { useEffect, useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios

export default function Form() {

    const [country, setCountry]= useState([]);
    const [countryid, setCountryid]= useState('0');
    const [stateid, setStateid]= useState('0');
    const [state, setState]= useState([]);
    const [city, setCity]= useState([]);

    useEffect(() => {
        const fetchCountry = async () => {
            axios.get('http://127.0.0.1:5000/listall')
            .then(function (response) {
                //handle success
                console.log(response)
                setCountry(response.data)
            })
            .catch(function (response) {
                //handle error
                console.log(response)
            });
        }
        fetchCountry()
    }, [])

    const handlecountry=(event)=>{
        const getcoutryid= event.target.value;
        console.log(getcoutryid);
        setCountryid(getcoutryid);
        event.preventDefault();
    }  
    
    const handlestate=(event)=>{
        const stateid= event.target.value;
        console.log(stateid);
        setStateid(stateid);
        event.preventDefault();
    }

    useEffect( ()=>{
        const getstate= async ()=>{  
            axios.get(`http://127.0.0.1:5000/state/${countryid }`)
            .then(function (response) {
                //handle success
                //console.log(response)
                setState(response.data)
            })
            .catch(function (response) {
                //handle error
                console.log(response)
            });
        }
        getstate();
    },[countryid]);

    useEffect( ()=>{
        const getcity= async ()=>{
            axios.get(`http://127.0.0.1:5000/city/${stateid }`)
            .then(function (response) {
                //handle success
                //console.log(response)
                setCity(response.data)
            })
            .catch(function (response) {
                //handle error
                console.log(response)
            });
        }
        getcity();
    },[stateid]);

    return (
        <>
        <div className="max-w-xl mx-auto mt-5">
            <div>
            <form>
            <div className="mb-5 pr-4 pl-4">
                <label className="block text-sm font-medium text-gray-900">
                    Country
                </label>
                <select onChange={(e)=>handlecountry(e)} name="country" className="select select-info w-full max-w-xs">
                    <option defaultValue={'DEFAULT'}>--Select Country--</option>
                    {
                     country.map( (getcon)=>(
                        <option key={getcon.ID} value={getcon.ID }> { getcon.countryName}</option>
                     ))
                    }
                </select>
            </div>
            <div className="mb-5 pr-4 pl-4">
                <label className="block text-sm font-medium text-gray-900">
                    State
                </label>
                <select onChange={(e)=>handlestate(e)} name="state" className="select select-success w-full max-w-xs">
                   <option defaultValue={'DEFAULT'}>--Select State--</option>
                   {
                     state.map( (st,index)=>(                    
                        <option key={index} value={st.id}>{ st.name}</option>
                     ))
                     }
                 </select>
            </div>
            <div className="mb-5 pr-4 pl-4">
                <label className="block text-sm font-medium text-gray-900">
                    City
                </label>
                <select name="city" className="select select-warning w-full max-w-xs">
                   <option>--Select City--</option>                  
                    {
                     city.map( (st,index)=>(                    
                        <option key={index} value={st.id}>{ st.name}</option>
                     ))
                    }
                 </select>
            </div>
        </form>
        </div>
        </div>
        
        </>
  );
}
run C:\nextjs>npm run dev

Monday, April 15, 2024

Next.js 14 Laravel 11 CRUD with Upload and Pagination (Create, Read, Update and Delete) Mysql | TailwindCSS DaisyUI

Next.js 14 Laravel 11 CRUD with Upload and Pagination (Create, Read, Update and Delete) Mysql | TailwindCSS DaisyUI

Download Laravel App

https://laravel.com/docs/11.x/installation

Connecting our Database

open .env file root directory.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=8889
DB_DATABASE=laravel11dev
DB_USERNAME=root
DB_PASSWORD=root

Create Model and Migration

C:\xampp\htdocs\laravel\laravelproject>php artisan make:model Product -m

A new file named Product.php will be created in the app directory and database/migrations directory to generate the table in our database
app/Models/Product.php
//app/Models/Product.php
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
 
class Product extends Model
{
    use HasFactory;
 
    protected $fillable = [
        'name', 
        'image', 
        'price'
    ];
}
database\migrations\create_products_table.php
//database\migrations\create_products_table.ph
<?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('image');
            $table->integer('price');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('products');
    }
};
Database Migration
php artisan migrate

C:\xampp\htdocs\laravel\laravel10project>php artisan migrate
Migration table created successfully.
check database table
Create Controller and Request
C:\xampp\htdocs\laravel\laravel10project>php artisan make:controller ProductController

app\Http\Controllers\ProductController.php
//app\Http\Controllers\ProductController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Models\Product;
use App\Http\Requests\ProductStoreRequest;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage; //php artisan storage:link = php artisan storage:link = http://127.0.0.1:8000/storage/1.jpg

class ProductController extends Controller
{
    public function index()
    {
        //$products = Product::all(); // All Product

        $products = Product::paginate(5);

        // Return Json Response
        return response()->json([
            'products' => $products
        ], 200);
    }

    public function store(ProductStoreRequest $request)
    {
        try {

            $name = $request->name;
            $price = $request->price;
            $imageName = Str::random(32) . "." . $request->image->getClientOriginalExtension();
            
            Storage::disk('public')->put($imageName, file_get_contents($request->image));

            Product::create([
                'name' => $name,
                'image' => $imageName,
                'price' => $price
            ]);

            // Return Json Response
            return response()->json([
                'results' => "Product successfully created. '$name' -- '$imageName' -- '$price' "
            ], 200);
        } catch (\Exception $e) {
            // Return Json Response
            return response()->json([
                'message' => "Something went really wrong!"
            ], 500);
        }
    }

    public function show($id)
    {
        // Product Detail 
        $product = Product::find($id);
        if (!$product) {
            return response()->json([
                'message' => 'Product Not Found.'
            ], 404);
        }

        // Return Json Response
        return response()->json([
            'product' => $product
        ], 200);
    }

    public function update(ProductStoreRequest $request, $id)
    {
        try {
            // Find product
            $product = Product::find($id);
            if (!$product) {
                return response()->json([
                    'message' => 'Product Not Found.'
                ], 404);
            }

            echo "request : $request->image";
            $product->name = $request->name;
            $product->price = $request->price;

            if ($request->image) {

                // Public storage
                $storage = Storage::disk('public');

                // Old iamge delete
                if ($storage->exists($product->image))
                    $storage->delete($product->image);

                // Image name
                $imageName = Str::random(32) . "." . $request->image->getClientOriginalExtension();
                $product->image = $imageName;

                // Image save in public folder
                $storage->put($imageName, file_get_contents($request->image));
            }

            // Update Product
            $product->save();

            // Return Json Response
            return response()->json([
                'message' => "Product successfully updated."
            ], 200);
        } catch (\Exception $e) {
            // Return Json Response
            return response()->json([
                'message' => "Something went really wrong!"
            ], 500);
        }
    }

    public function destroy($id)
    {
        // Detail 
        $product = Product::find($id);
        if (!$product) {
            return response()->json([
                'message' => 'Product Not Found.'
            ], 404);
        }

        // Public storage
        $storage = Storage::disk('public');

        // Iamge delete
        if ($storage->exists($product->image))
            $storage->delete($product->image);

        // Delete Product
        $product->delete();

        // Return Json Response
        return response()->json([
            'message' => "Product successfully deleted."
        ], 200);
    }
}
php artisan make:request ProductStoreRequest
C:\xampp\htdocs\laravel\myapp>php artisan make:request ProductStoreRequest

app\Http\Requests\ProductStoreRequest.php
//app\Http\Requests\ProductStoreRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ProductStoreRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        //return false;
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
     */
    public function rules(): array
    {
        if (request()->isMethod('post')) {
            return [
                'name' => 'required|string|max:258',
                'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
                'price' => 'required|string'
            ];
        } else {
            return [
                'name' => 'required|string|max:258',
                'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
                'price' => 'required|string'
            ];
        }
    }

    public function messages()
    {
        if (request()->isMethod('post')) {
            return [
                'name.required' => 'Name is required!',
                'image.required' => 'Image is required!',
                'price.required' => 'Price'
            ];
        } else {
            return [
                'name.required' => 'Name is required!',
                'price.required' => 'Price is required!'
            ];
        }
    }
}
routes/api.php
//routes/api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;

Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');

Route::get('products', [ProductController::class, 'index']);
Route::post('products', [ProductController::class, 'store']);
Route::get('products/{id}', [ProductController::class, 'show']);
Route::put('productsupdate/{id}', [ProductController::class, 'update']);
Route::delete('productdelete/{id}', [ProductController::class, 'destroy']);
Run C:\xampp\htdocs\laravel\myapp>php artisan serve
Starting Laravel development server: http://127.0.0.1:8000/api/products
generate symbolic links C:\xampp\htdocs\laravel\myapp>php artisan storage:link

Run C:\xampp\htdocs\laravel\myapp>php artisan serve
Starting Laravel development server: http://127.0.0.1:8000

open postman new request

GET api/products Index All products return.
GET : http://127.0.0.1:8000/api/products

GET api/products/{id} Show Detail of a particular post by ID.
GET : http://127.0.0.1:8000/api/products/1

POST api/products Store Create a new product.
POST : http://127.0.0.1:8000/api/products
body
key value
name Iphone 13
image iphone.jpg = file
price 45

PUT api/products/{id} Update Update a particular product by ID.
POST : http://127.0.0.1:8000/api/products/1
body
key value
_method PUT
name Iphone 13 updated
image iphone.jpg = file
price 46 updated

DELETE api/products/{id} Destroy Delete a particular product by ID.
DELETE : http://127.0.0.1:8000/api/products/1

Install nextjs
https://nextjs.org/
npx create-next-app@latest

install axios
npm install axios
https://www.npmjs.com/package/axios

app\page.tsx
app\page.tsx
//app\page.tsx
import Link from "next/link";
import ProductsTable from "@/components/tabledata";
import { Suspense } from "react";
import { Spinner } from "@/components/spinner";

export default function Home() {
  return (
    <div className="w-screen py-20 flex justify-center flex-col items-center">
      <div className="flex items-center justify-between gap-1 mb-5">
        <h1 className="text-4xl font-bold">Next.js 14 Laravel 11 CRUD with Upload and Pagination <br/>(Create, Read, Update and Delete) Mysql | TailwindCSS DaisyUI</h1>
      </div>    
      <div className="overflow-x-auto">
          <div className="mb-2 w-full text-right">
            <Link
              href="/product/create"
              className="btn btn-primary">
              Add New Product
            </Link>
          </div>
          <Suspense fallback={<Spinner />}>
            <ProductsTable/>
          </Suspense>
      </div>  
    </div>
  );
}
components\tabledata.tsx
//components\tabledata.tsx
"use client";
   
import React, { useEffect, useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";
import Image from 'next/image'

export default function Products() {
    const [productsData, setProductsData] = useState([]);
    const [pageprevnext, setPage] = useState({});
  
    const url = "http://127.0.0.1:8000/api/products";
 
    useEffect(() => {
        fetchData(url);
    }, []);
 
    const fetchData = (url) => {
        axios
        .get(url)
        .then((data) => {
            setProductsData(data.data.products.data);
            console.log(data.data.products.data);
            setPage(data.data.products);
            //console.log(data.data.products.next_page_url);
        })
        .catch((error) => {
            console.log(error);
        });
    };

    const handleNextPage = () => {
        console.log(pageprevnext.next_page_url);
        fetchData(pageprevnext.next_page_url);
        window.scrollTo(0, 0);
    };
     
    const handlePreviousPage = () => {
        fetchData(pageprevnext.prev_page_url);
        window.scrollTo(0, 0);
    };

    const deleteProduct = (id) => {
        axios.delete('http://127.0.0.1:8000/api/productdelete/'+id).then(function(response){
            console.log(response.data);
            alert("Successfully Deleted");
            window.location.href = '/';
        });
    }

    return (
        <>
        <table className="table table-zebra">
        <thead className="text-sm text-gray-700 uppercase bg-gray-50">
            <tr>
            <th className="py-3 px-6">#</th>
            <th className="py-3 px-6">Photo</th>
            <th className="py-3 px-6">Name</th>
            <th className="py-3 px-6">Price</th>
            <th className="py-3 px-6 text-center">Actions</th>
            </tr>
        </thead>
        <tbody>
            {productsData.map((rs, index) => (
            <tr key={rs.id} className="bg-white border-b">
                <td className="py-3 px-6">{rs.id}</td>
                <td className="py-3 px-6">
                    <Image
                        src={`http://127.0.0.1:8000/storage/${rs.image}`}
                        width={70}
                        height={70}
                        style={{width:'90px', height: "auto" }}
                        alt="Photo"
                    />
                </td>
                <td className="py-3 px-6">{rs.name}</td>
                <td className="py-3 px-6">${rs.price}.99</td>
                <td className="flex justify-center gap-1 py-3">
                    <Link
                    href={`/product/view/${rs.id}`} 
                    className="btn btn-info">
                    View
                    </Link>
                    <Link
                    href={`/product/edit/${rs.id}`} 
                    className="btn btn-primary">
                    Edit
                    </Link>
                    <button onClick={() => deleteProduct(rs.id)} className="btn btn-secondary">Delete</button>
                </td>
            </tr>
            ))}
        </tbody>
        </table>
        
        <div className="w-1/2 items-center px-4 mt-6">   
            <div className="join grid grid-cols-2">
                {pageprevnext.prev_page_url ? (
                    <button className="join-item btn btn-primary btn-outline" onClick={handlePreviousPage}>
                    Previous
                    </button>
                ) : null}
                {pageprevnext.next_page_url ? (
                    <button className="join-item btn btn-primary btn-outline" onClick={handleNextPage}>
                    Next
                    </button>
                ) : null}
            </div>
        </div> 
        </>
  );
}
components\spinner.tsx
//components\spinner.tsx
export const Spinner = () => {
  return (
    <span className="loading loading-spinner loading-lg"></span>
  );
};
app\product\create\page.tsx
//app\product\create\page.tsx
"use client";

import React, { useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios

const Product = () => {
    const [name, setName] = useState("");
    const [price, setPrice] = useState("");
    const [image, setFile] = useState()
 
    const onSubmitUpload = async (e) => {
        e.preventDefault();
       try {
          const formData = new FormData()
          formData.append("name", name);
          formData.append("price", price);
          formData.append('image', image)
          axios.post('http://127.0.0.1:8000/api/products',formData )
          .then((response) => {
              console.log(response);
              window.location.href = '/';
          })
          .catch(er => console.log(er))
        } catch (err) {
            console.log("Something Wrong");
        }
    }
    
    return (
    <div className="max-w-md mx-auto mt-5">
        <h1 className="text-2xl text-center mb-2">Add New Product</h1>
        <div>
        <form>
        <div className="mb-5">
          <label htmlFor="name" className="block text-sm font-medium text-gray-900">
            Name
          </label>
          <input
            type="text"
            name="name"
            id="name"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Name..."
            onChange={(e) => setName(e.target.value)}
          />
        </div>
        <div className="mb-5">
          <label htmlFor="price" className="block text-sm font-medium text-gray-900">
            Price
          </label>
          <input
            type="price"
            name="price"
            id="price"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="price..."
            onChange={(e) => setPrice(e.target.value)}
          />
        </div>
        <div className="mb-5">
          <label className="block text-sm font-medium text-gray-900">
            Upload File
          </label>
          <input type="file" onChange={(e) => setFile(e.target.files[0])} name="image" id="image" className="file-input file-input-bordered file-input-secondary w-full max-w-xs"/>
        </div>
        <button type="submit" className="btn btn-primary" onClick={e => onSubmitUpload(e)}>Add New Product</button> 
      </form>
    </div>
    </div>
  );
};
  
export default Product;
app\product\edit\[id]\page.tsx
//app\product\edit\[id]\page.tsx
"use client";
 
import React, { useState, useEffect } from 'react';
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import { useParams } from 'next/navigation'
import Image from 'next/image'

export default function ViewProductPage() {
    const {id}=useParams();

    console.log(id);
 
    useEffect(()=>{
        fetchProduct();
    },[id]);
  
    const fetchProduct=async()=>{
        try{
            const result=await axios.get("http://127.0.0.1:8000/api/products/"+id);
            console.log(result.data.product);
            setInputs(result.data.product)
        }catch(err){
            console.log("Something Wrong");
        }
    }
 
    const[message, setMessage]= useState('');
    const [inputs, setInputs] = useState([]);
    const [fileimage, setPhoto]= useState('');
     
    const handleChange = (event) => {
        const name = event.target.name;
        const value = event.target.value;
        setInputs(values => ({...values, [name]: value}));
    }
     
    const uploadProduct= async()=>{
        const formData= new FormData();
        formData.append('_method', 'PUT');
        formData.append('name', inputs.name);
        formData.append('price',inputs.price);
        formData.append('image', fileimage);
        const response= await axios.post("http://127.0.0.1:8000/api/productsupdate/"+id, formData, {
            headers:{'Content-Type':"multipart/form-data"},
        } );
        setMessage(response.data.message); //"message": "Product successfully updated.."
        console.log(response)
        setTimeout(()=>{
            window.location.href = '/';
        }, 2000);
    }
 
    const handleSubmit= async(e)=>{
      e.preventDefault();
      await uploadProduct();
 
   }
 
    return (
    <div className="max-w-md mx-auto mt-5">
      <h1 className="text-2xl text-center mb-2">Edit Form</h1>
        <p className="text-success"><b>{ message }</b></p>  
            <form onSubmit={ handleSubmit}> 
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900"> ID:</label>
                    <input type="text" id="id" name="id" value={id} disabled />
                </div>
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900"> Full Name:</label>
                    <input type="text" className="input input-bordered input-primary w-full max-w-xs" placeholder="Enter Your Full Name" name="name"
                    value={inputs.name} onChange={ handleChange}/>
                </div>
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900">Price:</label>
                    <input type="text" className="input input-bordered input-primary w-full max-w-xs" id="price" placeholder="Enter Price" name="price"
                    value={inputs.price} onChange={ handleChange}/>
                </div>
                <div className="mb-5">
                    <label className="block text-sm font-medium text-gray-900">
                    Upload File
                    </label>
                    <input type="file" onChange={(e)=>setPhoto(e.target.files[0])} name="image" id="image" className="file-input file-input-bordered file-input-secondary w-full max-w-xs"/>
                </div>
                <p className="text-center mt-6">
                    <Image
                    src={`http://127.0.0.1:8000/storage/${inputs.image}`}
                    width={200}
                    height={200}
                    alt="Photo"
                    style={{width:'400px', height: "auto" }}
                />
                </p>
                <button type="submit" className="btn btn-primary">Update</button>
            </form>
    </div>
  );
}
app\product\view\[id]\page.tsx
//app\product\view\[id]\page.tsx
"use client";
 
import React, { useState, useEffect } from 'react';
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";
import { useParams } from 'next/navigation'
import Image from 'next/image'

export default function ViewProductPage() {
    const {id}=useParams();
 
    console.log(id);
 
    const[product,setProduct]=useState([]);
  
    useEffect(()=>{
        fetchProduct();
    },[id]);
  
    const fetchProduct=async()=>{
        try{
        const result=await axios.get("http://127.0.0.1:8000/api/products/"+id);
          console.log(result.data.product);
          setProduct(result.data.product)
  
        }catch(err){
            console.log("Something Wrong");
        }
    }
 
    return (
    <div className="max-w-2xl mx-auto mt-5">
      <h1 className="text-2xl text-center mb-2">View Product</h1>
      <table className="table table-zebra">
          <thead className="text-sm text-gray-700 uppercase bg-gray-50">
            <tr>
              <th>S No.</th>
              <th>Product Name</th>
              <th>Price</th>             
            </tr>
          </thead>
          <tbody>
            <tr>
                <td>{product.id}</td>
                <td>{product.name}</td>
                <td>{product.price}</td>
            </tr>
          </tbody>
      </table>
      <p className="text-center mt-6">
        <Image
        src={`http://127.0.0.1:8000/storage/${product.image}`}
        width={200}
        height={200}
        alt="Photo"
        style={{width:'400px', height: "auto" }}
      />
      </p>
    </div>
  );
}
next.config.mjs
/** @type {import('next').NextConfig} */
//const nextConfig = {};
const nextConfig = {
  reactStrictMode: true,
  images : {
    domains : ['localhost', 'cairocoders-ednalan.com', '127.0.0.1'] // == Domain name
  }
}
export default nextConfig;
run C:\nextjs>npm run dev
https://github.com/cairocodes/Next.js-14-Laravel-11-CRUD-with-Upload-and-Pagination-Create-Read-Update-and-Delete-Mysql

Saturday, April 13, 2024

Next.js 14 Laravel 11 Pagination Next Prev Mysql | TailwindCSS DaisyUI

Next.js 14 Laravel 11 Pagination Next Prev Mysql | TailwindCSS DaisyUI

Download Laravel App

https://laravel.com/docs/11.x/installation

Connecting our Database

open .env file root directory.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=8889
DB_DATABASE=laravel11dev
DB_USERNAME=root
DB_PASSWORD=root

Create Model and Migration

C:\xampp\htdocs\laravel\laravelproject>php artisan make:model Product -m

A new file named Product.php will be created in the app directory and database/migrations directory to generate the table in our database
app/Models/Product.php
//app/Models/Product.php
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
 
class Product extends Model
{
    use HasFactory;
 
    protected $fillable = [
        'name', 
        'image', 
        'price'
    ];
}
database\migrations\create_products_table.php
//database\migrations\create_products_table.ph
<?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('image');
            $table->integer('price');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('products');
    }
};
Database Migration
php artisan migrate

C:\xampp\htdocs\laravel\laravel10project>php artisan migrate
Migration table created successfully.
check database table
Create Controller and Request
C:\xampp\htdocs\laravel\laravel10project>php artisan make:controller ProductController

app\Http\Controllers\ProductController.php
//app\Http\Controllers\ProductController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Product;
use Illuminate\Support\Facades\Storage; //php artisan storage:link = php artisan storage:link = http://127.0.0.1:8000/storage/1.jpg

class ProductController extends Controller
{
    public function index()
    {
        //$products = Product::all(); // All Product

        $products = Product::paginate(3);

        // Return Json Response
        return response()->json([
            'results' => $products
        ], 200);
    }
}
Routes
install
php artisan install:api
All API requests will need the header Accept: application/json.
open routes/api.php and update the following code
routes\api.php
//routes\api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;

Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

Route::get('products', [ProductController::class, 'index']);
Run C:\xampp\htdocs\laravel\myapp>php artisan serve
Starting Laravel development server: http://127.0.0.1:8000

Install nextjs
https://nextjs.org/
npx create-next-app@latest

install axios
npm install axios
https://www.npmjs.com/package/axios

app\page.tsx
app\page.tsx
//app\page.tsx
import TableData from "@/components/tabledata";

export default function Home() {
  return (
    <div className="w-screen py-20 flex justify-center flex-col items-center bg-gray-300">
      <div className="flex items-center justify-between gap-1 mb-5">
        <h1 className="text-4xl font-bold">Next.js 14 Laravel 11 Pagination Next Prev Mysql | TailwindCSS DaisyUI</h1>
      </div>    
      <TableData/>
    </div>
  );
}
components\tabledata.tsx
//components\tabledata.tsx
"use client";

import React, { useEffect, useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Image from 'next/image' 

export default function Products() {
    const [products, setProducts] = useState([]);
    const [info, setInfo] = useState({});

    const url = "http://127.0.0.1:8000/api/products";

    useEffect(() => {
        fetchProducts(url);
    }, []);

    const fetchProducts = (url) => {
        axios
        .get(url)
        .then((data) => {
            setProducts(data.data.results.data);
            //console.log(data.data.results.data);
            setInfo(data.data.results);
            //console.log(data.data.results.next_page_url);
        })
        .catch((error) => {
            console.log(error);
        });
    };

    const handleNextPage = () => {
        fetchProducts(info.next_page_url);
        window.scrollTo(0, 0);
    };
    
    const handlePreviousPage = () => {
        fetchProducts(info.prev_page_url);
        window.scrollTo(0, 0);
    };

    return (
            <div className="">
            <div className="container mx-auto px-4">
                <h2 className="text-3xl font-bold text-white mb-8">Introducing Our Latest Product</h2>
                <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
                
                {products.map((item, index) => (
                <div key={index} className="bg-white rounded-lg shadow-lg p-8">
                    <div className="relative overflow-hidden">
                        <Image
                        src={`http://127.0.0.1:8000/storage/${item.image}`}
                        width={400}
                        height={400}
                        alt="Photo"
                        />
                    <div className="absolute inset-0 bg-black opacity-40" />
                    <div className="absolute inset-0 flex items-center justify-center">
                        <button className="bg-white text-gray-900 py-2 px-6 rounded-full font-bold hover:bg-gray-300">View Product</button>
                    </div>
                    </div>
                    <h3 className="text-xl font-bold text-gray-900 mt-4">{item.name}</h3>
                    <p className="text-gray-500 text-sm mt-2">Description: {item.name}</p>
                    <div className="flex items-center justify-between mt-4">
                    <span className="text-gray-900 font-bold text-lg">${item.price}.99</span>
                    <button className="bg-gray-900 text-white py-2 px-4 rounded-full font-bold hover:bg-gray-800">Add to Cart</button>
                    </div>
                </div>
                ))}

                </div>
                <div className="w-1/2 items-center px-4 mt-6">   
                    <div className="join grid grid-cols-2">
                        {info.prev_page_url ? (
                            <button className="join-item btn btn-primary btn-outline" onClick={handlePreviousPage}>
                            Previous
                            </button>
                        ) : null}
                        {info.next_page_url ? (
                            <button className="join-item btn btn-primary btn-outline" onClick={handleNextPage}>
                            Next
                            </button>
                        ) : null}
                    </div>
                </div> 
            </div>
            </div>
  );
}
next.config.mjs
/** @type {import('next').NextConfig} */
//const nextConfig = {};
const nextConfig = {
  reactStrictMode: true,
  images : {
    domains : ['localhost', 'cairocdoers-ednalan.com', '127.0.0.1'] // == Domain name
  }
}
export default nextConfig;
run C:\nextjs>npm run dev
https://github.com/cairocodes/Next.js-14-Laravel-11-Pagination-Next-Prev-Mysql-TailwindCSS-DaisyUI

Thursday, April 11, 2024

Next.js 14 Python Flask Mysql Pagination Next Prev | TailwindCSS DaisyUI

Next.js 14 Python Flask Mysql Pagination Next Prev | TailwindCSS DaisyUI

https://python-guide-es.readthedocs.io/es/guide-es/dev/virtualenvs.html

Create an environment
ednalan@Cairocoders myapp % pip install virtualenv
ednalan@Cairocoders myapp % pip install virtualenv

Activate the environment
ednalan@Cairocoders myapp % source venv/bin/activate
(venv) ednalan@Cairocoders myapp %

Install Flask
https://pypi.org/project/Flask/
(venv) ednalan@Cairocoders myapp % pip install -U Flask
(venv) ednalan@Cairocoders myapp % flask run

Install requirements
pip install -U flask-cors
https://pypi.org/project/Flask-Cors/

Flask-SQLAlchemy
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy to your application.
https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/

(venv) PS C:\flask_dev\myapp>pip install -U Flask-SQLAlchemy

python3 -m pip install
https://pypi.org/project/pymysql/
app.py
//app.py
from flask import Flask, request, jsonify
from flask_cors import CORS, cross_origin #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors
   
from models import db, Products

app = Flask(__name__)
   
app.config['SECRET_KEY'] = 'cairocoders-ednalan'
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flaskdb.db'
# Databse configuration mysql                             Username:password@hostname/databasename
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:root@localhost:8889/nextjsdb'
   
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = True
   
CORS(app, supports_credentials=True)
   
db.init_app(app)
      
with app.app_context():
    db.create_all()
   
@app.route("/")
def hello_world():
    return "Hello, World!"
   
@app.route('/products/<int:page>/<int:per_page>', methods=['GET']) #http://127.0.0.1:5000/products/1/4
def products(page=1, per_page=3):
    
    nextpage = page + 1
    prevpage = page - 1
         
    total = Products.query.count()
     
    productdata = Products.query.order_by(Products.id.asc())  
    products = productdata.paginate(page=page, per_page=per_page)
     
    #print(products.next_num)
    #print(products.prev_num)
     
    nextnumber = products.next_num
    if nextnumber == None:
        next_page_url = ""
    else:
        next_page_url = f"http://127.0.0.1:5000/products/{nextpage}/{per_page}"
        
    prev_number = products.prev_num
    if prev_number == None:
        prev_page = ""
    else:
        prev_page = f"http://127.0.0.1:5000/products/{prevpage}/{per_page}"
         
    return jsonify({
        'total': total,
        'next_page_url': next_page_url,
        'prev_page_url': prev_page,
        'results': [{
            'id': rs.id,
            'name': rs.name,
            'image': rs.image,
            'price': rs.price
        } for rs in products.items]
    })
   
if __name__ == "__main__":
    app.run(debug=True)
models.py
//models.py
from flask_sqlalchemy import SQLAlchemy
       
db = SQLAlchemy()
       
class Products(db.Model):
    __tablename__ = "products"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(150), index=True)
    image = db.Column(db.String(150), index=True)
    price = db.Column(db.Integer,default=0)
run (venv) C:\flask_dev\myapp>flask run

Next.js
Install requirements
npm install axios
https://www.npmjs.com/package/axios

app\page.tsx
//app\page.tsx
import Link from "next/link";
import TableData from "@/components/tabledata";
import { Suspense } from "react";
import { Spinner } from "@/components/spinner";
 
export default function Home() {
  return (
    <div className="w-screen py-20 flex justify-center flex-col items-center bg-gray-300">
      <div className="flex items-center justify-between gap-1 mb-5">
        <h1 className="text-4xl font-bold">Next.js 14 Python Flask Mysql Pagination Next Prev | TailwindCSS DaisyUI</h1>
      </div>    
      <Suspense fallback={<Spinner />}>
        <TableData/>
      </Suspense>
    </div>
  );
}
components\tabledata.tsx
//components\tabledata.tsx
"use client";

import React, { useEffect, useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Image from 'next/image' 

export default function Users() {
    const [products, setProducts] = useState([]);
    const [info, setInfo] = useState({});

    const url = "http://127.0.0.1:5000/products/1/3";

    useEffect(() => {
        fetchProducts(url);
    }, []);

    const fetchProducts = (url) => {
        axios
        .get(url)
        .then((data) => {
            setProducts(data.data.results);
            //console.log(data.data.results);
            setInfo(data.data);
            //console.log(data.data);
        })
        .catch((error) => {
            console.log(error);
        });
    };

    const handleNextPage = () => {
        fetchProducts(info.next_page_url);
        window.scrollTo(0, 0);
    };
    
    const handlePreviousPage = () => {
        fetchProducts(info.prev_page_url);
        window.scrollTo(0, 0);
    };

    return (
            <div className="py-16">
            <div className="container mx-auto px-4">
                <h2 className="text-3xl font-bold text-white mb-8">Introducing Our Latest Product</h2>
                <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
                
                {products.map((item, index) => (
                <div key={index} className="bg-white rounded-lg shadow-lg p-8">
                    <div className="relative overflow-hidden">
                        <Image
                        src={`http://127.0.0.1:5000/static/images/${item.image}`}
                        width={400}
                        height={400}
                        alt="Photo"
                        />
                    <div className="absolute inset-0 bg-black opacity-40" />
                    <div className="absolute inset-0 flex items-center justify-center">
                        <button className="bg-white text-gray-900 py-2 px-6 rounded-full font-bold hover:bg-gray-300">View Product</button>
                    </div>
                    </div>
                    <h3 className="text-xl font-bold text-gray-900 mt-4">{item.name}</h3>
                    <p className="text-gray-500 text-sm mt-2">Description: {item.name}</p>
                    <div className="flex items-center justify-between mt-4">
                    <span className="text-gray-900 font-bold text-lg">${item.price}.99</span>
                    <button className="bg-gray-900 text-white py-2 px-4 rounded-full font-bold hover:bg-gray-800">Add to Cart</button>
                    </div>
                </div>
                ))}

                </div>
                <div className="w-1/2 items-center px-4 mt-6">   
                    <div className="join grid grid-cols-2">
                        {info.prev_page_url ? (
                            <button className="join-item btn btn-primary btn-outline" onClick={handlePreviousPage}>
                            Previous
                            </button>
                        ) : null}
                        {info.next_page_url ? (
                            <button className="join-item btn btn-primary btn-outline" onClick={handleNextPage}>
                            Next
                            </button>
                        ) : null}
                    </div>
                </div> 
            </div>
            </div>
  );
}
components\spinner.tsx
//components\spinner.tsx
export const Spinner = () => {
  return (
    <span className="loading loading-spinner loading-lg"></span>
  );
};
run C:\nextjs>npm run dev
https://github.com/cairocodes/Next.js-14-Python-Flask-Mysql-Pagination-Next-Prev-TailwindCSS-DaisyUI

Wednesday, April 10, 2024

Next.js 14 Laravel 11 CRUD Mysql (Create Read Update and Delete)| TailwindCSS DaisyUI

Next.js 14 Laravel 11 CRUD Mysql (Create Read Update and Delete)| TailwindCSS DaisyUI

Download Laravel App

https://laravel.com/docs/11.x/installation

Connecting our Database

open .env file root directory.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=8889
DB_DATABASE=laravel11dev
DB_USERNAME=root
DB_PASSWORD=root

Database Migration

C:\xampp\htdocs\laravel\my-app>php artisan migrate

Create Controller
C:\xampp\htdocs\laravel\myapp>php artisan make:controller UserController
app\Http\Controllers\UserController.php
//app\Http\Controllers\UserController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use App\Http\Requests\UserStoreRequest;

class UserController extends Controller
{
    public function index()
    {
        $users = User::all();

        // Return Json Response
        return response()->json([
            'results' => $users
        ], 200);
    }

    public function store(UserStoreRequest $request)
    {
        try {
            // Create User
            User::create([
                'name' => $request->name,
                'email' => $request->email,
                'password' => $request->password
            ]);

            // Return Json Response
            return response()->json([
                'message' => "User successfully created."
            ], 200);
        } catch (\Exception $e) {
            // Return Json Response
            return response()->json([
                'message' => "Something went really wrong!"
            ], 500);
        }
    }

    public function show($id)
    {
        // User Detail 
        $users = User::find($id);
        if (!$users) {
            return response()->json([
                'message' => 'User Not Found.'
            ], 404);
        }

        // Return Json Response
        return response()->json([
            'users' => $users
        ], 200);
    }

    public function update(UserStoreRequest $request, $id)
    {
        try {
            // Find User
            $users = User::find($id);
            if (!$users) {
                return users()->json([
                    'message' => 'User Not Found.'
                ], 404);
            }

            //echo "request : $request->image";
            $users->name = $request->name;
            $users->email = $request->email;

            // Update User
            $users->save();

            // Return Json Response
            return response()->json([
                'message' => "User successfully updated."
            ], 200);
        } catch (\Exception $e) {
            // Return Json Response
            return response()->json([
                'message' => "Something went really wrong!"
            ], 500);
        }
    }

    public function destroy($id)
    {
        // Detail 
        $users = User::find($id);
        if (!$users) {
            return response()->json([
                'message' => 'User Not Found.'
            ], 404);
        }

        // Delete User
        $users->delete();

        // Return Json Response
        return response()->json([
            'message' => "User successfully deleted."
        ], 200);
    }
}
php artisan make:request UserStoreRequest
C:\xampp\htdocs\laravel\myapp>php artisan make:request UserStoreRequest

app\Http\Requests\UserStoreRequest.php
//app\Http\Requests\UserStoreRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserStoreRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        //return false;
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
     */
    public function rules(): array
    {
        if(request()->isMethod('post')) {
            return [
                'name' => 'required|string|max:258',
                'email' => 'required|string',
                'password' => 'required|string'
            ];
        } else {
            return [
                'name' => 'required|string|max:258',
                'email' => 'required|string',
                'password' => 'required|string'
            ];
        }
    }
     
    public function messages()
    {
        if(request()->isMethod('post')) {
            return [
                'name.required' => 'Name is required!',
                'email.required' => 'Email is required!',
                'password.required' => 'password is required!'
            ];
        } else {
            return [
                'name.required' => 'Name is required!',
                'email.required' => 'email is required!',
                'password.required' => 'password is required!'
            ];   
        }
    }
}
routes/api.php
//routes/api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

Route::get('users', [UserController::class, 'index']); //php artisan install:api
Route::get('users/{id}', [UserController::class, 'show']);
Route::post('addnew', [UserController::class, 'store']);
Route::put('usersupdate/{id}', [UserController::class, 'update']);
Route::delete('usersdelete/{id}', [UserController::class, 'destroy']);
Run C:\xampp\htdocs\laravel\myapp>php artisan serve
Starting Laravel development server: http://127.0.0.1:8000/api/users
Install nextjs
https://nextjs.org/
npx create-next-app@latest

install axios
npm install axios
https://www.npmjs.com/package/axios

app\page.tsx
app\page.tsx
//app\page.tsx
import Link from "next/link";
import TableData from "@/components/tabledata";
import { Suspense } from "react";
import { Spinner } from "@/components/spinner";
 
export default function Home() {
    return (
    <div className="w-screen py-20 flex justify-center flex-col items-center">
      <div className="flex items-center justify-between gap-1 mb-5">
        <h1 className="text-4xl font-bold">Next.js 14 Laravel 11 CRUD Mysql (Create Read Update and Delete)| TailwindCSS DaisyUI</h1>
      </div>    
        <div className="overflow-x-auto">
          <div className="mb-2 w-full text-right">
            <Link
              href="/user/create"
              className="btn btn-primary">
              Create
            </Link>
          </div>
          <Suspense fallback={<Spinner />}>
            <TableData/>
          </Suspense>
      </div>  
    </div>
  ); 
}
components\tabledata.tsx
//components\tabledata.tsx
"use client";
  
import React, { useEffect, useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";

export default function Users() {
    const [userData, setUSerData] = useState([]);
    useEffect(() => {
        fetchData();
    }, [])
 
    const fetchData = async () => {
        try {
            const result = await axios("http://127.0.0.1:8000/api/users");
            console.log(result.data.results);
            setUSerData(result.data.results) 
        } catch (err) {
            console.log("somthing Wrong");
        }
    }

    const handleDelete=async(id)=>{
        console.log(id);
        await axios.delete("http://127.0.0.1:8000/api/usersdelete/"+id);
        const newUserData=userData.filter((item)=>{
            return(
                item.id !==id
            )
        })
        setUSerData(newUserData);
    }
  return (
        <table className="table table-zebra">
        <thead className="text-sm text-gray-700 uppercase bg-gray-50">
            <tr>
            <th className="py-3 px-6">#</th>
            <th className="py-3 px-6">Name</th>
            <th className="py-3 px-6">Email</th>
            <th className="py-3 px-6">Created At</th>
            <th className="py-3 px-6 text-center">Actions</th>
            </tr>
        </thead>
        <tbody>
            {userData.map((rs, index) => (
            <tr key={rs.id} className="bg-white border-b">
                <td className="py-3 px-6">{index + 1}</td>
                <td className="py-3 px-6">{rs.name}</td>
                <td className="py-3 px-6">{rs.email}</td>
                <td className="py-3 px-6">{rs.created_at}</td>
                <td className="flex justify-center gap-1 py-3">
                    <Link
                    href={`/user/view/${rs.id}`} 
                    className="btn btn-info">
                    View
                    </Link>
                    <Link
                    href={`/user/edit/${rs.id}`} 
                    className="btn btn-primary">
                    Edit
                    </Link>
                    <button onClick={()=>handleDelete(rs.id)} className="btn btn-secondary">Delete</button>
                </td>
            </tr>
            ))}
        </tbody>
        </table>
  );
}
components\spinner.tsx
//components\spinner.tsx
export const Spinner = () => {
  return (
    <span className="loading loading-spinner loading-lg"></span>
  );
};
app\user\create\page.tsx
//app\user\create\page.tsx
"use client";

import React, { useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios

const CreateUserPage = () => {
    const [userField, setUserField] = useState({
        name: "",
        email: "",
        password: ""
    });
 
    const changeUserFieldHandler = (e) => {
        setUserField({
            ...userField,
            [e.target.name]: e.target.value
        });
        //console.log(userField);
    }

    const onSubmitChange = async (e) => {
        e.preventDefault();
        try {
          const responce= await axios.post("http://127.0.0.1:8000/api/addnew", userField);
          console.log(responce)
          window.location.href = '/';
        } catch (err) {
            console.log("Something Wrong");
        }
    }
    return (
    <div className="max-w-md mx-auto mt-5">
        <h1 className="text-2xl text-center mb-2">Add New User</h1>
        <div>
        <form>
        <div className="mb-5">
          <label htmlFor="name" className="block text-sm font-medium text-gray-900">
            Full Name
          </label>
          <input
            type="text"
            name="name"
            id="name"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Full Name..."
            onChange={e => changeUserFieldHandler(e)} 
          />
        </div>
        <div className="mb-5">
          <label htmlFor="email" className="block text-sm font-medium text-gray-900">
            Email
          </label>
          <input
            type="email"
            name="email"
            id="email"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Email..."
            onChange={e => changeUserFieldHandler(e)}
          />
        </div>

        <div className="mb-5">
          <label
            htmlFor="password" className="block text-sm font-medium text-gray-900">
            Password
          </label>
          <input
            type="password"
            name="password"
            id="password"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Password..."
            onChange={e => changeUserFieldHandler(e)}
          />
        </div>

         <button type="submit" className="btn btn-primary" onClick={e => onSubmitChange(e)}>Add User</button> 
      </form>
    </div>
    </div>
  );
};
  
export default CreateUserPage;
app\user\edit\[id]\page.tsx
//app\user\edit\[id]\page.tsx
"use client";

import React, { useState, useEffect } from 'react';
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";
import { useParams } from 'next/navigation'

export default function ViewUserPage() {
    const {id}=useParams();

    console.log(id);
 
    const [userField, setUserField] = useState({
        name: "",
        email: ""
    });

    useEffect(()=>{
        fetchUser();
    },[id]);
 
    const fetchUser=async()=>{
        try{
            const result=await axios.get("http://127.0.0.1:8000/api/users/"+id);
            console.log(result.data.users);
            setUserField(result.data.users)
 
        }catch(err){
            console.log("Something Wrong");
        }
    }

    const changeUserFieldHandler = (e) => {
        setUserField({
            ...userField,
            [e.target.name]: e.target.value
        });
        console.log(userField);
    }
     
    const onSubmitChange = async (e) => {
        e.preventDefault();
        try {
            await axios.put("http://127.0.0.1:8000/api/usersupdate/"+id, userField);
            window.location.href = '/';
        } catch (err) {
            console.log("Something Wrong");
        }
    }

    return (
    <div className="max-w-md mx-auto mt-5">
      <h1 className="text-2xl text-center mb-2">Edit Form</h1>
            <form>
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900"> ID:</label>
                    <input type="text" id="id" name="id" value={id} disabled />
                </div>
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900"> Full Name:</label>
                    <input type="text" className="input input-bordered input-primary w-full max-w-xs" placeholder="Enter Your Full Name" name="name" 
                    value={userField.name} onChange={e => changeUserFieldHandler(e)} />
                </div>
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900">Email:</label>
                    <input type="email" className="input input-bordered input-primary w-full max-w-xs" id="email" placeholder="Enter email" name="email" 
                    value={userField.email}  onChange={e => changeUserFieldHandler(e)}/>
                </div>
                <div className="mb-3 mt-3">
                     <label className="block text-sm font-medium text-gray-900">Password:</label>
                      <input type="text" className="input input-bordered input-primary w-full max-w-xs" id="password" placeholder="Enter Password" name="password" 
                      onChange={e => changeUserFieldHandler(e)} required/>
                </div>
                <button type="submit" className="btn btn-primary" onClick={e=>onSubmitChange(e)}>Update</button>
            </form>
    </div>
  );
}
app\user\view\[id]\page.tsx
//app\user\view\[id]\page.tsx
"use client";

import React, { useState, useEffect } from 'react';
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";
import { useParams } from 'next/navigation'

export default function ViewUserPage() {
    const {id}=useParams();

    console.log(id);

    const[user,setUser]=useState([]);
 
    useEffect(()=>{
        fetchUser();
    },[id]);
 
    const fetchUser=async()=>{
        try{
        const result=await axios.get("http://127.0.0.1:8000/api/users/"+id);
          console.log(result.data.users);
          setUser(result.data.users)
 
        }catch(err){
            console.log("Something Wrong");
        }
    }

    return (
    <div className="max-w-2xl mx-auto mt-5">
      <h1 className="text-2xl text-center mb-2">View User</h1>
      <table className="table table-zebra">
          <thead className="text-sm text-gray-700 uppercase bg-gray-50">
            <tr>
              <th>S No.</th>
              <th>Full Name</th>
              <th>Email</th>             
            </tr>
          </thead>
          <tbody>
            <tr>
                <td>{user.id}</td>
                <td>{user.name}</td>
                <td>{user.email}</td>
            </tr>
          </tbody>
      </table>
    </div>
  );
}
run C:\nextjs>npm run dev
https://github.com/cairocodes/Next.js-14-Laravel-11-CRUD-Mysql-Create-Read-Update-and-Delete-TailwindCSS-DaisyUI

Tuesday, April 9, 2024

Next.js 14 Node Express MongoDB Create with Upload File and List all data | TailwindCSS DaisyUI

Next.js 14 Node Express MongoDB Create with Upload File and List all data | TailwindCSS DaisyUI

https://expressjs.com/
Express JS
Fast, unopinionated, minimalist web framework for Node.js

Install
$ npm install express --savev PS C:\nodeproject> npm install express --save
https://expressjs.com/en/starter/hello-world.html

https://mongoosejs.com/docs/
npm install mongoose --save
multer
npm install --save multer
http://expressjs.com/en/resources/middleware/multer.html

cors
CORS is a node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options.
https://www.npmjs.com/package/cors
PS C:\nodeproject>npm i cors

run PS C:\nodeproject> node index.js

index.js
//index.js
const express = require('express')
const mongoose = require('mongoose')
const cors = require('cors')
const multer = require('multer') //http://expressjs.com/en/resources/middleware/multer.html npm install --save multer
const UserModel = require('./User')

const app = express()
const port = 3000

const path = require('path') //https://expressjs.com/en/starter/static-files.html
app.use('/static', express.static(path.join(__dirname, 'public')))

app.use(cors())
app.use(express.json())
 
main().catch(err => console.log(err));

async function main() {
    try {
        await mongoose.connect('mongodb://127.0.0.1/nodeexpressdb', {});
        console.log("CONNECTED TO DATABASE SUCCESSFULLY");
    } catch (error) {
        console.error('COULD NOT CONNECT TO DATABASE:', error.message);
    }
}

const storage = multer.diskStorage({
  destination: function(req, file, cb) {
    return cb(null, "./public/images")
  },
  filename: function (req, file, cb) {
    return cb(null, `${Date.now()}_${file.originalname}`)
  }
})
 
const upload = multer({storage})

app.get('/hello', (req, res) => {
  res.send('Hello World!')
})

app.post('/upload', upload.single('file'), (req, res) => {
  console.log(req.body)
  console.log(req.file)
  return res.json({Status: "Success"});
})

app.post('/create',upload.single('file'), (req, res) => {
    UserModel.create({
        name: req.body.name,
        email: req.body.email,
        photo: req.file.filename
    }).then(user => res.json(user))
    .catch(err => res.json(err))
})

app.get('/', (req, res) => {
    UserModel.find()
    .then(users => res.json(users))
    .catch(err => res.json(err))
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
User.js
//User.js
const mongoose = require('mongoose')
 
const UserSchema = new mongoose.Schema({
    name: String,
    email: String,
    photo: String
})
 
const UserModel = mongoose.model("users", UserSchema)
 
module.exports = UserModel;
Next.js
Install requirements
npm install axios
https://www.npmjs.com/package/axios

app\page.tsx
//app\page.tsx
import Link from "next/link";
import TableData from "@/components/tabledata";
import { Suspense } from "react";
import { Spinner } from "@/components/spinner";
 
export default function Home() {
    return (
    <div className="w-screen py-20 flex justify-center flex-col items-center">
      <div className="flex items-center justify-between gap-1 mb-5">
        <h1 className="text-4xl font-bold">Next.js 14 Node Express MongoDB Create with Upload File and List all data  | TailwindCSS DaisyUI</h1>
      </div>    
        <div className="overflow-x-auto">
          <div className="mb-2 w-full text-right">
            <Link
              href="/user/create"
              className="btn btn-primary">
              Create
            </Link>
          </div>
          <Suspense fallback={<Spinner />}>
            <TableData/>
          </Suspense>
      </div>  
    </div>
  ); 
}
components\tabledata.tsx
//components\tabledata.tsx
"use client";
  
import Image from 'next/image'  
import React, { useEffect, useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";

export default function Users() {
    const [userData, setUSerData] = useState([]);
    useEffect(() => {
        fetchData();
    }, [])
 
    const fetchData = async () => {
        try {
            const result = await axios("http://localhost:3000/");
            console.log(result.data);
            setUSerData(result.data)
        } catch (err) {
            console.log("somthing Wrong");
        }
    }
  return (
        <table className="table table-zebra">
        <thead className="text-sm text-gray-700 uppercase bg-gray-50">
            <tr>
            <th className="py-3 px-6">#</th>
            <th className="py-3 px-6">Name</th>
            <th className="py-3 px-6">Email</th>
            <th className="py-3 px-6">Photo</th>
            <th className="py-3 px-6 text-center">Actions</th>
            </tr>
        </thead>
        <tbody>
            {userData.map((rs, index) => (
            <tr key={rs.id} className="bg-white border-b">
                <td className="py-3 px-6">{index + 1}</td>
                <td className="py-3 px-6">{rs.name}</td>
                <td className="py-3 px-6">{rs.email}</td>
                <td className="py-3 px-6">
                    <Image
                    //src="http://localhost:3000/static/images/cairocoders-ednalan.png"
                    src={`http://localhost:3000/static/images/${rs.photo}`}
                    width={100}
                    height={100}
                    alt="Photo"
                    />
                </td>
                <td className="flex justify-center gap-1 py-3">
                    <Link
                    href="#" 
                    className="btn btn-info">
                    View
                    </Link>
                    <Link
                    href="#"
                    className="btn btn-primary">
                    Edit
                    </Link>
                    <button className="btn btn-secondary">Delete</button>
                </td>
            </tr>
            ))}
        </tbody>
        </table>
  );
}
components\spinner.tsx
//components\spinner.tsx
export const Spinner = () => {
  return (
    <span className="loading loading-spinner loading-lg"></span>
  );
};
app\user\create\page.tsx
//app\user\create\page.tsx
"use client";

import React, { useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios

const CreateUserPage = () => {
    const [name, setName] = useState("");
    const [email, setEmail] = useState("");
    const [file, setFile] = useState()

    const onSubmitUpload = async (e) => {
        e.preventDefault();
       try {
          const formData = new FormData()
          formData.append("name", name);
          formData.append("email", email);
          formData.append('file', file)
          axios.post('http://localhost:3000/create',formData )
          .then((response) => {
              console.log(response);
              window.location.href = '/';
          })
          .catch(er => console.log(er))
        } catch (err) {
            console.log("Something Wrong");
        }
    }

    return (
    <div className="max-w-md mx-auto mt-5">
        <h1 className="text-2xl text-center mb-2">Add New User</h1>
        <div>
        <form>
        <div className="mb-5">
          <label htmlFor="name" className="block text-sm font-medium text-gray-900">
            Full Name
          </label>
          <input
            type="text"
            name="name"
            id="name"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Full Name..."
            onChange={(e) => setName(e.target.value)}
          />
        </div>
        <div className="mb-5">
          <label htmlFor="email" className="block text-sm font-medium text-gray-900">
            Email
          </label>
          <input
            type="email"
            name="email"
            id="email"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Email..."
            onChange={(e) => setEmail(e.target.value)}
          />
        </div>
        <div className="mb-5">
          <label className="block text-sm font-medium text-gray-900">
            Upload File
          </label>
          <input type="file" onChange={(e) => setFile(e.target.files[0])} className="file-input file-input-bordered file-input-secondary w-full max-w-xs"/>
        </div>
         <button type="submit" className="btn btn-primary" onClick={e => onClick={e => onSubmitUpload(e)}>Add User</button> 
      </form>
    </div>
    </div>
  );
};
  
export default CreateUserPage;
next.config.mjs
//next.config.mjs
/** @type {import('next').NextConfig} */
//const nextConfig = {};
const nextConfig = {
  reactStrictMode: true,
  images : {
    domains : ['localhost', 'cairocoders.com'] // == Domain name
  }
}
export default nextConfig;
run C:\nextjs>npm run dev
https://github.com/cairocodes/Next.js-14-Node-Express-MongoDB-Create-with-Upload-File-and-List-all-data-TailwindCSS-DaisyUI

Monday, April 8, 2024

Next.js 14 Node Express CRUD MongoDB (Create Read Update and Delete)| TailwindCSS DaisyUI

Next.js 14 Node Express CRUD MongoDB (Create Read Update and Delete)| TailwindCSS DaisyUI

https://expressjs.com/
Express JS
Fast, unopinionated, minimalist web framework for Node.js

Install
$ npm install express --savev PS C:\nodeproject> npm install express --save
https://expressjs.com/en/starter/hello-world.html

https://mongoosejs.com/docs/
npm install mongoose --save
cors
CORS is a node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options.
https://www.npmjs.com/package/cors
PS C:\nodeproject>npm i cors

run PS C:\nodeproject> node index.js

//index.js
const express = require('express')
const mongoose = require('mongoose')
const cors = require('cors')
const UserModel = require('./User')
 
const app = express()
const port = 3000

app.use(cors())
app.use(express.json())
 
main().catch(err => console.log(err));

async function main() {
    try {
        await mongoose.connect('mongodb://127.0.0.1/nodeexpressdb', {});
        console.log("CONNECTED TO DATABASE SUCCESSFULLY");
    } catch (error) {
        console.error('COULD NOT CONNECT TO DATABASE:', error.message);
    }
}

app.get('/hello', (req, res) => {
  res.send('Hello World!')
})

app.get('/', (req, res) => {
    UserModel.find()
    .then(users => res.json(users))
    .catch(err => res.json(err))
})
 
 
app.get('/get/:id', (req, res) => {
    const id = req.params.id
    UserModel.findById({_id: id})
    .then(post => res.json(post))
    .catch(err => console.log(err))
})
 
app.post('/create', (req, res) => {
    UserModel.create(req.body)
    .then(user => res.json(user))
    .catch(err => res.json(err))
})
 
app.put('/update/:id', (req, res) => {
    const id = req.params.id;
    UserModel.findByIdAndUpdate({_id: id}, {
        name: req.body.name,
        email: req.body.email,
        age: req.body.age
    }).then(user => res.json(user))
    .catch(err => res.json(err))
})
 
app.delete('/deleteuser/:id', (req, res) => {
    const id = req.params.id;
    UserModel.findByIdAndDelete({_id: id})
    .then(response => res.json(response))
    .catch(err => res.json(err))
})
 
app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
User.js
//User.js
const mongoose = require('mongoose')
 
const UserSchema = new mongoose.Schema({
    name: String,
    email: String,
    age: Number
})
 
const UserModel = mongoose.model("users", UserSchema)
 
module.exports = UserModel;
Next.js Install requirements
npm install axios
https://www.npmjs.com/package/axios

app\page.tsx
//app\page.tsx
import Link from "next/link";
import TableData from "@/components/tabledata";
import { Suspense } from "react";
import { Spinner } from "@/components/spinner";
 
export default function Home() {
    return (
    <div className="w-screen py-20 flex justify-center flex-col items-center">
      <div className="flex items-center justify-between gap-1 mb-5">
        <h1 className="text-4xl font-bold">Next.js 14 Node Express CRUD MongoDB (Create Read Update and Delete)| TailwindCSS DaisyUI</h1>
      </div>    
        <div className="overflow-x-auto">
          <div className="mb-2 w-full text-right">
            <Link
              href="/user/create"
              className="btn btn-primary">
              Create
            </Link>
          </div>
          <Suspense fallback={<Spinner />}>
            <TableData/>
          </Suspense>
      </div>  
    </div>
  ); 
}
components\tabledata.tsx
//components\tabledata.tsx
"use client";
  
import React, { useEffect, useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";

export default function Users() {
    const [userData, setUSerData] = useState([]);
    useEffect(() => {
        fetchData();
    }, [])
 
    const fetchData = async () => {
        try {
            const result = await axios("http://localhost:3000/");
            console.log(result.data);
            setUSerData(result.data)
        } catch (err) {
            console.log("somthing Wrong");
        }
    }

    const handleDelete=async(id)=>{
        console.log(id);
        await axios.delete("http://localhost:3000/deleteuser/"+id);
        const newUserData=userData.filter((item)=>{
            return(
                item._id !==id
            )
        })
        setUSerData(newUserData);
    }
  return (
        <table className="table table-zebra">
        <thead className="text-sm text-gray-700 uppercase bg-gray-50">
            <tr>
            <th className="py-3 px-6">#</th>
            <th className="py-3 px-6">Name</th>
            <th className="py-3 px-6">Email</th>
            <th className="py-3 px-6">Age</th>
            <th className="py-3 px-6 text-center">Actions</th>
            </tr>
        </thead>
        <tbody>
            {userData.map((rs, index) => (
            <tr key={rs.id} className="bg-white border-b">
                <td className="py-3 px-6">{index + 1}</td>
                <td className="py-3 px-6">{rs.name}</td>
                <td className="py-3 px-6">{rs.email}</td>
                <td className="py-3 px-6">{rs.age}</td>
                <td className="flex justify-center gap-1 py-3">
                    <Link
                    href={`/user/view/${rs._id}`} 
                    className="btn btn-info">
                    View
                    </Link>
                    <Link
                    href={`/user/edit/${rs._id}`} 
                    className="btn btn-primary">
                    Edit
                    </Link>
                    <button onClick={()=>handleDelete(rs._id)} className="btn btn-secondary">Delete</button>
                </td>
            </tr>
            ))}
        </tbody>
        </table>
  );
}
components\spinner.tsx
//components\spinner.tsx
export const Spinner = () => {
  return (
    <span className="loading loading-spinner loading-lg"></span>
  );
};
app\user\create\page.tsx
//app\user\create\page.tsx
"use client";

import React, { useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios

const CreateUserPage = () => {
    const [userField, setUserField] = useState({
        name: "",
        email: "",
        age: ""
    });
 
    const changeUserFieldHandler = (e) => {
        setUserField({
            ...userField,
            [e.target.name]: e.target.value
        });
        //console.log(userField);
    }

    const onSubmitChange = async (e) => {
        e.preventDefault();
        try {
          const responce= await axios.post("http://localhost:3000/create", userField);
          console.log(responce)
          window.location.href = '/';
        } catch (err) {
            console.log("Something Wrong");
        }
    }
    return (
    <div className="max-w-md mx-auto mt-5">
        <h1 className="text-2xl text-center mb-2">Add New User</h1>
        <div>
        <form>
        <div className="mb-5">
          <label htmlFor="name" className="block text-sm font-medium text-gray-900">
            Full Name
          </label>
          <input
            type="text"
            name="name"
            id="name"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Full Name..."
            onChange={e => changeUserFieldHandler(e)} 
          />
        </div>
        <div className="mb-5">
          <label htmlFor="email" className="block text-sm font-medium text-gray-900">
            Email
          </label>
          <input
            type="email"
            name="email"
            id="email"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Email..."
            onChange={e => changeUserFieldHandler(e)}
          />
        </div>
        <div className="mb-5">
          <label
            htmlFor="age" className="block text-sm font-medium text-gray-900">
            Age
          </label>
          <input
            type="text"
            name="age"
            id="age"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Age..."
            onChange={e => changeUserFieldHandler(e)}
          />
        </div>
         <button type="submit" className="btn btn-primary" onClick={e => onSubmitChange(e)}>Add User</button> 
      </form>
    </div>
    </div>
  );
};
  
export default CreateUserPage;
app\user\edit\[id]\page.tsx
//app\user\edit\[id]\page.tsx
"use client";

import React, { useState, useEffect } from 'react';
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";
import { useParams } from 'next/navigation'

export default function ViewUserPage() {
    const {id}=useParams();

    console.log(id);
 
    const [userField, setUserField] = useState({
        name: "",
        email: ""
    });

    useEffect(()=>{
        fetchUser();
    },[id]);
 
    const fetchUser=async()=>{
        try{
            const result=await axios.get("http://localhost:3000/get/"+id);
            console.log(result.data);
            setUserField(result.data)
 
        }catch(err){
            console.log("Something Wrong");
        }
    }

    const changeUserFieldHandler = (e) => {
        setUserField({
            ...userField,
            [e.target.name]: e.target.value
        });
        console.log(userField);
    }
     
    const onSubmitChange = async (e) => {
        e.preventDefault();
        try {
            await axios.put("http://localhost:3000/update/"+id, userField);
            window.location.href = '/';
        } catch (err) {
            console.log("Something Wrong");
        }
    }

    return (
    <div className="max-w-md mx-auto mt-5">
      <h1 className="text-2xl text-center mb-2">Edit Form</h1>
            <form>
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900"> ID:</label>
                    <input type="text" id="id" name="id" value={id} disabled />
                </div>
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900"> Full Name:</label>
                    <input type="text" className="input input-bordered input-primary w-full max-w-xs" placeholder="Enter Your Full Name" name="name" value={userField.name} onChange={e => changeUserFieldHandler(e)} />
                </div>
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900">Email:</label>
                    <input type="email" className="input input-bordered input-primary w-full max-w-xs" id="email" placeholder="Enter email" name="email" value={userField.email}  onChange={e => changeUserFieldHandler(e)}/>
                </div>
                <div className="mb-3 mt-3">
                     <label className="block text-sm font-medium text-gray-900">Age:</label>
                      <input type="text" className="input input-bordered input-primary w-full max-w-xs" id="age" placeholder="Enter age" name="age" onChange={e => changeUserFieldHandler(e)} required/>
                </div>
                <button type="submit" className="btn btn-primary" onClick={e=>onSubmitChange(e)}>Update</button>
            </form>
    </div>
  );
}
app\user\view\[id]\page.tsx
//app\user\view\[id]\page.tsx
"use client";

import React, { useState, useEffect } from 'react';
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";
import { useParams } from 'next/navigation'

export default function ViewUserPage() {
    const {id}=useParams();

    console.log(id);

    const[user,setUser]=useState([]);
 
    useEffect(()=>{
        fetchUser();
    },[id]);
 
    const fetchUser=async()=>{
        try{
        const result=await axios.get("http://localhost:3000/get/"+id);
        console.log(result.data);
        setUser(result.data)
 
        }catch(err){
            console.log("Something Wrong");
        }
    }

    return (
    <div className="max-w-2xl mx-auto mt-5">
      <h1 className="text-2xl text-center mb-2">View User</h1>
      <table className="table table-zebra">
          <thead className="text-sm text-gray-700 uppercase bg-gray-50">
            <tr>
              <th>S No.</th>
              <th>Full Name</th>
              <th>Email</th>             
            </tr>
          </thead>
          <tbody>
            <tr>
                <td>{user._id}</td>
                <td>{user.name}</td>
                <td>{user.email}</td>
            </tr>
          </tbody>
      </table>
    </div>
  );
}
run C:\nextjs>npm run dev
https://github.com/cairocodes/Next.js-14-Node-Express-CRUD-MongoDB-Create-Read-Update-and-Delete-TailwindCSS-DaisyUI

Thursday, April 4, 2024

Next.js 14 Python Flask CRUD Mysql (Create Read Update and Delete)| TailwindCSS DaisyUI

Next.js 14 Python Flask CRUD Mysql (Create Read Update and Delete)| TailwindCSS DaisyUI

https://python-guide-es.readthedocs.io/es/guide-es/dev/virtualenvs.html

Create an environment
ednalan@Cairocoders myapp % pip install virtualenv
ednalan@Cairocoders myapp % pip install virtualenv

Activate the environment
ednalan@Cairocoders myapp % source venv/bin/activate
(venv) ednalan@Cairocoders myapp %

Install Flask
https://pypi.org/project/Flask/
(venv) ednalan@Cairocoders myapp % pip install -U Flask
(venv) ednalan@Cairocoders myapp % flask run

Install requirements
pip install -U flask-cors
https://pypi.org/project/Flask-Cors/

Flask-SQLAlchemy
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy to your application.
https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/

(venv) PS C:\flask_dev\myapp>pip install -U Flask-SQLAlchemy

Flask + marshmallow for beautiful APIs
https://pypi.org/project/flask-marshmallow/

(venv) PS C:\flask_dev\myapp>pip install flask-marshmallow

python3 -m pip install
https://pypi.org/project/pymysql/
app.py
 
//app.py
from flask import Flask, jsonify, request
from flask_marshmallow import Marshmallow #ModuleNotFoundError: No module named 'flask_marshmallow' = pip install flask-marshmallow https://pypi.org/project/flask-
from flask_cors import CORS, cross_origin #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors
from models import db, Users
 
app = Flask(__name__)
 
app.config['SECRET_KEY'] = 'cairocoders-ednalan'
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flaskdb.db'
# Databse configuration mysql                             Username:password@hostname/databasename
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:root@localhost:8889/flasknextjs' #python3 -m pip install PyMySQL https://pypi.org/project/pymysql/
                                                        
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = True
  
CORS(app, supports_credentials=True)
 
db.init_app(app)
        
with app.app_context():
    db.create_all()
 
ma=Marshmallow(app)
 
class UserSchema(ma.Schema):
    class Meta:
        fields = ('id','name','email','password')
  
user_schema = UserSchema()
users_schema = UserSchema(many=True)
  
@app.route("/")
def hello_world():
    return "<p>Hello, World!=</p>"
 
@app.route('/users', methods=['GET']) 
def listusers():
    all_users = Users.query.all()
    results = users_schema.dump(all_users)
    return jsonify(results)
  
@app.route('/userdetails/<id>',methods =['GET'])
def userdetails(id):
    user = Users.query.get(id)
    return user_schema.jsonify(user)
  
@app.route('/userupdate/<id>',methods = ['PUT'])
def userupdate(id):
    user = Users.query.get(id)
  
    name = request.json['name']
    email = request.json['email']
  
    user.name = name
    user.email = email
  
    db.session.commit()
    return user_schema.jsonify(user)
 
@app.route('/userdelete/<id>',methods=['DELETE'])
def userdelete(id):
    user = Users.query.get(id)
    db.session.delete(user)
    db.session.commit()
    return user_schema.jsonify(user)
  
@app.route('/newuser',methods=['POST'])
def newuser():
    name = request.json['name']
    email = request.json['email']
    password = request.json['password']
  
    print(name)
    print(email)
    print(password)
 
    users = Users(name=name, email=email, password=password)
 
    db.session.add(users)
    db.session.commit()
    return user_schema.jsonify(users)
 
if __name__ == "__main__":
    app.run(debug=True)
models.py
 
//models.py
from flask_sqlalchemy import SQLAlchemy #pip install -U Flask-SQLAlchemy
         
db = SQLAlchemy()
         
class Users(db.Model):
    __tablename__ = "tblusers"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(150), index=True)
    email = db.Column(db.String(150), index=True, unique=True)
    password = db.Column(db.String(255), index=True)
run (venv) C:\flask_dev\myapp>flask run

Next.js Install requirements
npm install axios
https://www.npmjs.com/package/axios

app\page.tsx
//app\page.tsx
import Link from "next/link";
import TableData from "@/components/tabledata";
import { Suspense } from "react";
import { Spinner } from "@/components/spinner";
 
export default function Home() {
    return (
    <div className="w-screen py-20 flex justify-center flex-col items-center">
      <div className="flex items-center justify-between gap-1 mb-5">
        <h1 className="text-4xl font-bold">Next.js 14 Python Flask CRUD Mysql (Create Read Update and Delete)| TailwindCSS DaisyUI</h1>
      </div>    
        <div className="overflow-x-auto">
          <div className="mb-2 w-full text-right">
            <Link
              href="/user/create"
              className="btn btn-primary">
              Create
            </Link>
          </div>
          <Suspense fallback={<Spinner />}>
            <TableData/>
          </Suspense>
      </div>  
    </div>
  ); 
}
components\tabledata.tsx
//components\tabledata.tsx
"use client";
  
import React, { useEffect, useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";

export default function Users() {
    const [userData, setUSerData] = useState([]);
    useEffect(() => {
        fetchData();
    }, [])
 
    const fetchData = async () => {
        try {
            const result = await axios("http://127.0.0.1:5000/users");
            console.log(result.data);
            setUSerData(result.data)
        } catch (err) {
            console.log("somthing Wrong");
        }
    }

    const handleDelete=async(id)=>{
        console.log(id);
        await axios.delete("http://127.0.0.1:5000/userdelete/"+id);
        const newUserData=userData.filter((item)=>{
            return(
                item.id !==id
            )
        })
        setUSerData(newUserData);
    }
  return (
        <table className="table table-zebra">
        <thead className="text-sm text-gray-700 uppercase bg-gray-50">
            <tr>
            <th className="py-3 px-6">#</th>
            <th className="py-3 px-6">Name</th>
            <th className="py-3 px-6">Email</th>
            <th className="py-3 px-6">Password</th>
            <th className="py-3 px-6 text-center">Actions</th>
            </tr>
        </thead>
        <tbody>
            {userData.map((rs, index) => (
            <tr key={rs.id} className="bg-white border-b">
                <td className="py-3 px-6">{index + 1}</td>
                <td className="py-3 px-6">{rs.name}</td>
                <td className="py-3 px-6">{rs.email}</td>
                <td className="py-3 px-6">{rs.password}</td>
                <td className="flex justify-center gap-1 py-3">
                    <Link
                    href={`/user/view/${rs.id}`} 
                    className="btn btn-info">
                    View
                    </Link>
                    <Link
                    href={`/user/edit/${rs.id}`} 
                    className="btn btn-primary">
                    Edit
                    </Link>
                    <button onClick={()=>handleDelete(rs.id)} className="btn btn-secondary">Delete</button>
                </td>
            </tr>
            ))}
        </tbody>
        </table>
  );
}
components\spinner.tsx
//components\spinner.tsx
export const Spinner = () => {
  return (
    <span className="loading loading-spinner loading-lg"></span>
  );
};
app\user\create\page.tsx
//app\user\create\page.tsx
"use client";

import React, { useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios

const CreateUserPage = () => {
    const [userField, setUserField] = useState({
        name: "",
        email: "",
        password: ""
    });
 
    const changeUserFieldHandler = (e) => {
        setUserField({
            ...userField,
            [e.target.name]: e.target.value
        });
        //console.log(userField);
    }

    const onSubmitChange = async (e) => {
        e.preventDefault();
        try {
          const responce= await axios.post("http://127.0.0.1:5000/newuser", userField);
          console.log(responce)
          window.location.href = '/';
        } catch (err) {
            console.log("Something Wrong");
        }
    }
    return (
    <div className="max-w-md mx-auto mt-5">
        <h1 className="text-2xl text-center mb-2">Add New User</h1>
        <div>
        <form>
        <div className="mb-5">
          <label htmlFor="name" className="block text-sm font-medium text-gray-900">
            Full Name
          </label>
          <input
            type="text"
            name="name"
            id="name"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Full Name..."
            onChange={e => changeUserFieldHandler(e)} 
          />
        </div>
        <div className="mb-5">
          <label htmlFor="email" className="block text-sm font-medium text-gray-900">
            Email
          </label>
          <input
            type="email"
            name="email"
            id="email"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Email..."
            onChange={e => changeUserFieldHandler(e)}
          />
        </div>
        <div className="mb-5">
          <label
            htmlFor="password" className="block text-sm font-medium text-gray-900">
            Password
          </label>
          <input
            type="text"
            name="password"
            id="password"
            className="input input-bordered input-primary w-full max-w-xs"
            placeholder="Password..."
            onChange={e => changeUserFieldHandler(e)}
          />
        </div>
         <button type="submit" className="btn btn-primary" onClick={e => onSubmitChange(e)}>Add User</button> 
      </form>
    </div>
    </div>
  );
};
  
export default CreateUserPage;
app\user\edit\[id]\page.tsx
//app\user\edit\[id]\page.tsx
"use client";

import React, { useState, useEffect } from 'react';
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";
import { useParams } from 'next/navigation'

export default function ViewUserPage() {
    const {id}=useParams();

    console.log(id);
 
    const [userField, setUserField] = useState({
        name: "",
        email: ""
    });

    useEffect(()=>{
        fetchUser();
    },[id]);
 
    const fetchUser=async()=>{
        try{
            const result=await axios.get("http://127.0.0.1:5000/userdetails/"+id);
            console.log(result.data);
            setUserField(result.data)
 
        }catch(err){
            console.log("Something Wrong");
        }
    }

    const changeUserFieldHandler = (e) => {
        setUserField({
            ...userField,
            [e.target.name]: e.target.value
        });
        console.log(userField);
    }
     
    const onSubmitChange = async (e) => {
        e.preventDefault();
        try {
            await axios.put("http://127.0.0.1:5000/userupdate/"+id, userField);
            window.location.href = '/';
        } catch (err) {
            console.log("Something Wrong");
        }
    }

    return (
    <div className="max-w-md mx-auto mt-5">
      <h1 className="text-2xl text-center mb-2">Edit Form</h1>
            <form>
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900"> ID:</label>
                    <input type="text" id="id" name="id" value={id} disabled />
                </div>
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900"> Full Name:</label>
                    <input type="text" className="input input-bordered input-primary w-full max-w-xs" placeholder="Enter Your Full Name" name="name" value={userField.name} onChange={e => changeUserFieldHandler(e)} />
                </div>
                <div className="mb-3 mt-3">
                    <label className="block text-sm font-medium text-gray-900">Email:</label>
                    <input type="email" className="input input-bordered input-primary w-full max-w-xs" id="email" placeholder="Enter email" name="email" value={userField.email}  onChange={e => changeUserFieldHandler(e)}/>
                </div>
                <div className="mb-3 mt-3">
                     <label className="block text-sm font-medium text-gray-900">Password:</label>
                      <input type="text" className="input input-bordered input-primary w-full max-w-xs" id="password" placeholder="Enter password" name="password" onChange={e => changeUserFieldHandler(e)} required/>
                </div>
                <button type="submit" className="btn btn-primary" onClick={e=>onSubmitChange(e)}>Update</button>
            </form>
    </div>
  );
}
app\user\view\[id]\page.tsx
//app\user\view\[id]\page.tsx
"use client";

import React, { useState, useEffect } from 'react';
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";
import { useParams } from 'next/navigation'

export default function ViewUserPage() {
    const {id}=useParams();

    console.log(id);

    const[user,setUser]=useState([]);
 
    useEffect(()=>{
        fetchUser();
    },[id]);
 
    const fetchUser=async()=>{
        try{
        const result=await axios.get("http://127.0.0.1:5000/userdetails/"+id);
        console.log(result.data);
        setUser(result.data)
 
        }catch(err){
            console.log("Something Wrong");
        }
    }

    return (
    <div className="max-w-md mx-auto mt-5">
      <h1 className="text-2xl text-center mb-2">View User</h1>
      <table className="table table-zebra">
          <thead className="text-sm text-gray-700 uppercase bg-gray-50">
            <tr>
              <th>S No.</th>
              <th>Full Name</th>
              <th>Email</th>             
            </tr>
          </thead>
          <tbody>
            <tr>
                <td>{user.id}</td>
                <td>{user.name}</td>
                <td>{user.email}</td>
            </tr>
          </tbody>
      </table>
    </div>
  );
}
run C:\nextjs>npm run dev
https://github.com/cairocodes/Next.js-14-Python-Flask-CRUD-Mysql-Create-Read-Update-and-Delete-TailwindCSS-DaisyUI

Related Post