article

Showing posts with label Python-Flask. Show all posts
Showing posts with label Python-Flask. Show all posts

Wednesday, April 26, 2023

ReactJS Python Flask Infinite Scroll Pagination | SQLAlchemy Mysql

ReactJS Python Flask Infinite Scroll Pagination | SQLAlchemy Mysql

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

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\flaskreact>pip install -U Flask-SQLAlchemy

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors

C:\flask_dev\flaskreact\app.py
 
#C:\flask_dev\flaskreact\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, User
 
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:''@localhost/flaskreact'
 
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('/users/<int:page>/<int:per_page>', methods=['GET']) #http://127.0.0.1:5000/users/1/4
def posts(page=1, per_page=10):
  
    total = User.query.count()
    print(total)
  
    posts = User.query.order_by(User.id.asc())  
    posts = posts.paginate(page=page, per_page=per_page)
  
    return jsonify({
        'total': total,
        'page': page,
        'per_page': per_page,
        'data': [{
            'id': p.id,
            'fullname': p.name,
            'email': p.email,
            'password': p.password,
            'photo': p.photo
        } for p in posts.items]
    })
 
if __name__ == "__main__":
    app.run(debug=True)
C:\flask_dev\flaskreact\models.py
 
#C:\flask_dev\flaskreact\models.py
from flask_sqlalchemy import SQLAlchemy
from uuid import uuid4
   
db = SQLAlchemy()
   
def get_uuid():
    return uuid4().hex
   
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.String(11), primary_key=True, unique=True, default=get_uuid)
    name = db.Column(db.String(150), unique=True)
    email = db.Column(db.String(150), unique=True)
    password = db.Column(db.Text, nullable=False)
    photo = db.Column(db.String(150), unique=True)
run (venv) C:\flask_dev\flaskreact>flask run
http://127.0.0.1:5000/users/1/4

users.sql : https://github.com/cairocodes/cairocoders/blob/main/users.sql

React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js
//C:\react-js\myreactdev\src\App.js
import React, { useEffect, useState } from "react";
import "./App.css";
  
import InfiniteScroll from "react-infinite-scroll-component"; //npm install --save react-infinite-scroll-component = https://github.com/ankeetmaini/react-infinite-scroll-component
import Users from "./components/Users";
import Loader from "./components/Loader";
import End from "./components/End";

function App() {
  const [items, setItems] = useState([]);

  const [hasMore, sethasMore] = useState(true);

  const [page, setpage] = useState(2);

  const perPage = 8;

  useEffect(() => {
    const getUsers = async () => {
      const res = await fetch(
        `http://127.0.0.1:5000/users/1/${perPage}`
      );
      const usersdata = await res.json();
      setItems(usersdata.data);
      console.log(usersdata.data);
    };

    getUsers();
  }, []);

  const fetchUsers = async () => {
    const res = await fetch(
      `http://127.0.0.1:5000/users/${page}/${perPage}`
    );
    const scrolldata = await res.json();
    return scrolldata.data;
  };

  const fetchData = async () => {
    const usersServer = await fetchUsers();

    setItems([...items, ...usersServer]);
    if (usersServer.length === 0 || usersServer.length < 20) {
      sethasMore(false);
    }
    setpage(page + 1);
  };
  return (
    <InfiniteScroll
      dataLength={items.length} //render next data
      next={fetchData}
      hasMore={hasMore}
      loader={<Loader />}
      endMessage={<End />}
    >
      <div className="container">
        <div className="row justify-content-center">
          <div className="col-12 col-sm-8 col-lg-6">
            <div className="section_heading text-center wow fadeInUp">
              <h3>ReactJS Python Flask Infinite Scroll Pagination | SQLAlchemy Mysql</h3>
              <div className="line"></div>
            </div>
          </div>
        </div>

        <div className="row" style={{padding: 20}}>
          {items.map((item) => {
            return <Users key={item.id} item={item} />;
          })}
        </div>

      </div>
    </InfiniteScroll>
  );
}

export default App;
C:\react-js\myreactdev\src\components\Users.js
//C:\react-js\myreactdev\src\components\Users.js
import React, { } from "react";
  
function Users({item: { fullname, email, photo }}) {
    return (
      <div className="col-12 col-sm-6 col-lg-3">
          <div className="single_advisor_profile wow fadeInUp">
              <div className="advisor_thumb"> <img alt="pic" src={photo} width="315" height="315"/></div>
              <div className="single_advisor_details_info">
                    <h6>{fullname}</h6>
                    <p className="designation">{email}</p>
              </div>
        </div>
      </div>
    )
}

export default Users
C:\react-js\myreactdev\src\components\Loader.js
//C:\react-js\myreactdev\src\components\Loader.js
import React, { } from "react";
  
function Loader() {
    return (
        <div className="container">
          <div className="row ">
            <div className="col d-flex justify-content-center">
              
            <div class="spinner-border spin" role="status">
            <span class="visually-hidden">Loading...</span>
            </div>

            </div>
          </div>
        </div>
    )
}

export default Loader
C:\react-js\myreactdev\src\components\End.js
//C:\react-js\myreactdev\src\components\End.js
import React, { } from "react";
  
function End() {
    return (
        <p style={{ textAlign: "center" }}>
          <b>End</b>
        </p>
    )
}

export default End
react-js\myreactdev\src\App.css
//react-js\myreactdev\src\App.css
 body{margin-top:20px;
background:#eee;
}
.single_advisor_profile {
    position: relative;
    margin-bottom: 50px;
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    z-index: 1;
    border-radius: 15px;
    -webkit-box-shadow: 0 0.25rem 1rem 0 rgba(47, 91, 234, 0.125);
    box-shadow: 0 0.25rem 1rem 0 rgba(47, 91, 234, 0.125);
}
.single_advisor_profile .advisor_thumb {
    position: relative;
    z-index: 1;
    border-radius: 15px 15px 0 0;
    margin: 0 auto;
    padding: 30px 30px 0 30px;
    background-color: #3f43fd;
    overflow: hidden;
}
.single_advisor_profile .advisor_thumb::after {
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    position: absolute;
    width: 150%;
    height: 80px;
    bottom: -45px;
    left: -25%;
    content: "";
    background-color: #ffffff;
    -webkit-transform: rotate(-15deg);
    transform: rotate(-15deg);
}
@media only screen and (max-width: 575px) {
    .single_advisor_profile .advisor_thumb::after {
        height: 160px;
        bottom: -90px;
    }
}
.single_advisor_profile .single_advisor_details_info {
    position: relative;
    z-index: 1;
    padding: 30px;
    text-align: right;
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    border-radius: 0 0 15px 15px;
    background-color: #ffffff;
}
.single_advisor_profile .single_advisor_details_info::after {
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    position: absolute;
    z-index: 1;
    width: 50px;
    height: 3px;
    background-color: #3f43fd;
    content: "";
    top: 12px;
    right: 30px;
}
.single_advisor_profile .single_advisor_details_info h6 {
    margin-bottom: 0.25rem;
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
}
@media only screen and (min-width: 768px) and (max-width: 991px) {
    .single_advisor_profile .single_advisor_details_info h6 {
        font-size: 14px;
    }
}
.single_advisor_profile .single_advisor_details_info p {
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    margin-bottom: 0;
    font-size: 14px;
}
@media only screen and (min-width: 768px) and (max-width: 991px) {
    .single_advisor_profile .single_advisor_details_info p {
        font-size: 12px;
    }
}
.single_advisor_profile:hover .advisor_thumb::after,
.single_advisor_profile:focus .advisor_thumb::after {
    background-color: #070a57;
}
.single_advisor_profile:hover .single_advisor_details_info,
.single_advisor_profile:focus .single_advisor_details_info {
    background-color: #070a57;
}
.single_advisor_profile:hover .single_advisor_details_info::after,
.single_advisor_profile:focus .single_advisor_details_info::after {
    background-color: #ffffff;
}
.single_advisor_profile:hover .single_advisor_details_info h6,
.single_advisor_profile:focus .single_advisor_details_info h6 {
    color: #ffffff;
}
.single_advisor_profile:hover .single_advisor_details_info p,
.single_advisor_profile:focus .single_advisor_details_info p {
    color: #ffffff;
}

.spin {
    width: 3rem; height: 3rem;
}
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

ReactJS Python Flask AutoComplete Textbox | Filter Search | SQLAlchemy Mysql

ReactJS Python Flask AutoComplete Textbox | Filter Search | SQLAlchemy Mysql

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

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\flaskreact>pip install -U Flask-SQLAlchemy
C:\flask_dev\flaskreact\app.py

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

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

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors

C:\flask_dev\flaskreact\app.py

 
#C:\flask_dev\flaskreact\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
 
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:''@localhost/flaskreact'
 
db.init_app(app)
   
with app.app_context():
    db.create_all()
 
ma=Marshmallow(app)
  
class CountriesSchema(ma.Schema):
    class Meta:
        fields = ('ID','countryName')
          
countries_schema = CountriesSchema(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)
C:\flask_dev\flaskreact\models.py
 
#C:\flask_dev\flaskreact\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)
run (venv) C:\flask_dev\flaskreact>flask run
http://127.0.0.1:5000/listall

React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js
//C:\react-js\myreactdev\src\App.js
import React, { useState, useEffect } from "react";
import "./App.css";
 
function App() {

  const [allcountry, setAllcountry] = useState([]);
  const [filterresult, setFilterresult] = useState([]);
  const [serachcountry, setSearchcountry] = useState("");
 
  const handlesearch = (event) => {
    const search = event.target.value;
    console.log(search);
    setSearchcountry(search);
 
    if (search !== "") {
      const filterdata = allcountry.filter((item) => {
        return Object.values(item)
          .join("")
          .toLowerCase()
          .includes(search.toLowerCase());
      });
      setFilterresult(filterdata);
    } else {
      setFilterresult(allcountry);
    }
  };
 
  useEffect(() => {
    const getcountry = async () => {
      const getres = await fetch("http://127.0.0.1:5000/listall");
      const setcounty = await getres.json();
      console.log(setcounty);
      setAllcountry(await setcounty);
    };
    getcountry();
  }, []);
 
  return (
      <div className="container">
        <div className="row"><p><h3>ReactJS Python Flask AutoComplete Textbox | Filter Search | SQLAlchemy Mysql</h3></p>
          <div className="col-md-6 mb-3 mt-3">
            <input
              type="text"
              className="form-control"
              placeholder="Enter Keyword"
              onChange={(e) => {
                handlesearch(e);
              }}
            />
            <table className="table table-bordered table-striped">
              <thead>
                <tr>
                  <th>Country ID </th>
                  <th>Country Name</th>
                </tr>
              </thead>
              <tbody>
                {serachcountry.length > 1
                  ? filterresult.map((filtercountry, index) => (
                      <tr key={index}>
                        <td> {filtercountry.ID} </td>
                        <td> {filtercountry.countryName} </td>
                      </tr>
                    ))
                  : allcountry.map((getcon, index) => (
                      <tr key={index}>
                        <td> {getcon.ID} </td>
                        <td> {getcon.countryName} </td>
                      </tr>
                    ))}
              </tbody>
            </table>
          </div>
        </div>
      </div>
  );
}

export default App;
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Tuesday, April 25, 2023

ReactJS Python Flask Click Load More Results | SQLAlchemy Mysql

ReactJS Python Flask Click Load More Results | SQLAlchemy Mysql

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

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\flaskreact>pip install -U Flask-SQLAlchemy

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors

C:\flask_dev\flaskreact\app.py
#>C:\flask_dev\flaskreact\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, User

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:''@localhost/flaskreact'

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('/users/<int:page>/<int:per_page>', methods=['GET'])
def posts(page=1, per_page=10):
 
    total = User.query.count()
    print(total)
 
    posts = User.query.order_by(User.id.asc())  
    posts = posts.paginate(page=page, per_page=per_page)
 
    return jsonify({
        'total': total,
        'page': page,
        'per_page': per_page,
        'has_next': posts.has_next,
        'has_prev': posts.has_prev,
        'page_list': [iter_page if iter_page else '...' for iter_page in posts.iter_pages()],
        'data': [{
            'id': p.id,
            'fullname': p.name,
            'email': p.email,
            'password': p.password,
            'photo': p.photo
        } for p in posts.items]
    })

if __name__ == "__main__":
    app.run(debug=True)
C:\flask_dev\flaskreact\models.py
#C:\flask_dev\flaskreact\models.py
from flask_sqlalchemy import SQLAlchemy
from uuid import uuid4
  
db = SQLAlchemy()
  
def get_uuid():
    return uuid4().hex
  
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.String(11), primary_key=True, unique=True, default=get_uuid)
    name = db.Column(db.String(150), unique=True)
    email = db.Column(db.String(150), unique=True)
    password = db.Column(db.Text, nullable=False)
    photo = db.Column(db.String(150), unique=True)
run (venv) C:\flask_dev\flaskreact>flask run
http://127.0.0.1:5000/users/1/4

users.sql : https://github.com/cairocodes/cairocoders/blob/main/users.sql

React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js
//C:\react-js\myreactdev\src\App.js
import React, { useEffect, useState } from 'react';
import "./App.css";
 
function App() {
  const perPage = 4;
  const [totalPages, setTotalPages] = useState(1);
  const [page, setPage] = useState(1);
 
  const [userList, setUserList] = useState([]);
  const [loading, setLoading] = useState(false);
 
  useEffect(() => {
    const getUserList = () => {
		setLoading(true);
		fetch(`http://127.0.0.1:5000/users/${page}/${perPage}`)
        .then(res => res.json())
        .then(res => {
          setTotalPages(res.total);
          setUserList([...userList, ...res.data]);
          setLoading(false);
        });
    }
    getUserList();
  }, [page]);
 
  return (
	<div className="container">
        <div className="row justify-content-center">
          <div className="col-12 col-sm-8 col-lg-6">
            <div className="section_heading text-center wow fadeInUp">
              <h3>ReactJS Python Flask Click Load More Results | SQLAlchemy Mysql</h3>
              <div className="line"></div>
            </div>
          </div>
        </div>
        <div className="row" style={{padding: 20}}>
			{userList.map((x, i) => {
			return <div key={i} className="col-12 col-sm-6 col-lg-3">
				<div className="single_advisor_profile wow fadeInUp">
				  <div className="advisor_thumb"> <img alt="pic" src={x.photo} width="315" height="315"/></div>
				  <div className="single_advisor_details_info">
					<h6>{x.fullname}</h6>
					<p className="designation">{x.email}</p>
				  </div>
				</div>
			</div>
			
            })}
            <div className="clearfix"></div>
            {totalPages !== page && <button className="btn btn-primary" onClick={() => setPage(page + 1)}>{loading ? 'Loading...' : 'Load More'}</button>}
        </div>
		
    </div>
  );
}
 
export default App;
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
react-js\myreactdev\src\App.css
//react-js\myreactdev\src\App.css
 body{margin-top:20px;
background:#eee;
}
.single_advisor_profile {
    position: relative;
    margin-bottom: 50px;
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    z-index: 1;
    border-radius: 15px;
    -webkit-box-shadow: 0 0.25rem 1rem 0 rgba(47, 91, 234, 0.125);
    box-shadow: 0 0.25rem 1rem 0 rgba(47, 91, 234, 0.125);
}
.single_advisor_profile .advisor_thumb {
    position: relative;
    z-index: 1;
    border-radius: 15px 15px 0 0;
    margin: 0 auto;
    padding: 30px 30px 0 30px;
    background-color: #3f43fd;
    overflow: hidden;
}
.single_advisor_profile .advisor_thumb::after {
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    position: absolute;
    width: 150%;
    height: 80px;
    bottom: -45px;
    left: -25%;
    content: "";
    background-color: #ffffff;
    -webkit-transform: rotate(-15deg);
    transform: rotate(-15deg);
}
@media only screen and (max-width: 575px) {
    .single_advisor_profile .advisor_thumb::after {
        height: 160px;
        bottom: -90px;
    }
}
.single_advisor_profile .single_advisor_details_info {
    position: relative;
    z-index: 1;
    padding: 30px;
    text-align: right;
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    border-radius: 0 0 15px 15px;
    background-color: #ffffff;
}
.single_advisor_profile .single_advisor_details_info::after {
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    position: absolute;
    z-index: 1;
    width: 50px;
    height: 3px;
    background-color: #3f43fd;
    content: "";
    top: 12px;
    right: 30px;
}
.single_advisor_profile .single_advisor_details_info h6 {
    margin-bottom: 0.25rem;
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
}
@media only screen and (min-width: 768px) and (max-width: 991px) {
    .single_advisor_profile .single_advisor_details_info h6 {
        font-size: 14px;
    }
}
.single_advisor_profile .single_advisor_details_info p {
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    margin-bottom: 0;
    font-size: 14px;
}
@media only screen and (min-width: 768px) and (max-width: 991px) {
    .single_advisor_profile .single_advisor_details_info p {
        font-size: 12px;
    }
}
.single_advisor_profile:hover .advisor_thumb::after,
.single_advisor_profile:focus .advisor_thumb::after {
    background-color: #070a57;
}
.single_advisor_profile:hover .single_advisor_details_info,
.single_advisor_profile:focus .single_advisor_details_info {
    background-color: #070a57;
}
.single_advisor_profile:hover .single_advisor_details_info::after,
.single_advisor_profile:focus .single_advisor_details_info::after {
    background-color: #ffffff;
}
.single_advisor_profile:hover .single_advisor_details_info h6,
.single_advisor_profile:focus .single_advisor_details_info h6 {
    color: #ffffff;
}
.single_advisor_profile:hover .single_advisor_details_info p,
.single_advisor_profile:focus .single_advisor_details_info p {
    color: #ffffff;
}
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Monday, April 24, 2023

ReactJS Python Flask Registration with Form Validation | SQLAlchemy | Formik

ReactJS Python Flask Registration with Form Validation | SQLAlchemy | Formik

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

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\flaskreact>pip install -U Flask-SQLAlchemy

Flask-Bcrypt
Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application.
https://pypi.org/project/Flask-Bcrypt/

(venv) PS C:\flask_dev\flaskreact>pip install Flask-Bcrypt

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors

C:\flask_dev\flaskreact\app.py
#C:\flask_dev\flaskreact\app.py
from flask import Flask, request, jsonify
from flask_bcrypt import Bcrypt #pip install Flask-Bcrypt = https://pypi.org/project/Flask-Bcrypt/
from flask_cors import CORS, cross_origin #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors
from models import db, User
 
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'] = 'sqlite:///flaskdb.db'

SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = True
  
bcrypt = Bcrypt(app) 
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("/signup", methods=["POST"])
def signup():
    fullname = request.json["fullname"]
    username = request.json["username"]
    email = request.json["email"]
    password = request.json["password"]
 
    user_exists = User.query.filter_by(email=email).first() is not None
 
    if user_exists:
        return jsonify({"error": "Email already exists"}), 409
     
    hashed_password = bcrypt.generate_password_hash(password)
    new_user = User(fullname=fullname, username=username, email=email, password=hashed_password)
    db.session.add(new_user)
    db.session.commit()
 
    return jsonify({
        "id": new_user.id,
        "email": new_user.email
    })
 
if __name__ == "__main__":
    app.run(debug=True)
C:\flask_dev\flaskreact\models.py
#C:\flask_dev\flaskreact\models.py
from flask_sqlalchemy import SQLAlchemy
from uuid import uuid4
 
db = SQLAlchemy()
 
def get_uuid():
    return uuid4().hex
 
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.String(11), primary_key=True, unique=True, default=get_uuid)
    fullname = db.Column(db.String(150), unique=True)
    username = db.Column(db.String(150), unique=True)
    email = db.Column(db.String(150), unique=True)
    password = db.Column(db.Text, nullable=False)
Postman
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
https://www.postman.com/

run (venv) C:\flask_dev\flaskreact>flask run
http://127.0.0.1:5000/signup

React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev

Install Formik
npm install formik yup
C:\reactdev\myreactdev>npm install formik yup

https://github.com/axios/axios

Installing the Axios Client
$ npm install axios

C:\reactdev\myreactdev>npm install axios

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js

//C:\react-js\myreactdev\src\App.js
import React from 'react';
import "./App.css";
import { Formik, Field, Form, ErrorMessage } from 'formik';
import * as Yup from 'yup';
import axios from 'axios';
 
class App extends React.Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
 
    handleSubmit(data) {
        axios.post('http://127.0.0.1:5000/signup', {
            fullname: data.fullname,
            username: data.username,
            email: data.email,
            password: data.password
        })
        .then(function (response) {
            //handle success
            console.log(response)
            alert('New User Successfully Added.');  
            window.location.href = '/';
        })
        .catch(function (response) {
            //handle error
            console.log(response)
            if (response.status === 400) {
                alert("Invalid credentials");
            }
        });
    }
 
    validationSchema() {
        return Yup.object().shape({
          fullname: Yup.string().required('Fullname is required'),
          username: Yup.string()
            .required('Username is required')
            .min(6, 'Username must be at least 6 characters')
            .max(20, 'Username must not exceed 20 characters'),
          email: Yup.string()
            .required('Email is required')
            .email('Email is invalid'),
          password: Yup.string()
            .required('Password is required')
            .min(6, 'Password must be at least 6 characters')
            .max(40, 'Password must not exceed 40 characters'),
          confirmPassword: Yup.string()
            .required('Confirm Password is required')
            .oneOf([Yup.ref('password'), null], 'Confirm Password does not match'),
          acceptTerms: Yup.bool().oneOf([true], 'Accept Terms is required'),
        });
    }
 
    render() {
        const initialValues = {
            fullname: '',
            username: '',
            email: '',
            password: '',
            confirmPassword: '',
            acceptTerms: false,
        };
 
        return (
            <div className="container" style={{padding: 20}}>
            <div className="register-form"><h1>ReactJS Python Flask Registration with Form Validation | SQLAlchemy | Formik</h1>
              <Formik
                initialValues={initialValues}
                validationSchema={this.validationSchema}
                onSubmit={this.handleSubmit}>
 
                {({ resetForm }) => (
                  <Form>
                    <div className="form-group">
                      <label>Full Name</label>
                      <Field name="fullname" type="text" className="form-control"/>
                      <ErrorMessage name="fullname" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group">
                      <label htmlFor="username"> Username </label>
                      <Field name="username" type="text" className="form-control" />
                      <ErrorMessage name="username" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group">
                      <label htmlFor="email"> Email </label>
                      <Field name="email" type="email" className="form-control" />
                      <ErrorMessage name="email" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group">
                      <label htmlFor="password"> Password </label>
                      <Field name="password" type="password" className="form-control"/>
                      <ErrorMessage name="password" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group">
                      <label htmlFor="confirmPassword"> Confirm Password </label>
                      <Field name="confirmPassword" type="password" className="form-control"/>
                      <ErrorMessage name="confirmPassword" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group form-check"><br/>
                      <Field name="acceptTerms" type="checkbox" className="form-check-input"/>
                      <label htmlFor="acceptTerms" className="form-check-label">
                        I have read and agree to the Terms
                      </label>
                      <ErrorMessage name="acceptTerms" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group">
                      <button type="submit" className="btn btn-primary">
                        Register
                      </button>
                      <button type="button" onClick={resetForm} className="btn btn-warning">
                        Reset
                      </button>
                    </div>
                  </Form>
                )}
              </Formik>
            </div>
            </div>
        );
    }
}      
export default App;
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

ReactJS Python Flask Pagination using react-paginate

ReactJS Python Flask Pagination using react-paginate

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

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\flaskreact>pip install -U Flask-SQLAlchemy
C:\flask_dev\flaskreact\app.py

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

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

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors

C:\flask_dev\flaskreact\app.py
//C:\flask_dev\flaskreact\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

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:''@localhost/flaskreact'

db.init_app(app)
  
with app.app_context():
    db.create_all()

ma=Marshmallow(app)
 
class CountriesSchema(ma.Schema):
    class Meta:
        fields = ('ID','countryName')
         
countries_schema = CountriesSchema(many=True)

@app.route("/")
def hello_world():
    return "Hello, World!" 

@app.route('/posts/<int:page>/<int:per_page>', methods=['GET'])
def posts(page=1, per_page=10):

    total = Countries.query.count()
    print(total)

    posts = Countries.query.order_by(Countries.ID.asc())  
    posts = posts.paginate(page=page, per_page=per_page)

    return jsonify({
        'total': total,
        'page': page,
        'per_page': per_page,
        'has_next': posts.has_next,
        'has_prev': posts.has_prev,
        'page_list': [iter_page if iter_page else '...' for iter_page in posts.iter_pages()],
        'posts': [{
            'id': p.ID,
            'title': p.countryName,
        } for p in posts.items]
    })
C:\flask_dev\flaskreact\models.py
 
#C:\flask_dev\flaskreact\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)
run (venv) C:\flask_dev\flaskreact>flask run
http://127.0.0.1:5000/posts/1/10

React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev

Install react-paginate
react-paginate A ReactJS component to render a pagination.
C:\react-js>npm install react-paginate --save

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js
//C:\react-js\myreactdev\src\App.js
import React, { useEffect, useState } from 'react';
import "./App.css";
import ReactPaginate from "react-paginate"; //npm install react-paginate --save = https://www.npmjs.com/package/react-paginate

function App() {

  const [items, setItems] = useState([]);

  const [pageCount, setpageCount] = useState(0);

  let limit = 10;

  useEffect(() => {
    const getPost = async () => {
      const res = await fetch(
         `http://127.0.0.1:5000/posts/1/${limit}`
      );
      const data = await res.json();
      //console.log(data.posts);
      const totalrec = data.total
      const total = totalrec;
      console.log(total);
      setpageCount(Math.ceil(total / limit));
      // console.log(Math.ceil(total/12));
      setItems(data.posts);
    };
 
    getPost();
  }, [limit]);

  const fetchPost = async (currentPage) => {
    const res = await fetch(
       `http://127.0.0.1:5000/posts/${currentPage}/${limit}`
    );
    const data = await res.json();
    return data.posts;
  };

  const handlePageClick = async (data) => {
    console.log(data.selected);
 
    let currentPage = data.selected + 1;
 
    const listpage = await fetchPost(currentPage);

    setItems(listpage);
  };

  return (
    <div className="container">
    <div className="container" style={{padding: 20}}>
      <h4 className="d-inline-block">ReactJS Python Flask Pagination using react-paginate</h4>
    </div>

      <table className="table table-striped">
          <thead className="thead-light ">
            <th>ID</th>
            <th>Country</th>
          </thead>
          <tbody>
          {items.map(row => <tr>
            <td>{row.id}</td>
              <td>{row.title}</td>
            </tr>)}
          </tbody>
        </table>

        <ReactPaginate
            previousLabel={"previous"}
            nextLabel={"next"}
            breakLabel={"..."}
            pageCount={pageCount}
            marginPagesDisplayed={2}
            pageRangeDisplayed={3}
            onPageChange={handlePageClick}
            containerClassName={"pagination justify-content-center"}
            pageClassName={"page-item"}
            pageLinkClassName={"page-link"}
            previousClassName={"page-item"}
            previousLinkClassName={"page-link"}
            nextClassName={"page-item"}
            nextLinkClassName={"page-link"}
            breakClassName={"page-item"}
            breakLinkClassName={"page-link"}
            activeClassName={"active"}
        />
    </div>
  );
}
 
export default App;
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Sunday, April 23, 2023

ReactJS Python Flask Pagination

ReactJS Python Flask Pagination

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

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\flaskreact>pip install -U Flask-SQLAlchemy
C:\flask_dev\flaskreact\app.py

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

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

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors

C:\flask_dev\flaskreact\app.py

 
#C:\flask_dev\flaskreact\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

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:''@localhost/flaskreact'

db.init_app(app)
  
with app.app_context():
    db.create_all()

ma=Marshmallow(app)
 
class CountriesSchema(ma.Schema):
    class Meta:
        fields = ('ID','countryName')
         
countries_schema = CountriesSchema(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)
C:\flask_dev\flaskreact\models.py
 
#C:\flask_dev\flaskreact\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)
run (venv) C:\flask_dev\flaskreact>flask run
http://127.0.0.1:5000/listall

React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev
Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js

//C:\react-js\myreactdev\src\App.js
import React, { useState, useEffect } from 'react';
import Pagination from './Pagination'
import axios from 'axios'
import './App.css';
 
function App() {
  const [countries, setCountries] = useState([])
  const [loading, setLoading] = useState(false)
  const [currentPage, setCurrentPage] = useState(1)
  const [CountriesPerPage] = useState(10) //10 Per Page
 
  useEffect(() => {
    const fetchPosts = async () => {
      setLoading(true)
      const res = await axios.get('http://127.0.0.1:5000/listall')
      setCountries(res.data)
      setLoading(false)
    }
 
    fetchPosts()
  }, [])
 
  if (loading && countries.length === 0) {
    return <h2>Loading...</h2>
  }
  //Get current countries
  const indexOfLastPost = currentPage * CountriesPerPage;
  const indexOfFirstPost = indexOfLastPost - CountriesPerPage;
  const CountriesList = countries.slice(indexOfFirstPost, indexOfLastPost)
  const howManyPages = Math.ceil(countries.length/CountriesPerPage)
   
  return (
    <div className="container" style={{padding: 20}}>
      <h4 className="d-inline-block">ReactJS Python Flask Pagination</h4>
 
      <table className="table table-striped">
          <thead className="thead-light ">
            <th>ID</th>
            <th>Country</th>
          </thead>
          <tbody>
          {CountriesList.map(row => <tr>
            <td>{row.ID}</td>
              <td>{row.countryName}</td>
            </tr>)}
          </tbody>
        </table>
 
      <Pagination pages = {howManyPages} setCurrentPage={setCurrentPage}/>
    </div>
  );
}
 
export default App;
Install React Router Dom
https://www.npmjs.com/package/react-router-dom
C:\react-js\myreactdev>npm i react-router-dom --save

Install Axios
https://www.npmjs.com/package/axios
C:\react-js\myreactdev>npm install axios --save

C:\react-js\myreactdev\src\Pagination.js
//C:\react-js\myreactdev\src\Pagination.js
import React, { useState, useEffect } from 'react';
 
