-
Notifications
You must be signed in to change notification settings - Fork 0
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
frontend refactoring and work on auth pages #8
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A nice addition would also be a privateRoute
type of component that wraps a regular route but checks if the user is logged in. That way if more pages are added to the app in the future, we don't have to manually check if the user is logged in each time.
|
||
const ButtonHeader = ({ href, questionText, buttonText, classes }) => { | ||
return ( | ||
<Box p={1} alignSelf="flex-end" alignItems="center"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typically you will want to use Grid
instead of Box
(Grid is a wrapper for Box) to make your life easier because of the built-in flexbox
marginTop: theme.spacing(1) | ||
}, | ||
label: { fontSize: 19, color: "rgb(0,0,0,0.4)", paddingLeft: "5px" }, | ||
submit: { | ||
margin: theme.spacing(3, 2, 2), | ||
padding: 10, | ||
width: 160, | ||
height: 56, | ||
borderRadius: 3, | ||
marginTop: 49, | ||
fontSize: 16, | ||
backgroundColor: "#3a8dff", | ||
fontWeight: "bold" | ||
}, | ||
inputs: { | ||
marginTop: ".8rem", | ||
height: "2rem", | ||
padding: "5px" | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have a variety of spacing types here.
theme.spacing
, px
, rem
, and just integer pixels. It would be a good practice to make as much of it uniform as possible
}; | ||
|
||
const redirect = () => { | ||
const user = localStorage.getItem("user"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
storing the user in localStorage will cause problems down the line. The idea behind using localStorage for things is to persist information between sessions. You shouldn't do that with user information. One example of a problem is if I sign in to multiple browsers, and change something in one browser, those changes will not be reflected in the second one.
client/src/pages/Login.jsx
Outdated
if (reason === "clickaway") return; | ||
setOpen(false); | ||
const login = async ({ email, password }) => { | ||
const res = await fetch('http://localhost:3001/user/login', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we have a proxy set up, you should be able to use relative paths /user/login
client/src/pages/Login.jsx
Outdated
localStorage.setItem("userId", userId); | ||
localStorage.setItem("username", username); | ||
localStorage.setItem("userImage", userImage); | ||
localStorage.setItem("token", token); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We prefer using httpOnly
cookies to localStorage, since it is less accessible
client/src/pages/Login.jsx
Outdated
<ButtonHeader | ||
classes={classes} | ||
href="/signup" | ||
questionText="Don't have an account?" | ||
buttonText="Create account" | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice abstraction
client/src/pages/Signup.jsx
Outdated
localStorage.setItem("userId", userId); | ||
localStorage.setItem("username", username); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see notes above
client/src/pages/Dashboard.jsx
Outdated
React.useEffect(() => { | ||
const user = localStorage.getItem("user"); | ||
useEffect(() => { | ||
const user = localStorage.getItem("token"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this variable should probably be called token
or loggedIn
. You also have to be careful. What if the token exists in localStorage
but is expired?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code needs some more organization. moving the logic of checking the user is logged in or not to the PrivateRoute and remove this logic from other components.
client/src/App.js
Outdated
const [userId, setUserId] = useState(""); | ||
const [username, setUsername] = useState(""); | ||
const [userImage, setUserImage] = useState(""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Storing each field of the user information in its own state is not the best choice here, what if the user had 10 or 20 key/value pairs in it. Why not store an object of the user data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch, thanks!
client/src/App.js
Outdated
|
||
const refreshAuth = async () => { | ||
const res = await fetch('/user/refresh', { method: 'POST' }); | ||
|
||
if (res.status === 200) { | ||
const { username, userImage } = await res.json(); | ||
setSignedIn(true); | ||
setUsername(username); | ||
setUserImage(userImage); | ||
} else { | ||
setSignedIn(false); | ||
history.push("/login"); | ||
} | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not let the PrivateRoute handle the logic of check if the user is logged in or not. And also handle the logic of forwarding the user to a certain route if they are not logged in.
client/src/App.js
Outdated
const logout = async () => { | ||
await fetch('/user/logout', { method: 'POST' }); | ||
|
||
setLoggingOut(true); | ||
try { | ||
history.push('/login'); | ||
} finally { | ||
setLoggingOut(false); | ||
setSignedIn(false); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this logic to a more relevant component, perhaps the component that is responsible for logging out the user.
|
||
const PrivateRoute = ({ component: Component, isSignedIn, refreshAuth, path, ...rest }) => { | ||
return ( | ||
<Route | ||
path={path} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This component could encapsulate the logic related to checking the user is logged in or not, and based on that forwarding the user to a certain route.
bgcolor: "background.paper", | ||
// minHeight: "100vh", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not leave commented-out code in PRs, you can always get code from old commits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That accidentally slipped in, will remove indeed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code is a lot cleaner than it was before. be careful bout edge cases that cause lots of render or unnecessary requests.
client/src/pages/Login.jsx
Outdated
Welcome back! | ||
<p className={classes.welcome} component="h1" variant="h5"> | ||
Welcome back! | ||
</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use Material UI's Typography instead of p and h tags
client/src/pages/Login.jsx
Outdated
import { useEffect } from "react"; | ||
import { Button, CssBaseline, TextField, Paper, Grid, Typography } from "@material-ui/core"; | ||
import { Formik } from "formik"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great way of using destructuring
client/src/pages/Login.jsx
Outdated
} else if (res.status === 401) { | ||
throw new Error("Invalid password"); | ||
} else if (res.status !== 200) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's better from a security perspective not to point out what the user did wrong when they are trying to login.
So a more generic message saying wrong credentials would be better.
setSignedIn(false); | ||
history.push("/login"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also empty the local storage from any flag that indicates that the user is authenticated if this fails
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After my last changed we don't use local storage anymore, so this should be good!
client/src/App.js
Outdated
</BrowserRouter> | ||
<Route path="/login" component={Login} /> | ||
<Route path="/signup" component={Signup} /> | ||
<PrivateRoute path="/dashboard" component={Dashboard} /> | ||
<Route exact path="/"> | ||
<Redirect to="/signup" /> | ||
</Route> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need a way to make sure an authenticated user does not get back to signup or login pages unless they logout.
|
||
const GreetingSideBar = ({ classes }) => { | ||
return ( | ||
<Grid item xs={false} sm={4} md={5} className={classes.image}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like some spacing issues here, do you happen to use a linter? It would probably make these issues much more easy in the future :)
client/src/components/SnackBar.jsx
Outdated
onClose={handleClose} | ||
message={message} | ||
action={ | ||
<React.Fragment> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm do you need this extra React.Fragment wrapping wrong IconButton?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch! We don't need it here!
|
||
if (res.status === 200) { | ||
setSignedIn(true); | ||
setUserInfo(await res.json()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
better to pull out await res.json()
in it's own line of code
Working on #5