article

Monday, June 19, 2023

React JS Login with Protected dashboard page and PHP Mysql

React JS Login with Protected dashboard page and PHP Mysql

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

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

Run
C:\react-js\my-app> npm start

C:\react-js\my-app\src\App.js
//C:\react-js\my-app\src\App.js
import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Protected from "./components/Protected";
import Dashboard from "./components/Dashboard";
import Login from "./components/Login";
//import './App.css';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Login />} />
        <Route path="/dashboard" element={<Protected Component={Dashboard} />} />
      </Routes>
    </BrowserRouter>
  );
}

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
C:\react-js\my-app\src\components\Login.js
//C:\react-js\my-app\src\components\Login.js
import React, { useState, useEffect  } from "react";

import { useNavigate } from 'react-router-dom';

export default function Login() {
    const naviget = useNavigate();
    const [user, setUser] = useState("");
    const [pass, setPass] = useState("");
    const [error, setError] = useState("");
    const [msg, setMsg] = useState("");

    useEffect(() => {
        let login = localStorage.getItem("login");
        if(login){
            naviget("/dashboard");
        }
        let loginStatus = localStorage.getItem("loginStatus");
        if(loginStatus){
            setError(loginStatus);
            setTimeout(function(){
                localStorage.clear();
                window.location.reload();
            }, 3000);
        }
        setTimeout(function(){
            setMsg("");
        }, 5000);
    }, [msg]);

    const handleInputChange = (e, type) => {
        switch(type){
            case "user":
                setError("");
                setUser(e.target.value);
                if(e.target.value === ""){
                    setError("Username has left blank");
                }
                break;
            case "pass":
                setError("");
                setPass(e.target.value);
                if(e.target.value === ""){
                    setError("Password has left blank");
                }
                break;
            default:
        }
    }

    function loginSubmit(){
        if(user !== "" && pass != ""){
            var url = "http://localhost/devtest/reactjs/login.php";
            var headers = {
                "Accept": "application/json",
                "Content-type": "application/json"
            };
            var Data = {
                user: user,
                pass: pass
            };
            fetch(url, {
                method: "POST",
                headers: headers,
                body: JSON.stringify(Data)
            }).then((response) => response.json())
            .then((response) => {
                console.log(response);
                if(response[0].result === "Invalid username!" || response[0].result === "Invalid password!"){
                    setError(response[0].result);
                }
                else{
                    setMsg(response[0].result);
                    setTimeout(function(){
                        localStorage.setItem("login", true);
                        localStorage.setItem('user', user);
                        naviget("/dashboard");
                    }, 5000);
                }
            }).catch((err) => {
                setError(err);
                console.log(err);
            })
        }
        else{
            setError("All field are required!")
        }
    }
    return(
        <>
        <section className="vh-100" style={{backgroundColor: '#9A616D'}}>
        <div className="container py-5 h-100">
            <div className="row d-flex justify-content-center align-items-center h-100">
            <div className="col col-xl-10">
                <div className="card" style={{borderRadius: '1rem'}}>
                <div className="row g-0">
                    <div className="col-md-6 col-lg-5 d-none d-md-block">
                    <img src="https://images.pexels.com/photos/4348403/pexels-photo-4348403.jpeg?auto=compress&cs=tinysrgb&w=1600" alt="login form" className="img-fluid" style={{borderRadius: '1rem 0 0 1rem'}} />
                    </div>
                    <div className="col-md-6 col-lg-7 d-flex align-items-center">
                    <div className="card-body p-4 p-lg-5 text-black">
                        <p>
                            {
                                error !== "" ?
                                <div style={{color: '#842029'}}><b>{error}</b></div> :
                                <div style={{color: '#badbcc'}}><b>{msg}</b></div>
                            }
                        </p>
                        <div className="d-flex align-items-center mb-3 pb-1">
                            <i className="fas fa-cubes fa-2x me-3" style={{color: '#ff6219'}} />
                            <span className="h1 fw-bold mb-0">Logo</span>
                        </div>
                        <h5 className="fw-normal mb-3 pb-3" style={{letterSpacing: 1}}>Sign into your account</h5>
                        <div className="form-outline mb-4">
                            <input 
                                type="text" 
                                id="username"
                                className="form-control form-control-lg"
                                value={user}
                                onChange={(e) => handleInputChange(e, "user")}
                            />
                            <label className="form-label" htmlFor="username">User Name</label>
                        </div>
                        <div className="form-outline mb-4">
                            <input 
                                type="password" 
                                id="pass"
                                className="form-control form-control-lg"
                                value={pass}
                                onChange={(e) => handleInputChange(e, "pass")}
                            />
                            <label className="form-label" htmlFor="pass">Password</label>
                        </div>
                        <div className="pt-1 mb-4">
                            <input 
                                type="submit"
                                defaultValue="Login" 
                                className="btn btn-dark btn-lg btn-block"
                                onClick={loginSubmit}
                            />
                        </div>
                        <a className="small text-muted" href="#!">Forgot password?</a>
                        <p className="mb-5 pb-lg-2" style={{color: '#393f81'}}>Don't have an account? <a href="#!" style={{color: '#393f81'}}>Register here</a></p>
                        <a href="#!" className="small text-muted">Terms of use.</a>
                        <a href="#!" className="small text-muted">Privacy policy</a>
                    </div>
                    </div>
                </div>
                </div>
            </div>
            </div>
        </div>
        </section>
        </>
    )
}
C:\react-js\my-app\src\components\Dashboard.js
//C:\react-js\my-app\src\components\Dashboard.js
import React, {  } from "react";
import { useNavigate } from 'react-router-dom';