function Pagination({ pages = 7, setCurrentPage }) {
 
  //Set number of pages
  const numberOfPages = []
  for (let i = 1; i <= pages; i++) {
    numberOfPages.push(i)
  }
 
  // Current active button number
  const [currentButton, setCurrentButton] = useState(1)
 
  // Array of buttons what we see on the page
  const [arrOfCurrButtons, setArrOfCurrButtons] = useState([])
 
  useEffect(() => {
    let tempNumberOfPages = [...arrOfCurrButtons]
 
    let dotsInitial = '...'
    let dotsLeft = '... '
    let dotsRight = ' ...'
 
    if (numberOfPages.length < 6) {
      tempNumberOfPages = numberOfPages
    }
 
    else if (currentButton >= 1 && currentButton <= 3) {
      tempNumberOfPages = [1, 2, 3, 4, dotsInitial, numberOfPages.length]
    }
 
    else if (currentButton === 4) {
      const sliced = numberOfPages.slice(0, 5)
      tempNumberOfPages = [...sliced, dotsInitial, numberOfPages.length]
    }
 
    else if (currentButton > 4 && currentButton < numberOfPages.length - 2) {               
      const sliced1 = numberOfPages.slice(currentButton - 2, currentButton)               
      const sliced2 = numberOfPages.slice(currentButton, currentButton + 1)                
      tempNumberOfPages = ([1, dotsLeft, ...sliced1, ...sliced2, dotsRight, numberOfPages.length]) 
    }
     
    else if (currentButton > numberOfPages.length - 3) {                
      const sliced = numberOfPages.slice(numberOfPages.length - 4)       
      tempNumberOfPages = ([1, dotsLeft, ...sliced])                        
    }
     
    else if (currentButton === dotsInitial) {
      setCurrentButton(arrOfCurrButtons[arrOfCurrButtons.length-3] + 1) 
    }
    else if (currentButton === dotsRight) {
      setCurrentButton(arrOfCurrButtons[3] + 2)
    }
 
    else if (currentButton === dotsLeft) {
      setCurrentButton(arrOfCurrButtons[3] - 2)
    }
 
    setArrOfCurrButtons(tempNumberOfPages)
    setCurrentPage(currentButton)
  }, [currentButton])
 
 
  return (
    <div className="pagination-container">
      <a
        href="!#"
        className={`${currentButton === 1 ? 'disabled' : ''}`}
        onClick={() => setCurrentButton(prev => prev <= 1 ? prev : prev - 1)}
      > 
        Prev
      </a>
 
      {arrOfCurrButtons.map(((item, index) => {
        return <a
          href="!#"
          key={index}
          className={`${currentButton === item ? 'active' : ''}`}
          onClick={() => setCurrentButton(item)}
        >
          {item}
        </a>
      }))}
 
      <a
        href="!#"
        className={`${currentButton === numberOfPages.length ? 'disabled' : ''}`}
        onClick={() => setCurrentButton(prev => prev >= numberOfPages.length ? prev : prev + 1)}
      >
        Next
      </a>
    </div>
  );
}
export default Pagination
react-js\myreactdev\src\App.css
//
body {
  margin: 0;
  background-color: #ffffff;
}

.pagination-container {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  font-weight: 500;
  font-size: 15px;
}
 
.pagination-container a {
  display: flex;
  justify-content: center;
  align-items: center;
  color: black;
  height: 40px;
  width: 40px;
  text-decoration: none;
  transition: background-color .2s;
  border: 1px solid #ddd;
  cursor: pointer;
   
}
 
.pagination-container a.active {
  background-color: #007bff;
  color: white;
  border: 1px solid #7cbddb;
}
 
.pagination-container a.disabled { 
  opacity: 0.2;
}
.pagination-container a:hover:not(.active) {background-color: rgb(238, 238, 238);}
react-js\myreactdev\public\index.html

//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Thursday, April 20, 2023

React-JS and Python Flask Multiple Image Upload with Show Uploaded Images

React-JS and Python Flask Multiple Image Upload with Show Uploaded Images

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

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\flaskreact>pip install -U Flask-SQLAlchemy
C:\flask_dev\flaskreact\app.py

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

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

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors
(venv) PS C:\flask_dev\flaskreact>pip install Werkzeug

C:\flask_dev\flaskreact\app.py

//C:\flask_dev\flaskreact\app.py
from flask import Flask, json, request, jsonify
import os
import urllib.request
from werkzeug.utils import secure_filename #pip install Werkzeug
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, Image

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:''@localhost/flaskreact'

db.init_app(app)
 
with app.app_context():
    db.create_all()

UPLOAD_FOLDER = 'static/uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024

ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

ma=Marshmallow(app)

class ImageSchema(ma.Schema):
    class Meta:
        fields = ('id','title')
        
image_schema = ImageSchema(many=True)

@app.route("/")
def hello_world():
    return "Hello, World!"

@app.route('/upload', methods=['POST'])
def upload_file():
    # check if the post request has the file part
    if 'files[]' not in request.files:
        resp = jsonify({
            "message": 'No file part in the request',
            "status": 'failed'
        })
        resp.status_code = 400
        return resp
 
    files = request.files.getlist('files[]')
     
    errors = {}
    success = False
     
    for file in files:      
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))

            newFile = Image(title=filename)
            db.session.add(newFile)
            db.session.commit()

            success = True
        else:
            resp = jsonify({
                "message": 'File type is not allowed',
                "status": 'failed'
            })
            return resp
        
    if success and errors:
        errors['message'] = 'File(s) successfully uploaded'
        errors['status'] = 'failed'
        resp = jsonify(errors)
        resp.status_code = 500
        return resp
    if success:
        resp = jsonify({
            "message": 'Files successfully uploaded',
            "status": 'successs'
        })
        resp.status_code = 201
        return resp
    else:
        resp = jsonify(errors)
        resp.status_code = 500
        return resp
    
@app.route('/images',methods =['GET'])
def images():
    all_images = Image.query.all()
    results = image_schema.dump(all_images)
    return jsonify(results)
C:\flask_dev\flaskreact\models.py
#C:\flask_dev\flaskreact\models.py
from flask_sqlalchemy import SQLAlchemy
  
db = SQLAlchemy()
  
class Image(db.Model):
    __tablename__ = "images"
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(120), index=True, unique=True)
Postman
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
https://www.postman.com/

upload
Post : http://127.0.0.1:5000/upload
Body - Form-data
Key : files[] - files
Value : select images

Create folder static\uploads

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

React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js

//C:\react-js\myreactdev\src\App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import ImageUpload from './components/ImageUpload';
import './App.css';
 
class App extends Component {
    render() {
      return (
        <Router>
            <Routes>
              <Route exact path="/upload-image" element={<ImageUpload/>}/>
            </Routes>
        </Router>
      );
    }
}
export default App;
Install React Router Dom
https://www.npmjs.com/package/react-router-dom
C:\react-js\myreactdev>npm i react-router-dom --save

Install Axios
https://www.npmjs.com/package/axios
C:\react-js\myreactdev>npm install axios --save

C:\react-js\myreactdev\src\components\ImageUpload.js
//C:\react-js\myreactdev\src\components\ImageUpload.js
import React, { Component } from "react";
import axios from "axios";
import Images from "./Image";
 
export default class ImageUpload extends Component {
  constructor(props) {
    super(props);
  
    this.state = {
      image: "",
      responseMsg: {
        status: "",
        message: "",
        error: "",
      },
    };
  }
  
  // image onchange hander
  handleChange = (e) => {
    const imagesArray = [];
  
    for (let i = 0; i < e.target.files.length; i++) {
      this.fileValidate(e.target.files[i]);
      imagesArray.push(e.target.files[i]);
    }
    this.setState({
      image: imagesArray,
    });
  };
  
  // submit handler
  submitHandler = (e) => {
    e.preventDefault();
    const data = new FormData(); 
    for (let i = 0; i < this.state.image.length; i++) {
      data.append("files[]", this.state.image[i]);
    }
  
    axios.post("http://127.0.0.1:5000/upload", data)
    .then((response) => {
            console.log(response)
        if (response.status === 201) {
          this.setState({
            responseMsg: {
              status: response.data.status,
              message: response.data.message,
            },
          });
          setTimeout(() => {
            this.setState({
              image: "",
              responseMsg: "",
            });
          }, 100000);
  
          document.querySelector("#imageForm").reset();
          // getting uploaded images
          this.refs.child.getImages();
        }
            alert("Successfully Uploaded");
    })
    .catch((error) => {
        console.error(error); 
        if (error.response) {
            console.log(error.response)
            if (error.response.status === 401) {
                alert("Invalid credentials");
            }
        }
    });
     
  };
  
