My last Flatiron project was a calorie counting application called Counting Cookies. If you’re interested in the idea behind that, you can read more about that here. I only created a minimal viable product that met the requirements I needed to pass the final project. While the application allowed new users to sign up to begin counting their calories, there was no way to sign in or sign out to log a new daily record .
Obviously this wouldn't work for an actual calorie counting application. You wouldn't want somebody hijacking your calendar and adding cookies to your daily log. So I decided to implement a sign-in feature, using my prior knowledge to see if it was possible. I've made login features in previous applications with vanilla JavaScript, but not with React Redux. I'm sure there is a more efficient way to handle a login with React, but I wanted to see if I could do it by myself.
My first task was to add a password and username column to the user table in my back end. I then installed the BCrypt gem to shield the passwords from any potential hackers. Later on I realized the most efficient way to communicate with the backend to login users was to create a Sessions resource, easily generated with Rails. This will allow me to continue creating new users in the user's controller, while creating new sessions for those users when they login within the Sessions controller.
For my next task, I began with making a simple login page with a username and password input. As my React application was designed to separate my actions, focused on making fetch requests to the API, the user data would be passed to the backend to be authenticated and initialize a session with the current user ID. The parsed data then passed to the reducer that handles updating the state
export const loginUser = (user) => {
return (dispatch) => {
const configObj = {
method: "POST",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(user)
}
return fetch(`http://localhost:3000/sessions/`, configObj)
.then(resp => resp.json())
.then(user => dispatch({
type: 'LOGIN_USER',
payload: user
}))
}
}
export default function loginReducer(state = {user: [], loggedIn: false, id: 0}, action) {
switch(action.type) {
case 'LOGIN_USER':
return {user: action.payload.data,
loggedIn: true
}
}
Originally my users container was placed in the root application page, as the users index was the root directory path for the application. Now that a user must sign in before creating new records, the sessions container handling logging in and logging out replaced the users container in the application page. But then where would the users container be placed and triggered after a user successfully signs in?
My solution was to place the user container in the sessions container, rendered only if userLogin
variable was true. Basically, when a user's information is sent back to the front end and stored into state, that would then trigger a userLogin
to be true in the sessionsReducer
. A user component would then be rendered in the login container, switching from the login component. Although I'm sure there is a better way to separate the two, this was my best solution for where to place the user container and it did the trick.
class LoginContainer extends Component {
render() {
if (this.props.loggedIn === true) {
return (
<div>
<Jumbotron>
<h1>Counting Cookies</h1>
<NavBar loggedIn={this.props.loggedIn}/>
</Jumbotron>
<UsersContainer user={this.props.user}/>
</div>
)
} else {
return (
<div>
<Jumbotron>
<h1>Counting Cookies</h1>
<NavBar loggedIn={this.props.loggedIn}/>
</Jumbotron>
<Switch>
<Route direct path ='/users/new' render={(routerProps) => <UserInput {...routerProps} addUser={this.props.addUser} />} />
<Route direct path='/signin' render={(routerProps) => <SignIn {...routerProps} loginUser={this.props.loginUser} />}/>
<Route direct path='/signout' render={(routerProps) => <SignOut {...routerProps} user={this.props.user} signoutUser={this.props.signoutUser} />}/>
<Route direct path='/'><Redirect to="/signin" /></Route>
</Switch>
</div>
)}
}
}
Counting Cookies was built with a nav bar with access to an index of users and sign up new users. Obviously having access to an index of users was not necessary anymore. More importantly was switching navbar links depending on whether a user was logged in or not. I separated the navbar into a new component that would render either a login and sign up links or sign out link depending on the user login status passed through props.
class NavBar extends Component {
render() {
if (this.props.loggedIn == true) {
return (
<div>
<Nav.Item>
<Nav.Link href='/logout'>Sign-Out</Nav.Link>
</Nav.Item>
</div>
)
}
return (
<div>
<Nav>
<Nav.Item>
<Nav.Link href='/login'>Sign-In</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link href='/users/new'>New User</Nav.Link>
</Nav.Item>
</Nav>
</div>
)
}
}
While building this feature was a lot easier said than done oh, it helped reinforce skills that I mastered previously. my next goal is to research and learn how to use react hooks to handle a user logging in. Stay tuned to next week to find out if I succeeded.
Top comments (0)