Home > Enterprise >  how do we pass the user id into a route in app.js?
how do we pass the user id into a route in app.js?

Time:03-20

my teammate and I are stuck on solving a critical problem, which is how do we pass the user_id from one component to another in app.js . For example, we are able to register, login, and logout perfectly; but when we try to submit information in another component like personal form it says user_id is not defined. Also we are using JWT Tokens for authorization, and authentication. We are using local storage only, we did not implement redux.

App.js

import React, { Fragment, useState, useEffect } from "react";
import "./App.css";
import {
    BrowserRouter as Router,
    Routes,
    Route,
    Navigate,
} from "react-router-dom";

import { toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

// import { useNavigation } from '@react-navigation/native';
import Home from "./components/Home";
import Login from "./components/Login";
import Register from "./components/Register";
import MedicalForm from "./components/MedicalForm";
import PersonalForm from "./components/PersonalForm";
import Navbar from "./components/Navbar/index";

toast.configure();

function App() {
    // we want to make sure it set to false first
    const [isAuthenticated, setAuthenticated] = useState(false);

    //this is going to the be toggle function to set the auth
    const setAuth = (Boolean) => {
        setAuthenticated(Boolean);
    };

    // this is going to check if the user is authenticated  even if the
    // page is refreshed

    async function isAuth() {
        try {
            const response = await fetch("http://localhost:4001/auth/is-verify", {
                method: "GET",
                headers: { token: localStorage.token },
            });

            const parseRes = await response.json();

            parseRes === true ? setAuthenticated(true) : setAuthenticated(false);

            console.log(parseRes);
        } catch (err) {
            console.error(err.message);
        }
    }
    useEffect(() => {
        isAuth();
    });

    return (
        <Fragment>
            <Router>
                {/* reason why we use render instead of component props is because
                              anytime we send props to a component we don't want it to remount */}
                <Navbar />
                <div className="container">
                    <Routes>
                        {/* if(!isAuthenticated){ if this is true, pass setAuth to Login, and if it comes out true, then navigate to login page
                            <Login setAuth={setAuth} />}
                        else{
                            <Navigate to="/home" />
                            } */}
                        <Route
                            exact
                            path="/login"
                            element={
                                !isAuthenticated ? (
                                    <Login setAuth={setAuth} />
                                ) : (
                                    <Navigate to="/home" />
                                )
                            }
                        />
                        <Route
                            exact
                            path="/register"
                            element={
                                !isAuthenticated ? (
                                    <Register setAuth={setAuth} />
                                ) : (
                                    <Navigate to="/login" />
                                )
                            }
                        />

                        <Route
                            exact
                            path="/home"
                            element={
                                isAuthenticated ? (
                                    <Home setAuth={setAuth} />
                                ) : (
                                    <Navigate to="/login" />
                                )
                            }
                        />
                        <Route
                            exact
                            path="/mform"
                            element={
                                isAuthenticated ? (
                                    <MedicalForm setAuth={setAuth} />
                                ) : (
                                    <Navigate to="/login" />
                                )
                            }
                        />
                        <Route
                            exact
                            path="/pform"
                            element={
                                isAuthenticated ? (
                                    <PersonalForm setAuth={setAuth} />
                                ) : (
                                    <Navigate to="/login" />
                                )
                            }
                        />
                    </Routes>
                </div>
            </Router>
        </Fragment>
    );
}

export default App;

PersonalForm.js

`Login.js

import React, { Fragment, useState } from "react";
// import { Link } from "react-router-dom";
import { toast } from "react-toastify";
const Personalform = (props) => {
    const [username, setUsername] = useState("");
    const [inputs, setInputs] = useState({
        first_name: "",
        last_name: "",
        pronoun: "",
        occupation: "",
        phone_number: "",
        city: "",
        state: "",
        zip: "",
    });
    const {
        first_name,
        last_name,
        pronoun,
        occupation,
        phone_number,
        city,
        state,
        zip,
    } = inputs;
    const onChange = (e) => {
        // take in every input and target the input value of name
        //like email,username, and password
        setInputs({ ...inputs, [e.target.name]: e.target.value });
    };
    const onSubmitForm = async (e) => {
        e.preventDefault();
        try {
            const body = {
                first_name,
                last_name,
                pronoun,
                occupation,
                phone_number,
                city,
                state,
                zip,
            };
            // console.log(user_id)
            const response = await fetch(
                `http://localhost:4001/pform/${props.user_id}`,
                {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                        token: localStorage.token,
                    },
                    body: JSON.stringify(body),
                }
            );
            const parseRes = await response.json();
            setUsername(parseRes.username);
            if (parseRes.token) {
                // we want to save the token to our local storage
                localStorage.setItem("token", parseRes.token);
                console.log(parseRes);
                //now we want to setAuth to true
                props.setAuth(true);
                toast.success("submit succesfully"); // then use toastify
            } else {
                // if false
                props.setAuth(false); // set auth to false
                toast.error(parseRes); // set the toast to send and error
            }
        } catch (err) {
            console.error(err.message);
        }
    };
    const logout = (e) => {
        e.preventDefault();
        localStorage.removeItem("token");
        props.setAuth(false);
        toast.success("Logged out successfully");
    };
    return (
        <Fragment>
            {username}
            <h1 className="text-center my-5">Personal Form</h1>
            <form onSubmit={onSubmitForm}>
                <input
                    type="text"
                    // this is a name of an input
                    name="first_name"
                    placeholder="first_name"
                    className="form-control my-3"
                    value={first_name}
                    onChange={(e) => onChange(e)}
                />
                <input
                    type="text"
                    name="last_name"
                    placeholder="Last Name"
                    className="form-control my-3"
                    value={last_name}
                    onChange={(e) => onChange(e)}
                />
                <input
                    type="text"
                    name="pronoun"
                    placeholder="pronoun"
                    className="form-control my-3"
                    value={pronoun}
                    onChange={(e) => onChange(e)}
                />
                <input
                    type="text"
                    name="occupation"
                    placeholder="occupation"
                    className="form-control my-3"
                    value={occupation}
                    onChange={(e) => onChange(e)}
                />
                <input
                    type="text"
                    name="phone_number"
                    placeholder="phone number"
                    className="form-control my-3"
                    value={phone_number}
                    onChange={(e) => onChange(e)}
                />
                <input
                    type="text"
                    name="city"
                    placeholder="city"
                    className="form-control my-3"
                    value={city}
                    onChange={(e) => onChange(e)}
                />
                <input
                    type="text"
                    name="state"
                    placeholder="state"
                    className="form-control my-3"
                    value={state}
                    onChange={(e) => onChange(e)}
                />
                <input
                    type="text"
                    name="zip"
                    placeholder="zip"
                    className="form-control my-3"
                    value={zip}
                    onChange={(e) => onChange(e)}
                />
                <button className="btn btn-success btn-block">Submit</button>
            </form>
            <button className="btn btn-primary" onClick={(e) => logout(e)}>
                logout
            </button>
        </Fragment>
    );
};
export default Personalform;

index.js or the navbar component

import React from "react";
import {
    Nav,
    NavLink,
    Bars,
    NavMenu,
    NavBtn,
    NavBtnLink,
} from "./NavbarElements";

const Navbar = () => {
    return (
        <>
            <Nav>
                <NavLink to="/">
                    <h1>Logo</h1>
                </NavLink>
                <Bars />
                <NavMenu>
                    <NavLink to="/pform" activeStyle>
                        Personal Form
                    </NavLink>
                </NavMenu>
                <NavBtn>
                    <NavBtnLink to="/login">Login</NavBtnLink>
                </NavBtn>
            </Nav>
        </>
    );
};

export default Navbar;

login.js

import React, { Fragment, useState } from "react";
import { Link } from "react-router-dom";
import { toast } from "react-toastify";

const Login = ({ setAuth }) => {
    const [inputs, setInputs] = useState({
        email: "",
        password: "",
    });

    const { email, password } = inputs;

    const onChange = (e) => {
        setInputs({ ...inputs, [e.target.name]: e.target.value });
    };

    const onSubmitForm = async (e) => {
        e.preventDefault();
        try {
            const body = { email, password };

            const response = await fetch("http://localhost:4001/auth/login", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(body),
            });

            const parseRes = await response.json();

            if (parseRes.token) {
                localStorage.setItem("token", parseRes.token);
                setAuth(true);
                toast.success("login successfully!");
            } else {
                setAuth(false);

                toast.error(parseRes);
            }
        } catch (err) {
            console.error(err.message);
        }
    };
    return (
        <Fragment>
            <h1>Login</h1>
            <form onSubmit={onSubmitForm}>
                <input
                    type="email"
                    name="email"
                    placeholder="email"
                    className="form-control my-3"
                    value={email}
                    onChange={(e) => onChange(e)}
                />

                <input
                    type="password"
                    name="password"
                    placeholder="password"
                    className="form-control my-3"
                    value={password}
                    onChange={(e) => onChange(e)}
                />
                <button className="btn btn-success btn-block">submit</button>
            </form>
            <Link to="/register">Register</Link>
        </Fragment>
    );
};