  // file validation
  fileValidate = (file) => {
    if (
      file.type === "image/png" ||
      file.type === "image/jpg" ||
      file.type === "image/jpeg"
    ) {
      this.setState({
        responseMsg: {
          error: "",
        },
      });
      return true;
    } else {
      this.setState({
        responseMsg: {
          error: "File type allowed only jpg, png, jpeg",
        },
      });
      return false;
    }
  };
  
  render() {
    return (
      <div className="container py-5">
        <div className="row">
          <div className="col-lg-12">
            <form onSubmit={this.submitHandler} encType="multipart/form-data" id="imageForm">
              <div className="card shadow">
  
                {this.state.responseMsg.status === "successs" ? (
                  <div className="alert alert-success">
                    {this.state.responseMsg.message}
                  </div>
                ) : this.state.responseMsg.status === "failed" ? (
                  <div className="alert alert-danger">
                    {this.state.responseMsg.message}
                  </div>
                ) : (
                  ""
                )}
                <div className="card-header">
                  <h4 className="card-title fw-bold">
                    React-JS and Python Flask Multiple Image Upload with Show Uploaded Images
                  </h4>
                </div>
  
                <div className="card-body">
                  <div className="form-group py-2">
                    <label htmlFor="images">Images</label>
                    <input
                      type="file"
                      name="image"
                      multiple
                      onChange={this.handleChange}
                      className="form-control"
                    />
                    <span className="text-danger">
                      {this.state.responseMsg.error}
                    </span>
                  </div>
                </div>
  
                <div className="card-footer">
                  <button type="submit" className="btn btn-success">
                    Upload
                  </button>
                </div>
              </div>
            </form>
          </div>
        </div>
  
		<Images ref="child" />
      </div>
    );
  }
}
C:\react-js\myreactdev\src\components\Image.js
//C:\react-js\myreactdev\src\components\Image.js
import React, { Component } from "react";
import axios from "axios";
 
export default class Images extends Component {
  constructor(props) {
    super(props);
 
    this.state = {
      title: [],
    };
  }
 
  componentDidMount() {
    this.getImages();
  }
 
  getImages = () => {
    axios
      .get("http://127.0.0.1:5000/images")
      .then((response) => {
        if (response.status === 200) {
          this.setState({
            title: response.data,
          });
          console.log(response.data);
        }
      })
      .catch((error) => {
        console.error(error);
      });
  };
 
