diff --git a/client/src/components/AuthModal.js b/client/src/components/AuthModal.js index 6b17ec1..ef2f81b 100644 --- a/client/src/components/AuthModal.js +++ b/client/src/components/AuthModal.js @@ -1,12 +1,11 @@ import {Fragment, useState} from 'react' import {Dialog, DialogTitle, TextField, Button, CircularProgress} from '@mui/material' -import axios from '../api' import {useAuth} from '../contexts/AuthContext' const textFieldSx = {mx: 2, my: 0.5} -export default function AuthModal({open, close, register, toggleRegister}) { - const {setIsLoggedIn, setToken, setAccount} = useAuth() +export default function AuthModal({open, close, isRegisterMode, toggleRegister}) { + const {login, register} = useAuth() const [formData, setFormData] = useState({}) const [loading, setLoading] = useState(false) @@ -22,16 +21,10 @@ export default function AuthModal({open, close, register, toggleRegister}) { setError('') try { - const requestPath = register ? '/auth/register' : '/auth/login' - const response = await axios.post(requestPath, formData) - - setToken(response.data.token) - setAccount(response.data.data) - setIsLoggedIn(true) + isRegisterMode ? await register(formData) : await login(formData) close() } catch (error) { - console.error(error) - setError(error?.response?.data?.message ?? error.message) + setError(error) } setLoading(false) @@ -42,7 +35,7 @@ export default function AuthModal({open, close, register, toggleRegister}) { return ( - {register ? ( + {isRegisterMode ? ( ) : ( @@ -57,13 +50,13 @@ export default function AuthModal({open, close, register, toggleRegister}) { ) : ( )} ) @@ -78,7 +71,7 @@ function LoginForm({formData, handleChange}) { label='Username' name='username' type='text' - value={formData['username'] ?? ''} + value={formData['username'] || ''} onChange={handleChange} variant='filled' sx={textFieldSx} @@ -88,7 +81,7 @@ function LoginForm({formData, handleChange}) { label='Password' name='password' type='password' - value={formData['password'] ?? ''} + value={formData['password'] || ''} onChange={handleChange} variant='filled' sx={textFieldSx} @@ -107,7 +100,7 @@ function RegisterForm({formData, handleChange}) { label='Username' name='username' type='text' - value={formData['username'] ?? ''} + value={formData['username'] || ''} onChange={handleChange} variant='filled' sx={textFieldSx} @@ -117,7 +110,7 @@ function RegisterForm({formData, handleChange}) { label='Password' name='password' type='password' - value={formData['password'] ?? ''} + value={formData['password'] || ''} onChange={handleChange} variant='filled' sx={textFieldSx} diff --git a/client/src/components/Header.js b/client/src/components/Header.js index bade1b0..58197d1 100644 --- a/client/src/components/Header.js +++ b/client/src/components/Header.js @@ -40,7 +40,7 @@ export default function Header() { - + @@ -69,7 +69,7 @@ export default function Header() { setAuthModal(false)} - register={register} + isRegisterMode={register} toggleRegister={() => setRegister((prev) => !prev)} /> diff --git a/client/src/contexts/AuthContext.js b/client/src/contexts/AuthContext.js index 1802ca0..5f12a92 100644 --- a/client/src/contexts/AuthContext.js +++ b/client/src/contexts/AuthContext.js @@ -11,14 +11,71 @@ export function useAuth() { // export the provider (handle all the logic here) export function AuthProvider({children}) { - const [token, setToken] = useState(localStorage.getItem('token') ?? null) - const [account, setAccount] = useState(null) const [isLoggedIn, setIsLoggedIn] = useState(false) + const [account, setAccount] = useState(null) + const [token, setToken] = useState(localStorage.getItem('token') || null) + + const register = (formData = {}) => + new Promise((resolve, reject) => { + axios + .post('/auth/register', formData) + .then(({data: {data, token}}) => { + setAccount(data) + setToken(token) + setIsLoggedIn(true) + resolve(true) + }) + .catch((error) => { + console.error(error) + reject(error?.response?.data?.message || error.message) + }) + }) + + const login = (formData = {}) => + new Promise((resolve, reject) => { + axios + .post('/auth/login', formData) + .then(({data: {data, token}}) => { + setAccount(data) + setToken(token) + setIsLoggedIn(true) + resolve(true) + }) + .catch((error) => { + console.error(error) + reject(error?.response?.data?.message || error.message) + }) + }) const logout = () => { - setToken(null) - setAccount(null) setIsLoggedIn(false) + setAccount(null) + setToken(null) + } + + const getAccount = async () => { + try { + const headers = {headers: {authorization: `Bearer ${token}`}} + const response = await axios.get('/auth/account', headers) + + setAccount(response.data.data) + setIsLoggedIn(true) + } catch (error) { + console.error(error) + if (error?.response?.statusCode === 401) setToken(null) + } + } + + const getTokenPayload = () => { + if (!token) { + console.warn(`Token is ${null}/${undefined}`) + return {} + } + + const informativePart = token.split('.')[1] + const payload = JSON.parse(window.atob(informativePart)) + + return payload } // This side effect keeps local storage updated with recent token value, @@ -32,28 +89,23 @@ export function AuthProvider({children}) { }, [token]) // This side effect runs only if we have a token, but no account or logged-in boolean. - // This "if" statement applies only when refreshed, or re-opened the browser, + // This "if" statement is "true" only when refreshed, or re-opened the browser, // if true, it will then ask the backend for the account information (and will get them if the token hasn't expired) useEffect(() => { - if (!isLoggedIn && !account && token) { - ;(async () => { - try { - const headers = {headers: {authorization: `Bearer ${token}`}} - const response = await axios.get('/auth/account', headers) - - setAccount(response.data.data) - setIsLoggedIn(true) - } catch (error) { - console.error(error) - if (error?.response?.statusCode === 401) setToken(null) - } - })() - } + if (!isLoggedIn && !account && token) getAccount() }, [isLoggedIn, account, token]) // eslint-disable-line react-hooks/exhaustive-deps return ( + value={{ + isLoggedIn, + account, + token, + register, + login, + logout, + getTokenPayload, + }}> {children} ) diff --git a/client/src/styles/index.css b/client/src/styles/index.css index 8ec2680..44f3035 100644 --- a/client/src/styles/index.css +++ b/client/src/styles/index.css @@ -1,6 +1,6 @@ :root { --online: #44b700; - --offline: rgb(183, 68, 0); + --offline: #b74400; } body {