export default Login;

Register

import React, { Fragment, useState } from "react";
import { Link } from "react-router-dom";
import { ToastContainer, toast } from "react-toastify";

const Register = ({ setAuth }) => {
    const [inputs, setInputs] = useState({
        email: "",
        password: "",
        username: "",
    });
    const { email, password, username } = inputs;
    const onChange = (e) => {
        // take in every input and target the input value of name
        //like email,username, and password
        setInputs({ ...inputs, [e.target.name]: e.target.value });
    };
    const onSubmitForm = async (e) => {
        e.preventDefault();
        try {
            const body = { email, password, username };
            const response = await fetch("http://localhost:4001/auth/register", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(body),
            });

            const parseRes = await response.json();
            if (parseRes.token) {
                localStorage.setItem("token", parseRes.token);
                setAuth(true);
                toast.success("Registered Successfully!");
            } else {
                setAuth(false);
                toast.error(parseRes);
            }
        } catch (err) {
            console.error(err.message);
        }
    };
    return (
        <Fragment>
            <h1 className="text-center my-5">Register</h1>
            <form onSubmit={onSubmitForm}>
                <input
                    type="email"
                    // this is a name of an input
                    name="email"
                    placeholder="email"
                    className="form-control my-3"
                    value={email}
                    onChange={(e) => onChange(e)}
                />
                <input
                    type="password"
                    name="password"
                    placeholder="password"
                    className="form-control my-3"
                    value={password}
                    onChange={(e) => onChange(e)}
                />
                <input
                    type="text"
                    name="username"
                    placeholder="username"
                    className="form-control my-3"
                    value={username}
                    onChange={(e) => onChange(e)}
                />
                <button className="btn btn-success btn-block">Submit</button>
            </form>
            <Link to="/login">Login</Link>
        </Fragment>
    );
};
export default Register;

jwtauth.js

const router = require("express").Router();
const { json, response } = require("express");
const pool = require("../db");
const bcrypt = require("bcrypt");
const jwtGenerator = require("../utils/jwtGenerator");
const validInfo = require("../middleware/validInfo");
const authorization = require("../middleware/authorization");

//registering

router.post("/register", validInfo, async (req, res) => {
    try {
        // 1. destructure the req.body(name,email,password)
        const { username, email, password } = req.body;

        // 2. check if user exists (if user exists then throw error)
        const user = await pool.query(
            "SELECT * FROM login_credentials WHERE email =$1",
            [email]
        );
        if (user.rows.length !== 0) {
            return res.status(401).json("User already exists");
        }
        // res.json(user.rows);
        // 3. bycrpyt the user password

        const saltRound = 10;
        const salt = await bcrypt.genSalt(saltRound);

        const bcryptPassword = await bcrypt.hash(password, salt);

        // 4. enter the new user inside our database

        const newUser = await pool.query(
            "INSERT INTO login_credentials (username,email,password) VALUES ($1,$2,$3) RETURNING *",
            [username, email, bcryptPassword]
        );

        // res.json(newUser.rows[0]);
        // 5. generate our jwt token
        const token = jwtGenerator(newUser.rows[0].user_id);

        res.json({ token });
    } catch (err) {
        console.error(err.message);
        res.status(500).send("server error");
    }
});

//login route
router.post("/login", validInfo, async (req, res) => {
    try {
        //1. destructure the req.body

        const { email, password } = req.body;
        //2. check if user doesn't exist (if not we throw error)
        const user = await pool.query(
            "SELECT * FROM login_credentials WHERE email=$1",
            [email]
        );

        if (user.rows.length === 0) {
            return res.status(401).json("password or email is incorrect");
        }
        //3. check if incoming password is the same the database password
        const validPassword = await bcrypt.compare(password, user.rows[0].password);
        console.log(validPassword);

        if (!validPassword) {
            return res.status(401).json("password or email is incorrect");
        }

        //4. give the jwt token
        const token = jwtGenerator(user.rows[0].user_id);

        res.json({ token });
    } catch (err) {
        console.error(err.message);
        res.status(500).send("Server Error");
    }
});

router.get("/is-verify", authorization, async (req, res) => {
    try {
        res.json(true);
    } catch (err) {
        console.error(err.message);
        res.status(500).send("Server Error");
    }
});

module.exports = router;

authorization.js

const jwt = require("jsonwebtoken");
require("dotenv").config();

// before it hits routes it's going to get access to the requested
// resonse then if everything ends up working ok, it will continue on
// with the process of next so it can keep going with the routes
module.exports = async (req, res, next) => {
    try {
        const jwtToken = req.header("token");

        if (!jwtToken) {
            return res.status(401).json("Not Authorized");
        }
        // if this is verified it is going to return us a payload that we can use within our routes
        const payload = jwt.verify(jwtToken, process.env.jwtSecret);

        req.user = payload.user;

        next();
    } catch (err) {
        console.error(err.message);
        return res.status(403).json("Not Authorized");
    }
};

validInfo.js

module.exports = (req, res, next) => {
    const { email, username, password } = req.body;

    function validEmail(userEmail) {
        return /^\w ([\.-]?\w )*@\w ([\.-]?\w )*(\.\w{2,3}) $/.test(userEmail);
    }

    if (req.path === "/register") {
        if (![email, username, password].every(Boolean)) {
            return res.status(401).json("Missing Credentials");
        } else if (!validEmail(email)) {
            return res.status(401).json("Invalid Email");
        }
    } else if (req.path === "/login") {
        if (![email, password].every(Boolean)) {
            return res.status(401).json("Missing Credentials");
        } else if (!validEmail(email)) {
            return res.status(401).json("Invalid Email");
        }
    }

    next();
};

CodePudding user response:

You can set vars in res object like this in node.js. But it your code is react not node.js.

res.user.user_id = user_id;

and then use it anywhere with:

let user_id = res.user.user_id;

CodePudding user response:

you can create a file for auth context then create a context and export it

export const AuthContext= React.createContext({userId:"",setUserId: ()=>{}}); //the param here should be the default value (default shape of the object you wanna pass to children)

Then in your app.js import that context and wrap your other components with

const [userId, setUserId] = useState("");

<AuthContext.Provider value={{userId:userId, setUserId:setUserId}}> //the object contains the state or functions you wanna access from child components
//your other components
</AuthContext.Provider>

now inside any screen or component that needs to access or set the user id (or any other value or callback you passed) you can just import the context and access the value like this

const {userId,setUserId} = useContext(AuthContext)

you can also refer to this example:

https://fatmali.medium.com/use-context-and-custom-hooks-to-share-user-state-across-your-react-app-ad7476baaf32

  • Related