  render() {
    return (
      <div className="container pt-4">
        <div className="row">
          <div className="col-lg-12">
            <div className="card shadow">
              <div className="card-header">
                <h4 className="card-title fw-bold"> Images List </h4>
              </div>
              <div className="card-body">
                <div className="row">
 
                  {
                    this.state.title.length > 0 ? (
                        this.state.title.map((image) => (
                        <div className="col-lg-3" key={image.id}>
                            <img src={ "http://127.0.0.1:5000/static/uploads/" + image.title } className="img-fluid img-bordered" width="200px"
                            />
                        </div>
                        ))
                    ) : (
                        <h6 className="text-danger text-center">No Image Found </h6>
                    )
                  }
 
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Wednesday, April 19, 2023

React-JS and Python Flask Multiple Image Upload with validation

React-JS and Python Flask Multiple Image Upload with validation

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors
(venv) PS C:\flask_dev\flaskreact>pip install Werkzeug

C:\flask_dev\flaskreact\app.py

 
#C:\flask_dev\flaskreact\app.py
from flask import Flask, json, request, jsonify
import os
import urllib.request
from werkzeug.utils import secure_filename #pip install Werkzeug
from flask_cors import CORS #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors

app = Flask(__name__)
CORS(app, supports_credentials=True)

app.secret_key = "caircocoders-ednalan"
 
UPLOAD_FOLDER = 'static/uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
 
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
 
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
 
@app.route('/')
def main():
    return 'Homepage'
 
@app.route('/upload', methods=['POST'])
def upload_file():
    # check if the post request has the file part
    if 'files[]' not in request.files:
        resp = jsonify({
            "message": 'No file part in the request',
            "status": 'failed'
        })
        resp.status_code = 400
        return resp
 
    files = request.files.getlist('files[]')
     
    errors = {}
    success = False
     
    for file in files:      
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            success = True
        else:
            resp = jsonify({
                "message": 'File type is not allowed',
                "status": 'failed'
            })
            return resp
        
    if success and errors:
        errors['message'] = 'File(s) successfully uploaded'
        errors['status'] = 'failed'
        resp = jsonify(errors)
        resp.status_code = 500
        return resp
    if success:
        resp = jsonify({
            "message": 'Files successfully uploaded',
            "status": 'successs'
        })
        resp.status_code = 201
        return resp
    else:
        resp = jsonify(errors)
        resp.status_code = 500
        return resp

if __name__ == '__main__':
    app.run(debug=True)
Postman
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
https://www.postman.com/

upload
Post : http://127.0.0.1:5000/upload
Body - Form-data
Key : files[] - files
Value : select images

Create folder static\uploads

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

React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js
//C:\react-js\myreactdev\src\App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import ImageUpload from './components/ImageUpload';
import './App.css';

class App extends Component {
    render() {
      return (
        <Router>
            <Routes>
              <Route exact path="/upload-image" element={<ImageUpload/>}/>
            </Routes>
        </Router>
      );
    }
}
export default App;
Install React Router Dom
https://www.npmjs.com/package/react-router-dom
C:\react-js\myreactdev>npm i react-router-dom --save

Install Axios
https://www.npmjs.com/package/axios
C:\react-js\myreactdev>npm install axios --save

C:\react-js\myreactdev\src\components\ImageUpload.js

//C:\react-js\myreactdev\src\components\ImageUpload.js
import React, { Component } from "react";
import axios from "axios";

export default class ImageUpload extends Component {
  constructor(props) {
    super(props);
 
    this.state = {
      image: "",
      responseMsg: {
        status: "",
        message: "",
        error: "",
      },
    };
  }
 
  // image onchange hander
  handleChange = (e) => {
    const imagesArray = [];
 
    for (let i = 0; i < e.target.files.length; i++) {
      this.fileValidate(e.target.files[i]);
      imagesArray.push(e.target.files[i]);
    }
    this.setState({
      image: imagesArray,
    });
  };
 
  // submit handler
  submitHandler = (e) => {
    e.preventDefault();
    const data = new FormData(); 
    for (let i = 0; i < this.state.image.length; i++) {
      data.append("files[]", this.state.image[i]);
    }
 
    axios.post("http://127.0.0.1:5000/upload", data)
    .then((response) => {
		    console.log(response)
        if (response.status === 201) {
          this.setState({
            responseMsg: {
              status: response.data.status,
              message: response.data.message,
            },
          });
          setTimeout(() => {
            this.setState({
              image: "",
              responseMsg: "",
            });
          }, 100000);
 
          document.querySelector("#imageForm").reset();
        }
		    alert("Successfully Uploaded");
    })
    .catch((error) => {
        console.error(error); 
        if (error.response) {
            console.log(error.response)
            if (error.response.status === 401) {
                alert("Invalid credentials");
            }
        }
    });
	
  };
 
  // file validation
  fileValidate = (file) => {
    if (
      file.type === "image/png" ||
      file.type === "image/jpg" ||
      file.type === "image/jpeg"
    ) {
      this.setState({
        responseMsg: {
          error: "",
        },
      });
      return true;
    } else {
      this.setState({
        responseMsg: {
          error: "File type allowed only jpg, png, jpeg",
        },
      });
      return false;
    }
  };
 
  render() {
    return (
      <div className="container py-5">
        <div className="row">
          <div className="col-lg-12">
            <form onSubmit={this.submitHandler} encType="multipart/form-data" id="imageForm">
              <div className="card shadow">
 
                {this.state.responseMsg.status === "successs" ? (
                  <div className="alert alert-success">
                    {this.state.responseMsg.message}
                  </div>
                ) : this.state.responseMsg.status === "failed" ? (
                  <div className="alert alert-danger">
                    {this.state.responseMsg.message}
                  </div>
                ) : (
                  ""
                )}
                <div className="card-header">
                  <h4 className="card-title fw-bold">
                    React-JS and Python Flask Multiple Image Upload with validation
                  </h4>
                </div>
 
                <div className="card-body">
                  <div className="form-group py-2">
                    <label htmlFor="images">Images</label>
                    <input
                      type="file"
                      name="image"
                      multiple
                      onChange={this.handleChange}
                      className="form-control"
                    />
                    <span className="text-danger">
                      {this.state.responseMsg.error}
                    </span>
                  </div>
                </div>
 
                <div className="card-footer">
                  <button type="submit" className="btn btn-success">
                    Upload
                  </button>
                </div>
              </div>
            </form>
          </div>
        </div>
 
      </div>
    );
  }
}
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Tuesday, April 18, 2023

React-JS and Python Flask Login Token Authentication flask_jwt_extended with Profile | SQLAlchemy.

React-JS and Python Flask Login Token Authentication flask_jwt_extended with Profile | SQLAlchemy.

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

Flask-JWT-Extended
Flask-JWT-Extended not only adds support for using JSON Web Tokens (JWT) to Flask for protecting routes, but also many helpful (and optional) features built in to make working with JSON Web Tokens easier.
https://pypi.org/project/Flask-JWT-Extended/

(venv) PS C:\flask_dev\flaskreact>pip install Flask-JWT-Extended

Flask-Bcrypt
Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application.
https://pypi.org/project/Flask-Bcrypt/

(venv) PS C:\flask_dev\flaskreact>pip install Flask-Bcrypt

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\flaskreact>pip install -U Flask-SQLAlchemy
C:\flask_dev\flaskreact\app.py

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors

C:\flask_dev\flaskreact\app.py

#C:\flask_dev\flaskreact\app.py
import json
from flask import Flask, request, jsonify
from datetime import datetime, timedelta, timezone
from flask_jwt_extended import create_access_token,get_jwt,get_jwt_identity, unset_jwt_cookies, jwt_required, JWTManager #pip install Flask-JWT-Extended = https://pypi.org/project/Flask-JWT-Extended/
from flask_bcrypt import Bcrypt #pip install Flask-Bcrypt = https://pypi.org/project/Flask-Bcrypt/
from flask_cors import CORS #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors

from models import db, User

api = Flask(__name__)
CORS(api, supports_credentials=True)

api.config['SECRET_KEY'] = 'cairocoders-ednalan'
api.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flaskdb.db'
# Databse configuration  Mysql                            Username:password@hostname/databasename
#app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:''@localhost/flaskreact'

api.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=1)
jwt = JWTManager(api)

SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = True

bcrypt = Bcrypt(api)    
db.init_app(api)
 
with api.app_context():
    db.create_all()

@api.route("/")
def hello_world():
    return "<p>Hello, World!</p>"

@api.route('/logintoken', methods=["POST"])
def create_token():
    email = request.json.get("email", None)
    password = request.json.get("password", None)
 
    user = User.query.filter_by(email=email).first()
    #if email != "test" or password != "test":
    #    return {"msg": "Wrong email or password"}, 401
    if user is None:
        return jsonify({"error": "Wrong email or passwords"}), 401
     
    if not bcrypt.check_password_hash(user.password, password):
        return jsonify({"error": "Unauthorized"}), 401
     
    access_token = create_access_token(identity=email)
    #response = {"access_token":access_token}
 
    return jsonify({
        "email": email,
        "access_token": access_token
    })
    #return response

@api.route("/signup", methods=["POST"])
def signup():
    email = request.json["email"]
    password = request.json["password"]
  
    user_exists = User.query.filter_by(email=email).first() is not None
  
    if user_exists:
        return jsonify({"error": "Email already exists"}), 409
      
    hashed_password = bcrypt.generate_password_hash(password)
    new_user = User(name="cairocoders Ednalan", email=email, password=hashed_password, about="sample about me")
    db.session.add(new_user)
    db.session.commit()
  
    return jsonify({
        "id": new_user.id,
        "email": new_user.email
    })

@api.after_request
def refresh_expiring_jwts(response):
    try:
        exp_timestamp = get_jwt()["exp"]
        now = datetime.now(timezone.utc)
        target_timestamp = datetime.timestamp(now + timedelta(minutes=30))
        if target_timestamp > exp_timestamp:
            access_token = create_access_token(identity=get_jwt_identity())
            data = response.get_json()
            if type(data) is dict:
                data["access_token"] = access_token 
                response.data = json.dumps(data)
        return response
    except (RuntimeError, KeyError):
        # Case where there is not a valid JWT. Just return the original respone
        return response

@api.route("/logout", methods=["POST"])
def logout():
    response = jsonify({"msg": "logout successful"})
    unset_jwt_cookies(response)
    return response

@api.route('/profile/<getemail>')
@jwt_required() 
def my_profile(getemail):
    print(getemail)
    if not getemail:
        return jsonify({"error": "Unauthorized Access"}), 401
      
    user = User.query.filter_by(email=getemail).first()
 
    response_body = {
        "id": user.id,
        "name": user.name,
        "email": user.email,
        "about" : user.about
    }
 
    return response_body
C:\flask_dev\flaskreact\models.py
#C:\flask_dev\flaskreact\models.py
from flask_sqlalchemy import SQLAlchemy
from uuid import uuid4
 
db = SQLAlchemy()
 
def get_uuid():
    return uuid4().hex
 
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.String(11), primary_key=True, unique=True, default=get_uuid)
    name = db.Column(db.String(150), unique=True)
    email = db.Column(db.String(150), unique=True)
    password = db.Column(db.Text, nullable=False)
    about = db.Column(db.Text, nullable=False)
Postman
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
https://www.postman.com/

Login
Post : http://127.0.0.1:5000/logintoken
Body - row - json
{
"email":"cairocoders@gmail.com",
"password":"123456"
}
Sign Up
Post : http://127.0.0.1:5000/signup
Body - row - json
{
"email":"cairocoders@gmail.com",
"password":"123456"
}
Profile
Get : http://127.0.0.1:5000/profile/cairocoders@gmail.com

Headers :
Key : Authorization
value : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTY

Log Out
Get : http://127.0.0.1:5000/logout

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

React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js
//C:\react-js\myreactdev\src\App.js
import React, { } from 'react';
import './App.css';
  
import {BrowserRouter, Routes, Route} from 'react-router-dom';

import Login from './components/Login'
import Header from './components/Header'
import Profile from './components/Profile'
import useToken from './components/useToken'

function App() {
	
	const { token, removeToken, setToken } = useToken();
	
	return (
		<div className="vh-100 gradient-custom">
		<div className="container">
		  <h1 className="page-header text-center">React-JS and Python Flask Login Token Authentication flask_jwt_extended with Profile | SQLAlchemy.</h1>
			
		  <BrowserRouter>
			<Header token={removeToken}/>
			{!token && token!=="" &&token!== undefined?  
			<Login setToken={setToken} />
			:(
			  <>
				<Routes>
				  <Route exact path="/profile" element={<Profile token={token} setToken={setToken}/>}></Route>
				</Routes>
			  </>
			)}
		  </BrowserRouter>
		</div>
		</div>
	);
}
    
export default App;
Install React Router Dom
https://www.npmjs.com/package/react-router-dom
C:\react-js\myreactdev>npm i react-router-dom --save

Install Axios
https://www.npmjs.com/package/axios
C:\react-js\myreactdev>npm install axios --save

C:\react-js\myreactdev\src\components\Login.js
//C:\react-js\myreactdev\src\components\Login.js
import React, { useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";

function Login(props) {
     
    const [loginForm, setloginForm] = useState({
      email: "",
      password: ""
    })

	const navigate = useNavigate();
	
    function btnlogin(event) {
		axios({
			method: "POST",
			url:"http://127.0.0.1:5000/logintoken",
			data:{
			  email: loginForm.email,
			  password: loginForm.password
			 }
		})
		.then((response) => {
			console.log(response)
			props.setToken(response.data.access_token)
			alert("Successfully Login");
			localStorage.setItem('email', loginForm.email)
			navigate('/profile');
		}).catch((error) => {
			if (error.response) {
			  console.log(error.response)
			  console.log(error.response.status)
			  console.log(error.response.headers)
				if (error.response.status === 401) {
                    alert("Invalid credentials");
                }
			}
		})

		setloginForm(({
			email: "",
			password: ""}))

		event.preventDefault()
    }

    function handleChange(event) { 
      const {value, name} = event.target
      setloginForm(prevNote => ({
          ...prevNote, [name]: value})
      )}

    let imgs = [
      'https://as1.ftcdn.net/v2/jpg/03/39/70/90/1000_F_339709048_ZITR4wrVsOXCKdjHncdtabSNWpIhiaR7.jpg',
    ];
	
    return (
    <div>
        <div className="container h-50">
          <div className="container-fluid h-custom">
            <div className="row d-flex justify-content-center align-items-center h-50">
              <div className="col-md-9 col-lg-6 col-xl-5">
                <img src={imgs[0]} className="img-fluid"/>
              </div>
              <div className="col-md-8 col-lg-6 col-xl-4 offset-xl-1">
                <form>
                  <div className="d-flex flex-row align-items-center justify-content-center justify-content-lg-start">
                    <p className="lead fw-normal mb-0 me-3">Log Into Your Account</p>
                  </div>
 
                  <div className="form-outline mb-4">
                    <input type="email" value={loginForm.email} onChange={handleChange} text={loginForm.email} name="email" id="form3Example3" className="form-control form-control-lg" placeholder="Enter a valid email address" />
                    <label className="form-label" for="form3Example3">Email address</label>
                  </div>
 
             
                  <div className="form-outline mb-3">
                    <input type="password" value={loginForm.password} onChange={handleChange} text={loginForm.password} name="password" id="form3Example4" className="form-control form-control-lg" placeholder="Enter password" />
                    <label className="form-label" for="form3Example4">Password</label>
                  </div>
 
                  <div className="d-flex justify-content-between align-items-center">
                    <div className="form-check mb-0">
                      <input className="form-check-input me-2" type="checkbox" value="" id="form2Example3" />
                      <label className="form-check-label" for="form2Example3">
                        Remember me
                      </label>
                    </div>
                    <a href="#!" className="text-body">Forgot password?</a>
                  </div>
 
                  <div className="text-center text-lg-start mt-4 pt-2">
                    <button type="button" className="btn btn-primary btn-lg" onClick={btnlogin} >Login</button>
                    <p className="small fw-bold mt-2 pt-1 mb-0">Don't have an account? <a href="/register" className="link-danger">Register</a></p>
                  </div>
 
                </form>
              </div>
            </div>
          </div>
        </div>
    </div>
  );
  
}
export default Login;
C:\react-js\myreactdev\src\components\Header.js
//C:\react-js\myreactdev\src\components\Header.js
import React, { } from "react";
import axios from "axios";
import {useNavigate} from "react-router-dom";

function Header(props) {

	const navigate = useNavigate();
	
	function logMeOut() {
		axios({
			method: "POST",
			url:"http://127.0.0.1:5000/logout",
		})
		.then((response) => {
			props.token()
			localStorage.removeItem('email')
			navigate("/");
		}).catch((error) => {
			if (error.response) {
				console.log(error.response)
				console.log(error.response.status)
				console.log(error.response.headers)
			}
		})
	}
	
	const logged = localStorage.getItem('email');
	
    return(
		<nav className="navbar navbar-expand-lg bg-light">
		  <div className="container-fluid">
			<a className="navbar-brand" href="#">Cairocoders</a>
			<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
			  <span className="navbar-toggler-icon"></span>
			</button>
			<div className="collapse navbar-collapse" id="navbarSupportedContent">
			  <ul className="navbar-nav me-auto mb-2 mb-lg-0">
				<li className="nav-item">
				  <a className="nav-link active" aria-current="page" href="#">Home</a>
				</li>
				<li className="nav-item">
				  <a className="nav-link" href="#">About</a>
				</li>
			  </ul>
				{!logged?
					<button className="btn btn-outline-success" type="submit">Login</button>
				:<button className="btn btn-outline-danger" type="submit" onClick={logMeOut}>Logout</button>}
			</div>
		  </div>
		</nav>
    )
}

export default Header;
C:\react-js\myreactdev\src\components\useToken.js
//C:\react-js\myreactdev\src\components\useToken.js
import { useState } from 'react';

function useToken() {

  function getToken() {
    const userToken = localStorage.getItem('token'); //https://javascript.info/localstorage
    return userToken && userToken
  }

  const [token, setToken] = useState(getToken());

  function saveToken(userToken) {
    localStorage.setItem('token', userToken);
    setToken(userToken);
  };

  function removeToken() {
    localStorage.removeItem("token");
    setToken(null);
  }

  return {
    setToken: saveToken,
    token,
    removeToken
  }

}

export default useToken;
C:\react-js\myreactdev\src\components\Profile.js
//C:\react-js\myreactdev\src\components\Profile.js
import React, { useState, useEffect } from "react";
import axios from "axios";

function Profile(props) {

    const [profileData, setProfileData] = useState(null)
	
    useEffect(() => {
        getUsers();
    }, []);
	
	const email = localStorage.getItem('email');
	
    function getUsers() { 
		axios({
		  method: "GET",
		  url:`http://127.0.0.1:5000/profile/${email}`, 
		  headers: {
			Authorization: 'Bearer ' + props.token
		  }
		})
		.then((response) => {
			console.log(response)
		  const res =response.data
		  res.access_token && props.setToken(res.access_token)
		  setProfileData(({
			profile_name: res.name,
			profile_email: res.email,
			about_me: res.about}))
		}).catch((error) => {
		  if (error.response) {
			console.log(error.response)
			console.log(error.response.status)
			console.log(error.response.headers)
			}
		})
    }
	
    let imgs = [
      'https://mdbcdn.b-cdn.net/img/Photos/new-templates/bootstrap-chat/ava1-bg.webp',
    ];


  return (
	  <div className="container">
		<div className="row d-flex justify-content-center align-items-center h-50">
		  <div className="col col-lg-12">
				<div className="card mb-3">
				
					{profileData && <div className="row g-0">
					<div className="col-md-4 bg-c-lite-green text-center text-white">
						<img src={imgs[0]} className="img-fluid my-5" width="150"/>
						<h5>{profileData.profile_name}</h5>
						<p>Coder</p>
						<i className="far fa-edit mb-5"></i>
					</div>
			
					<div className="col-md-8">
						<div className="card-body p-4">
							<h6>Your profile details:</h6>
							
							<div className="row pt-1">
							<div className="col-6 mb-3">
								<h6>Email</h6>
								<p className="text-muted">{profileData.profile_email}</p>
							</div>
							<div className="col-6 mb-3">
								<h6>Phone</h6>
								<p className="text-muted">123 456 789</p>
							</div>
							</div>
							<h6>About</h6>
							<div className="d-flex justify-content-start">
							{profileData.about_me}
							</div>
						</div>
					</div>	

				</div>
				}
			</div>
		  </div>
		</div>
	</div>
  );
}

export default Profile;
react-js\myreactdev\src\App.css
//react-js\myreactdev\src\App.css
body {
  margin: 0;
  background-color: #ffffff;
}

.h-50 {
	margin-top:50px;
}	

.bg-c-lite-green {
    background: -webkit-gradient(linear, left top, right top, from(#f29263), to(#ee5a6f));
    background: linear-gradient(to right, #ee5a6f, #f29263);
}
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Related Post