export default function Dashboard() {
    const naviget = useNavigate();
    function logoutSubmit(){
        localStorage.setItem("login", "");
        localStorage.setItem("loginStatus", "Logged out successfully!")
        naviget("/");
    }
    const user = localStorage.getItem('user');
    return(
        <>
        <nav className="navbar navbar-expand-lg navbar-light bg-light">
        <div className="container">
          <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" />
          </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="#">Link</a>
              </li>
            </ul>
            <div className="d-flex">
              <button className="btn btn-outline-primary" type="submit" onClick={logoutSubmit}>
                Logout
              </button>
            </div>
          </div>
        </div>
        </nav>
        <div className="container" style={{paddingTop: 50}}>
            <h3>{user}</h3>
            <h3>Dashboard Page</h3>
        </div>
        </>
    )
}
C:\react-js\my-app\src\components\Protected.js
//C:\react-js\my-app\src\components\Protected.js
import React, { useEffect } from "react";
import { useNavigate } from "react-router-dom";

export default function Protected(props) {
    const naviget = useNavigate();
    const { Component } = props;
    useEffect(() => {
        let login = localStorage.getItem("login");
        if(!login){
            localStorage.setItem("loginStatus", "Please login to view dashboard!");
            naviget("/", {replace: true});
        }
    }, []);

    return(
        <Component />
    );
}
react-js\my-app\public\index.html
//react-js\my-app\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" 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/

PHP Mysql http://localhost/devtest/reactjs/login.php
//http://localhost/devtest/reactjs/login.php
<?php
	header("Access-Control-Allow-Origin: *"); //add this CORS header to enable any domain to send HTTP requests to these endpoints:
    header("Access-Control-Allow-Methods: GET, POST");
    header("Access-Control-Allow-Headers: Content-Type");

    $conn = new mysqli("localhost", "root", "", "reactjsDB");
    if(mysqli_connect_error()){
        echo mysqli_connect_error();
        exit();
    }
    else{
        $eData = file_get_contents("php://input");
        $dData = json_decode($eData, true);

        $user = $dData['user'];
        $pass = $dData['pass'];
		//$password = md5($pass);
        $result = "";

        if($user != "" and $pass != ""){
            $sql = "SELECT * FROM user WHERE user='$user';";
            $res = mysqli_query($conn, $sql);

            if(mysqli_num_rows($res) != 0){
                $row = mysqli_fetch_array($res);
                if($pass != $row['pass']){
                    $result = "Invalid password!";
                }
                else{
                    $result = "Loggedin successfully! Redirecting...";
                }
            }
            else{
                $result = "Invalid username!";
            }
        }
        else{
            $result = "";
        }

        $conn -> close();
        $response[] = array("result" => $result);
        echo json_encode($response);
    }

?>

Related Post