diff --git a/client/src/App.tsx b/client/src/App.tsx index 94c82f2..5a14a13 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -2,22 +2,33 @@ import { BrowserRouter, Navigate, Outlet, Route, Routes } from 'react-router-dom import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import Login from './routes/login'; import Home from './routes/home'; -import { checkAuth } from './controllers/Auth'; -import { CookiesProvider } from 'react-cookie'; +import { ProvideAuth } from './controllers/Auth'; +import { Cookies, CookiesProvider, useCookies } from 'react-cookie'; +import Signup from './routes/signup'; +import { useEffect, useState } from 'react'; // Create a client const queryClient = new QueryClient(); export default () => { + const [auth, setAuth] = useState(false); + const [cookies, setCookie, removeCookie] = useCookies(['token']); + useEffect(() => { + if (cookies.token) { + setAuth(true); + } + }, [cookies.token]); + return ( - - : } /> - : } /> - - + + : } /> + : } /> + : } /> + + diff --git a/client/src/components/AppHeader.tsx b/client/src/components/AppHeader.tsx index 61cf05a..a4aafe9 100644 --- a/client/src/components/AppHeader.tsx +++ b/client/src/components/AppHeader.tsx @@ -1,8 +1,8 @@ import logo from '@assets/images/logo.svg'; import { useQuery } from '@tanstack/react-query'; -import { useEffect, useState } from 'react'; -import { Cookies, withCookies } from 'react-cookie'; -import { Navigate, useNavigate } from 'react-router-dom'; +import { useState } from 'react'; +import { Cookies, withCookies, useCookies } from 'react-cookie'; +import { Navigate } from 'react-router-dom'; const getMeInfo = async () => { const token = new Cookies().get('token'); @@ -26,36 +26,40 @@ const AppHeader = () => { console.error(error); }, }); + const [cookies, setCookie, removeCookie] = useCookies(['token']); const logOut = async () => { - new Cookies().remove('token'); - window.location.reload(); + console.log(cookies); + removeCookie('token'); + window.location.href = '/login'; }; return ( -
-
- logo -
-
-
-
- avatar + <> +
+
+ logo +
+
+
+
+ avatar +
+
+ + {meInfo.isLoading ? '' : meInfo.data ? meInfo.data.firstName + ' ' + meInfo.data.lastName : ''} + +
+
-
- - {meInfo.isLoading ? '' : meInfo.data ? meInfo.data.firstName + ' ' + meInfo.data.lastName : ''} - -
-
-
+ ); }; diff --git a/client/src/controllers/Auth.ts b/client/src/controllers/Auth.ts deleted file mode 100644 index 41ad556..0000000 --- a/client/src/controllers/Auth.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Cookies } from "react-cookie"; - -const checkAuth = () => { - const token = new Cookies().get("token"); - if (token && token !== '') { - return true; - } - return false; -}; - -export { checkAuth }; \ No newline at end of file diff --git a/client/src/controllers/Auth.tsx b/client/src/controllers/Auth.tsx new file mode 100644 index 0000000..f95384c --- /dev/null +++ b/client/src/controllers/Auth.tsx @@ -0,0 +1,145 @@ +import { useQuery } from "@tanstack/react-query"; +import { createContext, useCallback, useContext, useEffect, useReducer, useState } from "react"; +import { Cookies, useCookies } from "react-cookie"; +import { Token } from "../types"; + +// const checkAuth = () => { +// const [cookies, setCookie, removeCookie] = useCookies(["token"]); +// useEffect(() => { +// if (cookies.token) { +// console.log("token exists"); +// } else { +// console.log("token does not exist"); +// } +// }, [cookies.token]); + +// if (cookies.token && cookies.token !== '') { +// return true; +// } +// return false; +// }; + +// const reducer = (state: any, action: any) => { +// switch (action.type) { +// case "LOGIN": +// return { +// token: action.token, +// expires: action.expires, +// isAuthenticated: true, +// }; +// case "LOGOUT": +// return { +// token: null, +// expires: null, +// isAuthenticated: false, +// }; +// default: +// return state; +// } +// }; + + +// // create auth hook +// const useAuth = () => { +// const [cookies, setCookie, removeCookie] = useCookies(["token"]); + +// const [auth, dispatch] = useReducer(reducer, { +// token: cookies.token, +// isAuthenticated: false, +// }); + +// const login = (token: string, expires: string) => { +// setCookie("token", token, { path: "/", expires: new Date(expires) }); +// dispatch({ type: "LOGIN", token: token, expires: expires }); +// }; + +// const logout = () => { +// removeCookie("token", { path: "/" }); +// dispatch({ type: "LOGOUT" }); +// }; + +// return [ auth, login, logout ]; +// }; + +// export { checkAuth, useAuth }; + +const authContext = createContext({}); + +export function ProvideAuth({ children } : any) { + const auth = useProvideAuth(); + return {children}; +} + +export const useAuth = () => { + return useContext(authContext); +}; + +const loginQuery = (email: string, password: string) => { + return useQuery( + ['login'], + async () => { + const response = await fetch('/api/auth/login', { + method: 'POST', + body: JSON.stringify({ email, password }), + mode: 'cors', + headers: { + 'Content-Type': 'application/json', + }, + }); + return response.json(); + }, + { + onSuccess: (data: Token) => { + return data; + }, + onError: (error) => { + console.error(error); + }, + refetchOnWindowFocus: false, + } + ); +} + +function useProvideAuth() { + const [user, setUser] = useState({}); + const [cookies, setCookie, removeCookie] = useCookies(["token"]); + + // Wrap any Firebase methods we want to use making sure ... + // ... to save the user to state. + const login = (email: string, password: string) => { + const { data, error, isLoading } = loginQuery(email, password); + if (data) { + setUser(data); + setCookie("token", data.token, { path: "/", expires: new Date(data.expiresAt) }); + } + if (error) { + console.error(error); + } + if (isLoading) { + console.log('loading'); + } + }; + + // Subscribe to user on mount + // Because this sets state in the callback it will cause any ... + // ... component that utilizes this hook to re-render with the ... + // ... latest auth object. + useEffect(() => { + const unsubscribe = () => { + if (user) { + setUser(user); + } else { + setUser({}); + } + }; + + // Cleanup subscription on unmount + return () => unsubscribe(); + }, []); + + // Return the user object and auth methods + return { + user, + login, + }; +} \ No newline at end of file diff --git a/client/src/routes/login.tsx b/client/src/routes/login.tsx index 6cb6aff..7af3040 100644 --- a/client/src/routes/login.tsx +++ b/client/src/routes/login.tsx @@ -1,14 +1,15 @@ import { Link, Navigate, useNavigate } from 'react-router-dom'; import logo from '@assets/images/logo.svg'; import { useQuery } from '@tanstack/react-query'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useCookies } from 'react-cookie'; import type { Token } from '../types'; +import { useAuth } from '../controllers/Auth'; const Login = () => { - const [cookie, setCookie] = useCookies(['token']); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); + const [cookies, setCookie, removeCookie] = useCookies(['token']); const { refetch } = useQuery( ['login'], @@ -25,8 +26,9 @@ const Login = () => { }, { onSuccess: (data: Token) => { - setCookie('token', data.token, { path: '/', expires: new Date(data.expiresAt), sameSite: 'strict' }); - window.location.reload(); + console.log(data); + setCookie('token', data.token, { path: '/', expires: new Date(data.expiresAt) }); + window.location.href = '/home'; }, onError: (error) => { console.error(error);