Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redirect to Dashboard if logged in #16

Open
hazartilirot opened this issue May 15, 2023 · 0 comments
Open

Redirect to Dashboard if logged in #16

hazartilirot opened this issue May 15, 2023 · 0 comments

Comments

@hazartilirot
Copy link

hazartilirot commented May 15, 2023

Lesson Redirect to Dashboard if logged in, timeline 02:00

Oh my gooooood. The more I watch the less I like.... Mama Samba is soooooooo impatient and unreasonable. I have just implemented the feature of fetching a user by id. Instead of using the null in the initial state in AuthContext.jsx - I used a blank object as a kind of a guest with ROLE_GUEST. I decided to go this way so that Sidebar.jsx is loaded properly.

AuthContext.jsx

import { createContext, useContext, useEffect, useState } from "react";
import { executeLogin, getCustomerById } from "../../services/client.js";
import jwtDecode from "jwt-decode";
import { redirect } from "react-router-dom";

const AuthContext = createContext({});

const AuthProvider = ({ children }) => {

    let defaultCustomer = {
        name: "Viewer",
        email: "",
        age: undefined,
        gender: "",
        roles: ["ROLE_GUEST"]
    };

    const [customer, setCustomer] = useState(defaultCustomer);

    useEffect(() => {
            getCustomer().then(data => setCustomer({ ...data }))
    }, []);


    const getCustomer = async () => {
        const token = localStorage.getItem("access_token");
        const id = localStorage.getItem("customer_id");

        if (!token || !id) {
            return logout();
        }

        const { data } = await getCustomerById(id)

        const decodedJwt = jwtDecode(token);

        if (!data.email === decodedJwt.sub) {
            logout();
        }
         return data;
    }

    const login = async submitEmailPassword => new Promise(
        (resolve, reject) => executeLogin(submitEmailPassword)
            .then(res => {
                const jwt = res.headers["authorization"];
                localStorage.setItem("access_token", jwt);
                localStorage.setItem("customer_id", res.data.customerDto.id);

                getCustomer().then(fetched => {
                    setCustomer({ ...fetched })
                    resolve(res);
                });
            }).catch(err => {
                reject(err);
            })
    );

    const logout = () => {
        localStorage.removeItem("access_token");
        localStorage.removeItem("customer_id");
        setCustomer(defaultCustomer);
        redirect("/")
    };

    const isCustomerAuthenticated = () => {

        const token = localStorage.getItem("access_token");
        const id = localStorage.getItem("customer_id");

        if (!token || !id) {
            logout();
            return false
        }

        const { exp } = jwtDecode(token);

        if (Date.now() > exp * 1000) {
            logout();
            return false;
        }

        return true;
    };

    return (
        <AuthContext.Provider value={{
            customer,
            login,
            logout,
            isCustomerAuthenticated
        }}>
            {children}
        </AuthContext.Provider>
    );
};

export const useAuth = () => useContext(AuthContext);

export default AuthProvider;
export const getCustomerById = async id => {
    try {
        return await axios.get(
            `${import.meta.env.VITE_API_BASE_URL}/api/v1/customers/${id}`,
            getTokenFromLocalStorage()
        );
    } catch (e) {
        throw e;
    }
}

Each request I take the user's id from the localStorage, fetch the user from the database by the id and place the user into the state. Before that I retrieve the user's email from JWT and compare it with the customer's email - if they are the same - ok. If any of localStorage values have been removed from the client's side (jwt or user id) I redirect the user to the login page and delete any data in their localStorage.

What he does in the Login component is he checks if the user is null (state). The difference is he doesn't fetch the user from the database (there is no async request) and it seems to have worked perfectly well. In my case, by the time it checks the user it is yet GIMMICK (a guest! or it would've been null if I have done the same as he does in the video). Anyway, what we actually need to check is not the user's state, but if the user is authenticated:

Login.jsx

const { isCustomerAuthenticated } = useAuth();
    const navigate = useNavigate();

    useEffect(() => {
        if (isCustomerAuthenticated()) {
            navigate("dashboard")
        }
    }, [])

or, an alternative way....:

const navigate = useNavigate();

    useEffect(() => {
        const token = localStorage.getItem("access_token");
        const id = localStorage.getItem("customer_id");

        if (token && id) {
            navigate("dashboard")
        }
    }, [])

if you're going to implement the same, there are extra two pieces of code:

onSubmit={(values, { setSubmitting }) => {
                setSubmitting(true);
                login(values)
                    .then(res => {
                        navigate("dashboard");
                    }).catch(err => notifyOnFailure(err.code, err.response?.data.message)
                ).finally(() => setSubmitting(false));

            }}
 onSubmit={
                    (customer, { setSubmitting }) => {
                        setSubmitting(true);
                        registerCustomer(customer)
                            .then(res => {
                                notifyOnSuccess("Customer saved", `${customer.name} was saved`);
                                return login({
                                    username: customer.email,
                                    password: customer.password
                                })
                            }).then(res => location.reload())
                            .catch(err => notifyOnFailure(err.code, err.response.data.error))
                            .finally(() => setSubmitting(false))
                    }
                }

One is used when a user logs in to their account, another one is when a user signs up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant